mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-22 16:07:30 +00:00
Merge branch 'dev'
This commit is contained in:
commit
4001714705
1
.gitignore
vendored
1
.gitignore
vendored
@ -26,3 +26,4 @@ jni/libspeex/.deps/
|
|||||||
pkcs11.password
|
pkcs11.password
|
||||||
fabric.properties
|
fabric.properties
|
||||||
play
|
play
|
||||||
|
google-services.json
|
||||||
|
@ -16,12 +16,6 @@
|
|||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.bluetooth"
|
android:name="android.hardware.bluetooth"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
<!--
|
|
||||||
Loki - Enable again once we have location sharing
|
|
||||||
<uses-feature android:name="android.hardware.location" android:required="false"/>
|
|
||||||
<uses-feature android:name="android.hardware.location.network" android:required="false"/>
|
|
||||||
<uses-feature android:name="android.hardware.location.gps" android:required="false"/>
|
|
||||||
-->
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.microphone"
|
android:name="android.hardware.microphone"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
@ -56,8 +50,6 @@
|
|||||||
<!-- For conversation 'shortcuts' on the desktop -->
|
<!-- For conversation 'shortcuts' on the desktop -->
|
||||||
<uses-permission android:name="android.permission.INSTALL_SHORTCUT" />
|
<uses-permission android:name="android.permission.INSTALL_SHORTCUT" />
|
||||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||||
<!-- Set image as wallpaper -->
|
|
||||||
<uses-permission android:name="android.permission.SET_WALLPAPER" />
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
||||||
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
||||||
@ -96,62 +88,62 @@
|
|||||||
|
|
||||||
<!-- Session -->
|
<!-- Session -->
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.LandingActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.LandingActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.RegisterActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.RegisterActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.RestoreActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.RestoreActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.LinkDeviceActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.LinkDeviceActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.DisplayNameActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.DisplayNameActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.PNModeActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.PNModeActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.HomeActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:theme="@style/Session.DarkTheme.NoActionBar" />
|
android:theme="@style/Session.DarkTheme.NoActionBar" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.SettingsActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.SettingsActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:theme="@style/Session.DarkTheme.NoActionBar" />
|
android:theme="@style/Session.DarkTheme.NoActionBar" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.QRCodeActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.QRCodeActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.CreatePrivateChatActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.CreatePrivateChatActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.CreateClosedGroupActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.CreateClosedGroupActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.JoinPublicChatActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.JoinPublicChatActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.SeedActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.SeedActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.PrivacySettingsActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.PrivacySettingsActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.NotificationSettingsActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.NotificationSettingsActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.ChatSettingsActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.ChatSettingsActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.LinkedDevicesActivity"
|
android:name="org.thoughtcrime.securesms.loki.activities.LinkedDevicesActivity"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
<!-- Session -->
|
<!-- Session -->
|
||||||
<activity
|
<activity
|
||||||
@ -166,7 +158,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.InviteActivity"
|
android:name="org.thoughtcrime.securesms.InviteActivity"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||||
android:parentActivityName="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity"
|
android:parentActivityName="org.thoughtcrime.securesms.loki.activities.HomeActivity"
|
||||||
android:theme="@style/TextSecure.HighlightTheme"
|
android:theme="@style/TextSecure.HighlightTheme"
|
||||||
android:windowSoftInputMode="stateHidden">
|
android:windowSoftInputMode="stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
@ -225,7 +217,7 @@
|
|||||||
<activity-alias
|
<activity-alias
|
||||||
android:name=".RoutingActivity"
|
android:name=".RoutingActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:targetActivity="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity">
|
android:targetActivity="org.thoughtcrime.securesms.loki.activities.HomeActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
@ -264,7 +256,7 @@
|
|||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||||
android:label="@string/AndroidManifest_archived_conversations"
|
android:label="@string/AndroidManifest_archived_conversations"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:parentActivityName="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity">
|
android:parentActivityName="org.thoughtcrime.securesms.loki.activities.HomeActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="PsiClass:HomeActivity" />
|
android:value="PsiClass:HomeActivity" />
|
||||||
@ -275,7 +267,7 @@
|
|||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:theme="@style/Session.DarkTheme.NoActionBar"
|
android:theme="@style/Session.DarkTheme.NoActionBar"
|
||||||
android:parentActivityName="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity"
|
android:parentActivityName="org.thoughtcrime.securesms.loki.activities.HomeActivity"
|
||||||
android:windowSoftInputMode="stateUnchanged">
|
android:windowSoftInputMode="stateUnchanged">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
@ -514,7 +506,7 @@
|
|||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@style/TextSecure.LightNoActionBar" />
|
android:theme="@style/TextSecure.LightNoActionBar" />
|
||||||
<service
|
<service
|
||||||
android:name="org.thoughtcrime.securesms.service.PushNotificationService"
|
android:name="org.thoughtcrime.securesms.loki.api.PushNotificationService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@ -673,12 +665,12 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<!-- Session -->
|
<!-- Session -->
|
||||||
<receiver android:name="org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPollWorker">
|
<receiver android:name="org.thoughtcrime.securesms.loki.api.BackgroundPollWorker">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver android:name="org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundOpenGroupPollWorker">
|
<receiver android:name="org.thoughtcrime.securesms.loki.api.BackgroundOpenGroupPollWorker">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
@ -190,8 +190,8 @@ dependencies {
|
|||||||
implementation "com.github.ybq:Android-SpinKit:1.4.0"
|
implementation "com.github.ybq:Android-SpinKit:1.4.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
def canonicalVersionCode = 49
|
def canonicalVersionCode = 50
|
||||||
def canonicalVersionName = "1.1.0"
|
def canonicalVersionName = "1.2.0"
|
||||||
|
|
||||||
def postFixSize = 10
|
def postFixSize = 10
|
||||||
def abiPostFix = ['armeabi-v7a' : 1,
|
def abiPostFix = ['armeabi-v7a' : 1,
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
android:textColor="@color/text"
|
android:textColor="@color/text"
|
||||||
android:text="Your Session begins here..." />
|
android:text="Your Session begins here..." />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.FakeChatView
|
<org.thoughtcrime.securesms.loki.views.FakeChatView
|
||||||
android:id="@+id/fakeChatView"
|
android:id="@+id/fakeChatView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/fake_chat_view_height"
|
android:layout_height="@dimen/fake_chat_view_height"
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.SeedReminderView
|
<org.thoughtcrime.securesms.loki.views.SeedReminderView
|
||||||
android:id="@+id/seedReminderView"
|
android:id="@+id/seedReminderView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:text="Users can share their Session ID by going into their account settings and tapping "Share Session ID", or by sharing their QR code." />
|
android:text="Users can share their Session ID by going into their account settings and tapping "Share Session ID", or by sharing their QR code." />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.LabeledSeparatorView
|
<org.thoughtcrime.securesms.loki.views.LabeledSeparatorView
|
||||||
android:id="@+id/separatorView"
|
android:id="@+id/separatorView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="32dp"
|
android:layout_height="32dp"
|
||||||
|
75
res/layout-sw400dp/view_seed_reminder.xml
Normal file
75
res/layout-sw400dp/view_seed_reminder.xml
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/cell_background"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/accent_line_thickness"
|
||||||
|
android:paddingLeft="-2dp"
|
||||||
|
android:paddingRight="-2dp"
|
||||||
|
android:progressTint="@color/accent"
|
||||||
|
android:progressBackgroundTint="@color/progress_bar_background"
|
||||||
|
android:progress="80" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:padding="@dimen/medium_spacing"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/titleTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text"
|
||||||
|
android:textSize="@dimen/small_font_size"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:text="You're almost finished! 80%" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/subtitleTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:textColor="@color/text"
|
||||||
|
android:textSize="@dimen/very_small_font_size"
|
||||||
|
android:alpha="0.6"
|
||||||
|
android:text="Secure your account by saving your recovery phrase" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginLeft="4dp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style="@style/MediumProminentOutlineButton"
|
||||||
|
android:id="@+id/button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:textStyle="normal"
|
||||||
|
android:text="Continue" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1px"
|
||||||
|
android:background="@color/separator" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -25,7 +25,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginRight="@dimen/very_large_spacing"
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
android:textSize="@dimen/small_font_size"
|
android:textSize="@dimen/small_font_size"
|
||||||
android:textColor="@color/text"
|
android:textColor="@color/text"
|
||||||
@ -37,7 +37,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginRight="@dimen/very_large_spacing"
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
android:hint="Enter a display name" />
|
android:hint="Enter a display name" />
|
||||||
|
|
||||||
|
@ -21,11 +21,11 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
|
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
|
||||||
android:id="@+id/profileButton"
|
android:id="@+id/profileButton"
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
android:layout_width="@dimen/small_profile_picture_size"
|
||||||
android:layout_height="@dimen/small_profile_picture_size"
|
android:layout_height="@dimen/small_profile_picture_size"
|
||||||
android:layout_marginLeft="10dp"
|
android:layout_marginLeft="9dp"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
android:layout_centerVertical="true" />
|
android:layout_centerVertical="true" />
|
||||||
|
|
||||||
@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
</android.support.v7.widget.Toolbar>
|
</android.support.v7.widget.Toolbar>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.SeedReminderView
|
<org.thoughtcrime.securesms.loki.views.SeedReminderView
|
||||||
android:id="@+id/seedReminderView"
|
android:id="@+id/seedReminderView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
@ -66,13 +66,39 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@drawable/home_activity_gradient" />
|
android:background="@drawable/home_activity_gradient" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.NewConversationButtonSetView
|
<org.thoughtcrime.securesms.loki.views.NewConversationButtonSetView
|
||||||
android:id="@+id/newConversationButtonSet"
|
android:id="@+id/newConversationButtonSet"
|
||||||
android:layout_width="252dp"
|
android:layout_width="252dp"
|
||||||
android:layout_height="212dp"
|
android:layout_height="212dp"
|
||||||
android:layout_centerHorizontal="true"
|
android:layout_centerHorizontal="true"
|
||||||
android:layout_alignParentBottom="true" />
|
android:layout_alignParentBottom="true" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/emptyStateContainer"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="32dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_centerInParent="true">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="@dimen/medium_font_size"
|
||||||
|
android:textColor="@color/text"
|
||||||
|
android:text="You don't have any contacts yet" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style="@style/MediumProminentOutlineButton"
|
||||||
|
android:id="@+id/createNewPrivateChatButton"
|
||||||
|
android:layout_width="196dp"
|
||||||
|
android:layout_height="@dimen/medium_button_height"
|
||||||
|
android:layout_marginTop="@dimen/medium_spacing"
|
||||||
|
android:text="Start a Session" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -21,7 +21,7 @@
|
|||||||
android:textColor="@color/text"
|
android:textColor="@color/text"
|
||||||
android:text="Your Session begins here..." />
|
android:text="Your Session begins here..." />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.FakeChatView
|
<org.thoughtcrime.securesms.loki.views.FakeChatView
|
||||||
android:id="@+id/fakeChatView"
|
android:id="@+id/fakeChatView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/fake_chat_view_height"
|
android:layout_height="@dimen/fake_chat_view_height"
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
android:layout_width="196dp"
|
android:layout_width="196dp"
|
||||||
android:layout_height="@dimen/medium_button_height"
|
android:layout_height="@dimen/medium_button_height"
|
||||||
android:layout_marginTop="@dimen/medium_spacing"
|
android:layout_marginTop="@dimen/medium_spacing"
|
||||||
android:text="Link a Device" />
|
android:text="Link a Device (Beta)" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginRight="@dimen/very_large_spacing"
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
android:textSize="@dimen/small_font_size"
|
android:textSize="@dimen/small_font_size"
|
||||||
android:textColor="@color/text"
|
android:textColor="@color/text"
|
||||||
@ -38,7 +38,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="18dp"
|
android:textSize="18dp"
|
||||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginRight="@dimen/very_large_spacing"
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginRight="@dimen/very_large_spacing"
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
android:textSize="@dimen/small_font_size"
|
android:textSize="@dimen/small_font_size"
|
||||||
android:textColor="@color/text"
|
android:textColor="@color/text"
|
||||||
@ -37,7 +37,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginRight="@dimen/very_large_spacing"
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
android:hint="Enter your recovery phrase" />
|
android:hint="Enter your recovery phrase" />
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.SeedReminderView
|
<org.thoughtcrime.securesms.loki.views.SeedReminderView
|
||||||
android:id="@+id/seedReminderView"
|
android:id="@+id/seedReminderView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
@ -22,7 +22,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
android:layout_marginRight="@dimen/very_large_spacing"
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
android:textSize="@dimen/large_font_size"
|
android:textSize="19sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="@color/text"
|
android:textColor="@color/text"
|
||||||
android:text="Meet your recovery phrase" />
|
android:text="Meet your recovery phrase" />
|
||||||
@ -31,9 +31,9 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginRight="@dimen/very_large_spacing"
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
android:textSize="@dimen/medium_font_size"
|
android:textSize="14sp"
|
||||||
android:textColor="@color/text"
|
android:textColor="@color/text"
|
||||||
android:text="Your recovery phrase is the master key to your Session ID — you can use it to restore your Session ID if you lose access to your device. Store your recovery phrase in a safe place, and don’t give it to anyone. To restore your Session ID, launch Session and tap Continue your Session." />
|
android:text="Your recovery phrase is the master key to your Session ID — you can use it to restore your Session ID if you lose access to your device. Store your recovery phrase in a safe place, and don’t give it to anyone. To restore your Session ID, launch Session and tap Continue your Session." />
|
||||||
|
|
||||||
@ -43,7 +43,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||||
android:layout_marginTop="@dimen/medium_spacing"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginRight="@dimen/very_large_spacing"
|
android:layout_marginRight="@dimen/very_large_spacing"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:textSize="@dimen/medium_font_size"
|
android:textSize="@dimen/medium_font_size"
|
||||||
@ -54,9 +54,9 @@
|
|||||||
android:id="@+id/revealButton"
|
android:id="@+id/revealButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="6dp"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textSize="@dimen/medium_font_size"
|
android:textSize="14sp"
|
||||||
android:textColor="@color/text"
|
android:textColor="@color/text"
|
||||||
android:alpha="0.6"
|
android:alpha="0.6"
|
||||||
android:text="Hold to reveal" />
|
android:text="Hold to reveal" />
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
|
|
||||||
</android.support.v7.widget.Toolbar>
|
</android.support.v7.widget.Toolbar>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
|
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
|
||||||
android:id="@+id/profilePictureView"
|
android:id="@+id/profilePictureView"
|
||||||
android:layout_width="@dimen/large_profile_picture_size"
|
android:layout_width="@dimen/large_profile_picture_size"
|
||||||
android:layout_height="@dimen/large_profile_picture_size"
|
android:layout_height="@dimen/large_profile_picture_size"
|
||||||
@ -107,7 +107,7 @@
|
|||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.LabeledSeparatorView
|
<org.thoughtcrime.securesms.loki.views.LabeledSeparatorView
|
||||||
android:id="@+id/separatorView"
|
android:id="@+id/separatorView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="32dp"
|
android:layout_height="32dp"
|
||||||
|
@ -19,6 +19,6 @@
|
|||||||
<fragment android:id="@+id/contact_selection_list_fragment"
|
<fragment android:id="@+id/contact_selection_list_fragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:name="org.thoughtcrime.securesms.ContactSelectionListFragment" />
|
android:name="org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -1,92 +1,53 @@
|
|||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/emptyStateContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="You don't have any contacts yet"
|
||||||
|
android:textColor="@color/text"
|
||||||
|
android:textSize="@dimen/medium_font_size" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/mainContentContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<android.support.v4.widget.SwipeRefreshLayout
|
<android.support.v4.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/swipe_refresh"
|
android:id="@+id/swipeRefreshLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/recycler_view"
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:scrollbars="vertical" />
|
android:scrollbars="vertical" />
|
||||||
|
|
||||||
<TextView android:id="@android:id/empty"
|
<TextView
|
||||||
|
android:id="@+id/loadingTextView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center|center_vertical"
|
android:gravity="center"
|
||||||
android:layout_marginTop="15dp"
|
android:textColor="@color/text"
|
||||||
android:text="@string/contact_selection_group_activity__finding_contacts"
|
android:text="@string/contact_selection_group_activity__finding_contacts"
|
||||||
android:textSize="20sp" />
|
android:textSize="@dimen/large_font_size" />
|
||||||
|
|
||||||
</android.support.v4.widget.SwipeRefreshLayout>
|
</android.support.v4.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.RecyclerViewFastScroller
|
|
||||||
android:id="@+id/fast_scroller"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_gravity="end"/>
|
|
||||||
|
|
||||||
<LinearLayout android:id="@+id/show_contacts_container"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<com.pnikosis.materialishprogress.ProgressWheel
|
|
||||||
android:id="@+id/progress"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:visibility="invisible"
|
|
||||||
app:matProg_circleRadius="145dp"
|
|
||||||
app:matProg_barWidth="6dp"
|
|
||||||
app:matProg_rimColor="@color/signal_primary"
|
|
||||||
app:matProg_barColor="@color/signal_primary_dark"
|
|
||||||
app:matProg_progressIndeterminate="true"
|
|
||||||
tools:visibility="visible"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ImageView android:layout_gravity="center"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@drawable/no_contacts"/>
|
|
||||||
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<TextView android:id="@+id/show_contacts_description"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="20dp"
|
|
||||||
android:layout_marginStart="50dp"
|
|
||||||
android:layout_marginEnd="50dp"
|
|
||||||
android:textSize="15sp"
|
|
||||||
android:lineSpacingMultiplier="1.3"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="@string/contact_selection_list_fragment__signal_needs_access_to_your_contacts_in_order_to_display_them"/>
|
|
||||||
|
|
||||||
<Button android:id="@+id/show_contacts_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="20dp"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:background="@color/signal_primary"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:text="@string/contact_selection_list_fragment__show_contacts"/>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.contacts.ContactSelectionListItem
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:focusable="true"
|
|
||||||
android:background="@drawable/conversation_item_background"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:paddingEnd="8dp">
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
|
|
||||||
android:id="@+id/profilePictureView"
|
|
||||||
android:layout_width="@dimen/medium_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/medium_profile_picture_size" />
|
|
||||||
|
|
||||||
<LinearLayout android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:paddingEnd="16dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
|
||||||
android:id="@+id/name"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="marquee"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:textColor="@color/text"
|
|
||||||
android:textStyle="bold"
|
|
||||||
tools:text="Frieeeeeeedrich Nieeeeeeeeeetzsche" />
|
|
||||||
|
|
||||||
<LinearLayout android:id="@+id/number_container"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<TextView android:id="@+id/number"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textDirection="ltr"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="marquee"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:fontFamily="sans-serif-light"
|
|
||||||
tools:text="+1 (555) 555-5555" />
|
|
||||||
|
|
||||||
<TextView android:id="@+id/label"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="10dip"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:fontFamily="sans-serif-light"
|
|
||||||
tools:text="Mobile" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<CheckBox android:id="@+id/check_box"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:focusable="false"
|
|
||||||
android:clickable="false" />
|
|
||||||
|
|
||||||
</org.thoughtcrime.securesms.contacts.ContactSelectionListItem>
|
|
@ -104,7 +104,7 @@
|
|||||||
android:indeterminate="false"
|
android:indeterminate="false"
|
||||||
android:progress="0" />
|
android:progress="0" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.SessionRestoreBannerView
|
<org.thoughtcrime.securesms.loki.views.SessionRestoreBannerView
|
||||||
android:id="@+id/sessionRestoreBannerView"
|
android:id="@+id/sessionRestoreBannerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
android:layout_height="42dp"
|
android:layout_height="42dp"
|
||||||
android:layout_alignParentStart="true">
|
android:layout_alignParentStart="true">
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
|
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
|
||||||
android:id="@+id/profilePictureView"
|
android:id="@+id/profilePictureView"
|
||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
android:layout_width="@dimen/small_profile_picture_size"
|
||||||
@ -208,7 +208,7 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.FriendRequestView
|
<org.thoughtcrime.securesms.loki.views.FriendRequestView
|
||||||
android:id="@+id/friend_request_view"
|
android:id="@+id/friend_request_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
android:id="@+id/container"
|
android:id="@+id/container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="@dimen/large_spacing"
|
android:layout_marginEnd="12dp"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:clipChildren="false">
|
android:clipChildren="false">
|
||||||
|
|
||||||
@ -161,7 +161,7 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.FriendRequestView
|
<org.thoughtcrime.securesms.loki.views.FriendRequestView
|
||||||
android:id="@+id/friend_request_view"
|
android:id="@+id/friend_request_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingStart="@dimen/large_spacing"
|
android:paddingStart="12dp"
|
||||||
android:paddingEnd="8dp"
|
android:paddingEnd="8dp"
|
||||||
android:paddingBottom="@dimen/small_spacing"
|
android:paddingBottom="@dimen/small_spacing"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:background="@drawable/default_dialog_background_inset"
|
android:background="@drawable/default_dialog_background_inset"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
@ -12,6 +13,7 @@
|
|||||||
android:paddingBottom="@dimen/medium_spacing">
|
android:paddingBottom="@dimen/medium_spacing">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
android:id="@+id/qrCodeImageViewContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/small_spacing"
|
android:layout_marginTop="@dimen/small_spacing"
|
||||||
@ -24,6 +26,15 @@
|
|||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<com.github.ybq.android.spinkit.SpinKitView
|
||||||
|
style="@style/SpinKitView.DoubleBounce"
|
||||||
|
android:id="@+id/spinner"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:SpinKit_Color="@color/text" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/titleTextView"
|
android:id="@+id/titleTextView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -56,6 +67,7 @@
|
|||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/buttonContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/large_spacing"
|
android:layout_marginTop="@dimen/large_spacing"
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_centerInParent="true"
|
|
||||||
app:SpinKit_Color="@color/text" />
|
app:SpinKit_Color="@color/text" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:text="Users can share their Session ID by going into their account settings and tapping "Share Session ID", or by sharing their QR code." />
|
android:text="Users can share their Session ID by going into their account settings and tapping "Share Session ID", or by sharing their QR code." />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.LabeledSeparatorView
|
<org.thoughtcrime.securesms.loki.views.LabeledSeparatorView
|
||||||
android:id="@+id/separatorView"
|
android:id="@+id/separatorView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="32dp"
|
android:layout_height="32dp"
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/large_spacing"
|
android:layout_marginLeft="@dimen/large_spacing"
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginRight="@dimen/large_spacing"
|
android:layout_marginRight="@dimen/large_spacing"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:textColor="@color/text"
|
android:textColor="@color/text"
|
||||||
@ -38,7 +38,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/large_spacing"
|
android:layout_marginLeft="@dimen/large_spacing"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginRight="@dimen/large_spacing"
|
android:layout_marginRight="@dimen/large_spacing"
|
||||||
android:hint="Enter your session ID" />
|
android:hint="Enter your session ID" />
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:name="org.thoughtcrime.securesms.ContactSelectionListFragment"
|
android:name="org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment"
|
||||||
tools:layout="@layout/contact_selection_list_fragment"/>
|
tools:layout="@layout/contact_selection_list_fragment"/>
|
||||||
|
|
||||||
<LinearLayout android:layout_width="match_parent"
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
android:layout_below="@id/toolbar"
|
android:layout_below="@id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:name="org.thoughtcrime.securesms.ContactSelectionListFragment" />
|
android:name="org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.SearchToolbar
|
<org.thoughtcrime.securesms.components.SearchToolbar
|
||||||
android:id="@+id/search_toolbar"
|
android:id="@+id/search_toolbar"
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/accent" />
|
android:background="@color/accent" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
|
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
|
||||||
android:id="@+id/profilePictureView"
|
android:id="@+id/profilePictureView"
|
||||||
android:layout_width="@dimen/medium_profile_picture_size"
|
android:layout_width="@dimen/medium_profile_picture_size"
|
||||||
android:layout_height="@dimen/medium_profile_picture_size"
|
android:layout_height="@dimen/medium_profile_picture_size"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.MentionCandidateView
|
<org.thoughtcrime.securesms.loki.views.MentionCandidateView
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="44dp"
|
android:layout_height="44dp"
|
||||||
@ -13,7 +13,7 @@
|
|||||||
android:layout_width="26dp"
|
android:layout_width="26dp"
|
||||||
android:layout_height="32dp">
|
android:layout_height="32dp">
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
|
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
|
||||||
android:id="@+id/profilePictureView"
|
android:id="@+id/profilePictureView"
|
||||||
android:layout_width="@dimen/very_small_profile_picture_size"
|
android:layout_width="@dimen/very_small_profile_picture_size"
|
||||||
android:layout_height="@dimen/very_small_profile_picture_size"
|
android:layout_height="@dimen/very_small_profile_picture_size"
|
||||||
@ -39,4 +39,4 @@
|
|||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:ellipsize="end" />
|
android:ellipsize="end" />
|
||||||
|
|
||||||
</org.thoughtcrime.securesms.loki.redesign.views.MentionCandidateView>
|
</org.thoughtcrime.securesms.loki.views.MentionCandidateView>
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.MentionCandidateSelectionView
|
<org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/userSelectionView"
|
android:id="@+id/userSelectionView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@color/cell_background"
|
android:background="@color/cell_background"
|
||||||
@ -39,11 +40,12 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/subtitleTextView"
|
android:id="@+id/subtitleTextView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="224dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:textColor="@color/text"
|
android:textColor="@color/text"
|
||||||
android:textSize="@dimen/very_small_font_size"
|
android:textSize="@dimen/very_small_font_size"
|
||||||
|
android:lines="2"
|
||||||
android:alpha="0.6"
|
android:alpha="0.6"
|
||||||
android:text="Secure your account by saving your recovery phrase" />
|
android:text="Secure your account by saving your recovery phrase" />
|
||||||
|
|
||||||
@ -52,14 +54,15 @@
|
|||||||
<View
|
<View
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1" />
|
android:layout_weight="1"
|
||||||
|
android:layout_marginLeft="4dp" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
style="@style/MediumProminentOutlineButton"
|
style="@style/MediumProminentOutlineButton"
|
||||||
android:id="@+id/button"
|
android:id="@+id/button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="27dp"
|
android:layout_height="28dp"
|
||||||
android:layout_marginLeft="@dimen/small_spacing"
|
android:layout_marginLeft="4dp"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
android:text="Continue" />
|
android:text="Continue" />
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:padding="@dimen/medium_spacing">
|
android:padding="@dimen/medium_spacing">
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
|
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
|
||||||
android:id="@+id/profilePictureView"
|
android:id="@+id/profilePictureView"
|
||||||
android:layout_width="@dimen/medium_profile_picture_size"
|
android:layout_width="@dimen/medium_profile_picture_size"
|
||||||
android:layout_height="@dimen/medium_profile_picture_size" />
|
android:layout_height="@dimen/medium_profile_picture_size" />
|
||||||
|
@ -1663,13 +1663,14 @@
|
|||||||
<string name="session_restore_banner_dismiss_button_title">Dismiss</string>
|
<string name="session_restore_banner_dismiss_button_title">Dismiss</string>
|
||||||
<string name="session_restore_banner_restore_button_title">Restore</string>
|
<string name="session_restore_banner_restore_button_title">Restore</string>
|
||||||
|
|
||||||
<!-- Loki -->
|
|
||||||
|
|
||||||
<!-- Session -->
|
<!-- Session -->
|
||||||
<string name="activity_register_public_key_copied_message">Copied to clipboard</string>
|
<string name="activity_register_public_key_copied_message">Copied to clipboard</string>
|
||||||
<string name="activity_home_leave_group_dialog_message">Are you sure you want to leave this group?</string>
|
<string name="activity_home_leave_group_dialog_message">Are you sure you want to leave this group?</string>
|
||||||
<string name="activity_home_delete_conversation_dialog_message">Are you sure you want to delete this conversation?</string>
|
<string name="activity_home_delete_conversation_dialog_message">Are you sure you want to delete this conversation?</string>
|
||||||
<string name="activity_home_conversation_deleted_message">Conversation deleted</string>
|
<string name="activity_home_conversation_deleted_message">Conversation deleted</string>
|
||||||
|
<string name="fragment_contact_selection_contacts_title">Contacts</string>
|
||||||
|
<string name="fragment_contact_selection_closed_groups_title">Closed Groups</string>
|
||||||
|
<string name="fragment_contact_selection_open_groups_title">Open Groups</string>
|
||||||
<string name="activity_pn_mode_title">Push Notifications</string>
|
<string name="activity_pn_mode_title">Push Notifications</string>
|
||||||
<string name="activity_pn_mode_explanation">There are two ways Session can handle push notifications. Make sure to read the descriptions carefully before you choose.</string>
|
<string name="activity_pn_mode_explanation">There are two ways Session can handle push notifications. Make sure to read the descriptions carefully before you choose.</string>
|
||||||
<string name="activity_pn_mode_fcm_option_title">Firebase Cloud Messaging</string>
|
<string name="activity_pn_mode_fcm_option_title">Firebase Cloud Messaging</string>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<network-security-config>
|
<network-security-config>
|
||||||
<domain-config cleartextTrafficPermitted="true">
|
<domain-config cleartextTrafficPermitted="true">
|
||||||
<domain includeSubdomains="true">149.56.148.124</domain>
|
<domain includeSubdomains="true">144.76.164.202</domain>
|
||||||
<domain includeSubdomains="true">storage.seed1.loki.network</domain>
|
<domain includeSubdomains="true">storage.seed1.loki.network</domain>
|
||||||
<domain includeSubdomains="true">storage.seed2.loki.network</domain>
|
<domain includeSubdomains="true">storage.seed2.loki.network</domain>
|
||||||
<domain includeSubdomains="true">public.loki.foundation</domain>
|
<domain includeSubdomains="true">public.loki.foundation</domain>
|
||||||
|
@ -19,10 +19,8 @@ package org.thoughtcrime.securesms;
|
|||||||
import android.arch.lifecycle.DefaultLifecycleObserver;
|
import android.arch.lifecycle.DefaultLifecycleObserver;
|
||||||
import android.arch.lifecycle.LifecycleOwner;
|
import android.arch.lifecycle.LifecycleOwner;
|
||||||
import android.arch.lifecycle.ProcessLifecycleOwner;
|
import android.arch.lifecycle.ProcessLifecycleOwner;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.ContentObserver;
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@ -41,12 +39,10 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseContentProviders;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule;
|
import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.DependencyInjector;
|
import org.thoughtcrime.securesms.jobmanager.DependencyInjector;
|
||||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
|
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
|
||||||
@ -62,16 +58,18 @@ import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger;
|
|||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.logging.PersistentLogger;
|
import org.thoughtcrime.securesms.logging.PersistentLogger;
|
||||||
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
|
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
|
||||||
import org.thoughtcrime.securesms.loki.LokiPublicChatManager;
|
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||||
import org.thoughtcrime.securesms.loki.LokiPushNotificationManager;
|
import org.thoughtcrime.securesms.loki.api.BackgroundOpenGroupPollWorker;
|
||||||
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
|
import org.thoughtcrime.securesms.loki.api.BackgroundPollWorker;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.api.LokiPublicChatManager;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundOpenGroupPollWorker;
|
import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPollWorker;
|
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiRSSFeedPoller;
|
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase;
|
import org.thoughtcrime.securesms.loki.protocol.EphemeralMessage;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.utilities.Broadcaster;
|
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation;
|
||||||
|
import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob;
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.Broadcaster;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||||
@ -86,6 +84,7 @@ import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
|
|||||||
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
||||||
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
|
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
|
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
|
||||||
import org.webrtc.PeerConnectionFactory;
|
import org.webrtc.PeerConnectionFactory;
|
||||||
import org.webrtc.PeerConnectionFactory.InitializationOptions;
|
import org.webrtc.PeerConnectionFactory.InitializationOptions;
|
||||||
@ -96,25 +95,29 @@ import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
|||||||
import org.whispersystems.signalservice.api.util.StreamDetails;
|
import org.whispersystems.signalservice.api.util.StreamDetails;
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
||||||
import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol;
|
|
||||||
import org.whispersystems.signalservice.loki.api.LokiP2PAPI;
|
|
||||||
import org.whispersystems.signalservice.loki.api.LokiP2PAPIDelegate;
|
|
||||||
import org.whispersystems.signalservice.loki.api.LokiPoller;
|
import org.whispersystems.signalservice.loki.api.LokiPoller;
|
||||||
import org.whispersystems.signalservice.loki.api.LokiPushNotificationAcknowledgement;
|
import org.whispersystems.signalservice.loki.api.LokiPushNotificationAcknowledgement;
|
||||||
import org.whispersystems.signalservice.loki.api.LokiSwarmAPI;
|
import org.whispersystems.signalservice.loki.api.LokiSwarmAPI;
|
||||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI;
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI;
|
import org.whispersystems.signalservice.loki.api.p2p.LokiP2PAPI;
|
||||||
import org.whispersystems.signalservice.loki.api.rssfeeds.LokiRSSFeed;
|
import org.whispersystems.signalservice.loki.api.p2p.LokiP2PAPIDelegate;
|
||||||
|
import org.whispersystems.signalservice.loki.database.LokiAPIDatabaseProtocol;
|
||||||
|
import org.whispersystems.signalservice.loki.protocol.friendrequests.FriendRequestProtocol;
|
||||||
|
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager;
|
||||||
|
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol;
|
||||||
|
import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink;
|
||||||
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
|
||||||
|
import org.whispersystems.signalservice.loki.protocol.sessionmanagement.SessionManagementProtocol;
|
||||||
|
import org.whispersystems.signalservice.loki.protocol.sessionmanagement.SessionManagementProtocolDelegate;
|
||||||
|
import org.whispersystems.signalservice.loki.protocol.syncmessages.SyncMessagesProtocol;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import dagger.ObjectGraph;
|
import dagger.ObjectGraph;
|
||||||
@ -132,7 +135,7 @@ import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant;
|
|||||||
*
|
*
|
||||||
* @author Moxie Marlinspike
|
* @author Moxie Marlinspike
|
||||||
*/
|
*/
|
||||||
public class ApplicationContext extends MultiDexApplication implements DependencyInjector, DefaultLifecycleObserver, LokiP2PAPIDelegate {
|
public class ApplicationContext extends MultiDexApplication implements DependencyInjector, DefaultLifecycleObserver, LokiP2PAPIDelegate, SessionManagementProtocolDelegate {
|
||||||
|
|
||||||
private static final String TAG = ApplicationContext.class.getSimpleName();
|
private static final String TAG = ApplicationContext.class.getSimpleName();
|
||||||
private final static int OK_HTTP_CACHE_SIZE = 10 * 1024 * 1024; // 10 MB
|
private final static int OK_HTTP_CACHE_SIZE = 10 * 1024 * 1024; // 10 MB
|
||||||
@ -146,10 +149,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
private PersistentLogger persistentLogger;
|
private PersistentLogger persistentLogger;
|
||||||
|
|
||||||
// Loki
|
// Loki
|
||||||
private LokiPoller lokiPoller = null;
|
public LokiPoller lokiPoller = null;
|
||||||
private LokiRSSFeedPoller lokiNewsFeedPoller = null;
|
public LokiPublicChatManager lokiPublicChatManager = null;
|
||||||
private LokiRSSFeedPoller lokiMessengerUpdatesFeedPoller = null;
|
|
||||||
private LokiPublicChatManager lokiPublicChatManager = null;
|
|
||||||
private LokiPublicChatAPI lokiPublicChatAPI = null;
|
private LokiPublicChatAPI lokiPublicChatAPI = null;
|
||||||
public Broadcaster broadcaster = null;
|
public Broadcaster broadcaster = null;
|
||||||
public SignalCommunicationModule communicationModule;
|
public SignalCommunicationModule communicationModule;
|
||||||
@ -164,13 +165,42 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
Log.i(TAG, "onCreate()");
|
Log.i(TAG, "onCreate()");
|
||||||
broadcaster = new Broadcaster(this);
|
|
||||||
checkNeedsDatabaseReset();
|
|
||||||
startKovenant();
|
startKovenant();
|
||||||
initializeSecurityProvider();
|
initializeSecurityProvider();
|
||||||
initializeLogging();
|
initializeLogging();
|
||||||
initializeCrashHandling();
|
initializeCrashHandling();
|
||||||
initializeDependencyInjection();
|
initializeDependencyInjection();
|
||||||
|
NotificationChannels.create(this);
|
||||||
|
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
|
||||||
|
// Loki
|
||||||
|
// ========
|
||||||
|
broadcaster = new Broadcaster(this);
|
||||||
|
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
|
||||||
|
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this);
|
||||||
|
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
|
||||||
|
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||||
|
LokiSessionResetImplementation sessionResetImpl = new LokiSessionResetImplementation(this);
|
||||||
|
if (userPublicKey != null) {
|
||||||
|
FriendRequestProtocol.Companion.configureIfNeeded(apiDB, userPublicKey);
|
||||||
|
MentionsManager.Companion.configureIfNeeded(userPublicKey, threadDB, userDB);
|
||||||
|
SessionMetaProtocol.Companion.configureIfNeeded(apiDB, userPublicKey);
|
||||||
|
SyncMessagesProtocol.Companion.configureIfNeeded(apiDB, userPublicKey);
|
||||||
|
}
|
||||||
|
MultiDeviceProtocol.Companion.configureIfNeeded(apiDB);
|
||||||
|
SessionManagementProtocol.Companion.configureIfNeeded(sessionResetImpl, threadDB, this);
|
||||||
|
setUpP2PAPIIfNeeded();
|
||||||
|
LokiPushNotificationAcknowledgement.Companion.configureIfNeeded(BuildConfig.DEBUG);
|
||||||
|
if (setUpStorageAPIIfNeeded()) {
|
||||||
|
if (userPublicKey != null) {
|
||||||
|
Set<DeviceLink> deviceLinks = DatabaseFactory.getLokiAPIDatabase(this).getDeviceLinks(userPublicKey);
|
||||||
|
LokiFileServerAPI.shared.setDeviceLinks(deviceLinks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resubmitProfilePictureIfNeeded();
|
||||||
|
lokiPublicChatManager = new LokiPublicChatManager(this);
|
||||||
|
updateOpenGroupProfilePicturesIfNeeded();
|
||||||
|
registerForFCMIfNeeded(false);
|
||||||
|
// ========
|
||||||
initializeJobManager();
|
initializeJobManager();
|
||||||
initializeMessageRetrieval();
|
initializeMessageRetrieval();
|
||||||
initializeExpiringMessageManager();
|
initializeExpiringMessageManager();
|
||||||
@ -182,30 +212,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
initializePendingMessages();
|
initializePendingMessages();
|
||||||
initializeUnidentifiedDeliveryAbilityRefresh();
|
initializeUnidentifiedDeliveryAbilityRefresh();
|
||||||
initializeBlobProvider();
|
initializeBlobProvider();
|
||||||
NotificationChannels.create(this);
|
|
||||||
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
|
|
||||||
// Loki - Set up P2P API if needed
|
|
||||||
setUpP2PAPI();
|
|
||||||
// Loki - Set up push notification acknowledgement
|
|
||||||
LokiPushNotificationAcknowledgement.Companion.configureIfNeeded(BuildConfig.DEBUG);
|
|
||||||
// Loki - Update device mappings
|
|
||||||
if (setUpStorageAPIIfNeeded()) {
|
|
||||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
|
|
||||||
if (userHexEncodedPublicKey != null) {
|
|
||||||
if (TextSecurePreferences.getNeedsIsRevokedSlaveDeviceCheck(this)) {
|
|
||||||
MultiDeviceUtilities.checkIsRevokedSlaveDevice(this);
|
|
||||||
} else {
|
|
||||||
// We always update our current device links onto the server in case we failed to do so upon linking
|
|
||||||
MultiDeviceUtilities.updateDeviceLinksOnServer(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Loki - Resubmit profile picture if needed
|
|
||||||
resubmitProfilePictureIfNeeded();
|
|
||||||
// Loki - Set up public chat manager
|
|
||||||
lokiPublicChatManager = new LokiPublicChatManager(this);
|
|
||||||
updatePublicChatProfilePictureIfNeeded();
|
|
||||||
registerForFCMIfNeeded(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -214,9 +220,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
Log.i(TAG, "App is now visible.");
|
Log.i(TAG, "App is now visible.");
|
||||||
executePendingContactSync();
|
executePendingContactSync();
|
||||||
KeyCachingService.onAppForegrounded(this);
|
KeyCachingService.onAppForegrounded(this);
|
||||||
// Loki - Start polling if needed
|
// Loki
|
||||||
startPollingIfNeeded();
|
startPollingIfNeeded();
|
||||||
// Loki - Start open group polling if needed
|
|
||||||
lokiPublicChatManager.startPollersIfNeeded();
|
lokiPublicChatManager.startPollersIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,14 +231,14 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
Log.i(TAG, "App is no longer visible.");
|
Log.i(TAG, "App is no longer visible.");
|
||||||
KeyCachingService.onAppBackgrounded(this);
|
KeyCachingService.onAppBackgrounded(this);
|
||||||
MessageNotifier.setVisibleThread(-1);
|
MessageNotifier.setVisibleThread(-1);
|
||||||
// Loki - Stop polling if needed
|
// Loki
|
||||||
if (lokiPoller != null) { lokiPoller.stopIfNeeded(); }
|
if (lokiPoller != null) { lokiPoller.stopIfNeeded(); }
|
||||||
if (lokiPublicChatManager != null) { lokiPublicChatManager.stopPollers(); }
|
if (lokiPublicChatManager != null) { lokiPublicChatManager.stopPollers(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTerminate() {
|
public void onTerminate() {
|
||||||
stopKovenant();
|
stopKovenant(); // Loki
|
||||||
super.onTerminate();
|
super.onTerminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,20 +273,15 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
return persistentLogger;
|
return persistentLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LokiPublicChatManager getLokiPublicChatManager() {
|
// Loki
|
||||||
return lokiPublicChatManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable LokiPublicChatAPI getLokiPublicChatAPI() {
|
public @Nullable LokiPublicChatAPI getLokiPublicChatAPI() {
|
||||||
if (lokiPublicChatAPI == null && IdentityKeyUtil.hasIdentityKey(this)) {
|
if (lokiPublicChatAPI != null || !IdentityKeyUtil.hasIdentityKey(this)) { return lokiPublicChatAPI; }
|
||||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
|
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||||
if (userHexEncodedPublicKey != null) {
|
if (userPublicKey== null) { return lokiPublicChatAPI; }
|
||||||
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
|
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
|
||||||
LokiAPIDatabase apiDatabase = DatabaseFactory.getLokiAPIDatabase(this);
|
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
|
||||||
LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(this);
|
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
|
||||||
lokiPublicChatAPI = new LokiPublicChatAPI(userHexEncodedPublicKey, userPrivateKey, apiDatabase, userDatabase);
|
lokiPublicChatAPI = new LokiPublicChatAPI(userPublicKey, userPrivateKey, apiDB, userDB);
|
||||||
}
|
|
||||||
}
|
|
||||||
return lokiPublicChatAPI;
|
return lokiPublicChatAPI;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,8 +363,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
RotateSignedPreKeyListener.schedule(this);
|
RotateSignedPreKeyListener.schedule(this);
|
||||||
LocalBackupListener.schedule(this);
|
LocalBackupListener.schedule(this);
|
||||||
RotateSenderCertificateListener.schedule(this);
|
RotateSenderCertificateListener.schedule(this);
|
||||||
BackgroundPollWorker.schedule(this); // Session
|
BackgroundPollWorker.schedule(this); // Loki
|
||||||
BackgroundOpenGroupPollWorker.schedule(this); // Session
|
BackgroundOpenGroupPollWorker.schedule(this); // Loki
|
||||||
|
|
||||||
if (BuildConfig.PLAY_STORE_DISABLED) {
|
if (BuildConfig.PLAY_STORE_DISABLED) {
|
||||||
UpdateApkRefreshListener.schedule(this);
|
UpdateApkRefreshListener.schedule(this);
|
||||||
@ -442,18 +442,16 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
|
|
||||||
// region Loki
|
// region Loki
|
||||||
public boolean setUpStorageAPIIfNeeded() {
|
public boolean setUpStorageAPIIfNeeded() {
|
||||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
|
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||||
if (userHexEncodedPublicKey != null && IdentityKeyUtil.hasIdentityKey(this)) {
|
if (userPublicKey == null || !IdentityKeyUtil.hasIdentityKey(this)) { return false; }
|
||||||
boolean isDebugMode = BuildConfig.DEBUG;
|
boolean isDebugMode = BuildConfig.DEBUG;
|
||||||
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
|
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
|
||||||
LokiAPIDatabaseProtocol database = DatabaseFactory.getLokiAPIDatabase(this);
|
LokiAPIDatabaseProtocol apiDB = DatabaseFactory.getLokiAPIDatabase(this);
|
||||||
LokiFileServerAPI.Companion.configure(isDebugMode, userHexEncodedPublicKey, userPrivateKey, database);
|
LokiFileServerAPI.Companion.configure(isDebugMode, userPublicKey, userPrivateKey, apiDB);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpP2PAPI() {
|
public void setUpP2PAPIIfNeeded() {
|
||||||
String hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
|
String hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||||
if (hexEncodedPublicKey == null) { return; }
|
if (hexEncodedPublicKey == null) { return; }
|
||||||
LokiP2PAPI.Companion.configure(hexEncodedPublicKey, (isOnline, contactPublicKey) -> {
|
LokiP2PAPI.Companion.configure(hexEncodedPublicKey, (isOnline, contactPublicKey) -> {
|
||||||
@ -470,10 +468,10 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String token = task.getResult().getToken();
|
String token = task.getResult().getToken();
|
||||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context);
|
String userPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||||
if (userHexEncodedPublicKey == null) return;
|
if (userPublicKey == null) return;
|
||||||
if (TextSecurePreferences.isUsingFCM(this)) {
|
if (TextSecurePreferences.isUsingFCM(this)) {
|
||||||
LokiPushNotificationManager.register(token, userHexEncodedPublicKey, context, force);
|
LokiPushNotificationManager.register(token, userPublicKey, context, force);
|
||||||
} else {
|
} else {
|
||||||
LokiPushNotificationManager.unregister(token, context);
|
LokiPushNotificationManager.unregister(token, context);
|
||||||
}
|
}
|
||||||
@ -487,15 +485,15 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
|
|
||||||
private void setUpPollingIfNeeded() {
|
private void setUpPollingIfNeeded() {
|
||||||
if (lokiPoller != null) return;
|
if (lokiPoller != null) return;
|
||||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
|
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||||
if (userHexEncodedPublicKey == null) return;
|
if (userPublicKey == null) return;
|
||||||
LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(this);
|
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
|
||||||
Context context = this;
|
Context context = this;
|
||||||
LokiSwarmAPI.Companion.configureIfNeeded(lokiAPIDatabase);
|
LokiSwarmAPI.Companion.configureIfNeeded(apiDB);
|
||||||
LokiAPI.Companion.configureIfNeeded(userHexEncodedPublicKey, lokiAPIDatabase, broadcaster);
|
LokiAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster);
|
||||||
lokiPoller = new LokiPoller(userHexEncodedPublicKey, lokiAPIDatabase, protos -> {
|
lokiPoller = new LokiPoller(userPublicKey, apiDB, protos -> {
|
||||||
for (SignalServiceProtos.Envelope proto : protos) {
|
for (SignalServiceProtos.Envelope proto : protos) {
|
||||||
new PushContentReceiveJob(context).processEnvelope(new SignalServiceEnvelope(proto));
|
new PushContentReceiveJob(context).processEnvelope(new SignalServiceEnvelope(proto), false);
|
||||||
}
|
}
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
@ -506,94 +504,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
if (lokiPoller != null) { lokiPoller.startIfNeeded(); }
|
if (lokiPoller != null) { lokiPoller.startIfNeeded(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private LokiRSSFeed lokiNewsFeed() {
|
|
||||||
return new LokiRSSFeed("loki.network.feed", "https://loki.network/feed/", "Loki News", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LokiRSSFeed lokiMessengerUpdatesFeed() {
|
|
||||||
return new LokiRSSFeed("loki.network.messenger-updates.feed", "https://loki.network/category/messenger-updates/feed", "Session Updates", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createDefaultPublicChatsIfNeeded() {
|
|
||||||
List<LokiPublicChat> defaultPublicChats = LokiPublicChatAPI.Companion.getDefaultChats(BuildConfig.DEBUG);
|
|
||||||
for (LokiPublicChat publicChat : defaultPublicChats) {
|
|
||||||
long threadID = GroupManager.getPublicChatThreadId(publicChat.getId(), this);
|
|
||||||
String migrationKey = publicChat.getId() + "_migrated";
|
|
||||||
boolean isChatMigrated = TextSecurePreferences.getBooleanPreference(this, migrationKey, false);
|
|
||||||
boolean isChatSetUp = TextSecurePreferences.isChatSetUp(this, publicChat.getId());
|
|
||||||
if (!isChatSetUp || !publicChat.isDeletable()) {
|
|
||||||
lokiPublicChatManager.addChat(publicChat.getServer(), publicChat.getChannel(), publicChat.getDisplayName());
|
|
||||||
TextSecurePreferences.markChatSetUp(this, publicChat.getId());
|
|
||||||
TextSecurePreferences.setBooleanPreference(this, migrationKey, true);
|
|
||||||
} else if (threadID > -1 && !isChatMigrated) {
|
|
||||||
// Migrate the old public chats
|
|
||||||
DatabaseFactory.getLokiThreadDatabase(this).setPublicChat(publicChat, threadID);
|
|
||||||
TextSecurePreferences.setBooleanPreference(this, migrationKey, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createRSSFeedsIfNeeded() {
|
|
||||||
ArrayList<LokiRSSFeed> feeds = new ArrayList<>();
|
|
||||||
// feeds.add(lokiNewsFeed());
|
|
||||||
feeds.add(lokiMessengerUpdatesFeed());
|
|
||||||
for (LokiRSSFeed feed : feeds) {
|
|
||||||
boolean isFeedSetUp = TextSecurePreferences.isChatSetUp(this, feed.getId());
|
|
||||||
if (!isFeedSetUp || !feed.isDeletable()) {
|
|
||||||
GroupManager.createRSSFeedGroup(feed.getId(), this, null, feed.getDisplayName());
|
|
||||||
TextSecurePreferences.markChatSetUp(this, feed.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createRSSFeedPollersIfNeeded() {
|
|
||||||
// Only create the RSS feed pollers if their threads aren't deleted
|
|
||||||
LokiRSSFeed lokiNewsFeed = lokiNewsFeed();
|
|
||||||
long lokiNewsFeedThreadID = GroupManager.getRSSFeedThreadId(lokiNewsFeed.getId(), this);
|
|
||||||
if (lokiNewsFeedThreadID >= 0 && lokiNewsFeedPoller == null) {
|
|
||||||
lokiNewsFeedPoller = new LokiRSSFeedPoller(this, lokiNewsFeed);
|
|
||||||
// Set up deletion listeners if needed
|
|
||||||
setUpThreadDeletionListeners(lokiNewsFeedThreadID, () -> {
|
|
||||||
if (lokiNewsFeedPoller != null) lokiNewsFeedPoller.stop();
|
|
||||||
lokiNewsFeedPoller = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// The user can't delete the Session Updates RSS feed
|
|
||||||
if (lokiMessengerUpdatesFeedPoller == null) {
|
|
||||||
lokiMessengerUpdatesFeedPoller = new LokiRSSFeedPoller(this, lokiMessengerUpdatesFeed());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setUpThreadDeletionListeners(long threadID, Runnable onDelete) {
|
|
||||||
if (threadID < 0) { return; }
|
|
||||||
ContentObserver observer = new ContentObserver(null) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onChange(boolean selfChange) {
|
|
||||||
super.onChange(selfChange);
|
|
||||||
// Stop the poller if thread is deleted
|
|
||||||
try {
|
|
||||||
if (!DatabaseFactory.getThreadDatabase(getApplicationContext()).hasThread(threadID)) {
|
|
||||||
onDelete.run();
|
|
||||||
getContentResolver().unregisterContentObserver(this);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// TODO: Handle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.getContentResolver().registerContentObserver(DatabaseContentProviders.Conversation.getUriForThread(threadID), true, observer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startRSSFeedPollersIfNeeded() {
|
|
||||||
createRSSFeedPollersIfNeeded();
|
|
||||||
if (lokiNewsFeedPoller != null) lokiNewsFeedPoller.startIfNeeded();
|
|
||||||
if (lokiMessengerUpdatesFeedPoller != null) lokiMessengerUpdatesFeedPoller.startIfNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resubmitProfilePictureIfNeeded() {
|
private void resubmitProfilePictureIfNeeded() {
|
||||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
|
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||||
if (userHexEncodedPublicKey == null) return;
|
if (userPublicKey == null) return;
|
||||||
long now = new Date().getTime();
|
long now = new Date().getTime();
|
||||||
long lastProfilePictureUpload = TextSecurePreferences.getLastProfilePictureUpload(this);
|
long lastProfilePictureUpload = TextSecurePreferences.getLastProfilePictureUpload(this);
|
||||||
if (now - lastProfilePictureUpload <= 14 * 24 * 60 * 60 * 1000) return;
|
if (now - lastProfilePictureUpload <= 14 * 24 * 60 * 60 * 1000) return;
|
||||||
@ -601,7 +514,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
String encodedProfileKey = ProfileKeyUtil.generateEncodedProfileKey(this);
|
String encodedProfileKey = ProfileKeyUtil.generateEncodedProfileKey(this);
|
||||||
byte[] profileKey = ProfileKeyUtil.getProfileKeyFromEncodedString(encodedProfileKey);
|
byte[] profileKey = ProfileKeyUtil.getProfileKeyFromEncodedString(encodedProfileKey);
|
||||||
try {
|
try {
|
||||||
File profilePicture = AvatarHelper.getAvatarFile(this, Address.fromSerialized(userHexEncodedPublicKey));
|
File profilePicture = AvatarHelper.getAvatarFile(this, Address.fromSerialized(userPublicKey));
|
||||||
StreamDetails stream = new StreamDetails(new FileInputStream(profilePicture), "image/jpeg", profilePicture.length());
|
StreamDetails stream = new StreamDetails(new FileInputStream(profilePicture), "image/jpeg", profilePicture.length());
|
||||||
LokiFileServerAPI.shared.uploadProfilePicture(LokiFileServerAPI.shared.getServer(), profileKey, stream, () -> {
|
LokiFileServerAPI.shared.uploadProfilePicture(LokiFileServerAPI.shared.getServer(), profileKey, stream, () -> {
|
||||||
TextSecurePreferences.setLastProfilePictureUpload(this, new Date().getTime());
|
TextSecurePreferences.setLastProfilePictureUpload(this, new Date().getTime());
|
||||||
@ -615,7 +528,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePublicChatProfilePictureIfNeeded() {
|
public void updateOpenGroupProfilePicturesIfNeeded() {
|
||||||
AsyncTask.execute(() -> {
|
AsyncTask.execute(() -> {
|
||||||
LokiPublicChatAPI publicChatAPI = null;
|
LokiPublicChatAPI publicChatAPI = null;
|
||||||
try {
|
try {
|
||||||
@ -623,14 +536,14 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
if (publicChatAPI != null) {
|
if (publicChatAPI == null) { return; }
|
||||||
byte[] profileKey = ProfileKeyUtil.getProfileKey(this);
|
byte[] profileKey = ProfileKeyUtil.getProfileKey(this);
|
||||||
String url = TextSecurePreferences.getProfileAvatarUrl(this);
|
String url = TextSecurePreferences.getProfilePictureURL(this);
|
||||||
String ourMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(this);
|
String userMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(this);
|
||||||
if (ourMasterDevice != null) {
|
if (userMasterDevice != null) {
|
||||||
Recipient masterDevice = Recipient.from(this, Address.fromSerialized(ourMasterDevice), false).resolve();
|
Recipient userMasterDeviceAsRecipient = Recipient.from(this, Address.fromSerialized(userMasterDevice), false).resolve();
|
||||||
profileKey = masterDevice.getProfileKey();
|
profileKey = userMasterDeviceAsRecipient.getProfileKey();
|
||||||
url = masterDevice.getProfileAvatar();
|
url = userMasterDeviceAsRecipient.getProfileAvatar();
|
||||||
}
|
}
|
||||||
Set<String> servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers();
|
Set<String> servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers();
|
||||||
for (String server : servers) {
|
for (String server : servers) {
|
||||||
@ -638,33 +551,31 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
publicChatAPI.setProfilePicture(server, profileKey, url);
|
publicChatAPI.setProfilePicture(server, profileKey, url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkNeedsDatabaseReset() {
|
|
||||||
if (TextSecurePreferences.resetDatabase(this)) {
|
|
||||||
boolean wasUnlinked = TextSecurePreferences.databaseResetFromUnpair(this);
|
|
||||||
TextSecurePreferences.clearAll(this);
|
|
||||||
TextSecurePreferences.setDatabaseResetFromUnpair(this, wasUnlinked); // Loki - Re-set the preference so we can use it in the starting screen to determine whether device was unlinked or not
|
|
||||||
MasterSecretUtil.clear(this);
|
|
||||||
if (this.deleteDatabase("signal.db")) {
|
|
||||||
Log.d("Loki", "Deleted database");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearData() {
|
public void clearData() {
|
||||||
TextSecurePreferences.setResetDatabase(this, true);
|
boolean wasUnlinked = TextSecurePreferences.getWasUnlinked(this);
|
||||||
new Handler().postDelayed(this::restartApplication, 200);
|
TextSecurePreferences.clearAll(this);
|
||||||
|
TextSecurePreferences.setWasUnlinked(this, wasUnlinked);
|
||||||
|
MasterSecretUtil.clear(this);
|
||||||
|
if (!deleteDatabase("signal.db")) {
|
||||||
|
Log.d("Loki", "Failed to delete database.");
|
||||||
|
}
|
||||||
|
Util.runOnMain(() -> new Handler().postDelayed(ApplicationContext.this::restartApplication, 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void restartApplication() {
|
public void restartApplication() {
|
||||||
Intent intent = new Intent(this, HomeActivity.class);
|
Intent intent = new Intent(this, HomeActivity.class);
|
||||||
ComponentName componentName = intent.getComponent();
|
startActivity(Intent.makeRestartActivityTask(intent.getComponent()));
|
||||||
Intent mainIntent = Intent.makeRestartActivityTask(componentName);
|
|
||||||
this.startActivity(mainIntent);
|
|
||||||
Runtime.getRuntime().exit(0);
|
Runtime.getRuntime().exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendSessionRequest(@NotNull String publicKey) {
|
||||||
|
DatabaseFactory.getLokiAPIDatabase(this).setSessionRequestTimestamp(publicKey, new Date().getTime());
|
||||||
|
EphemeralMessage sessionRequest = EphemeralMessage.createSessionRequest(publicKey);
|
||||||
|
jobManager.add(new PushEphemeralMessageSendJob(sessionRequest));
|
||||||
|
}
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ import android.util.Log;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||||
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
||||||
import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
|
import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
|
||||||
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
|
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
|
||||||
|
@ -20,11 +20,11 @@ import android.os.Bundle;
|
|||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
|
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
|
import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment;
|
||||||
|
import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListLoader.DisplayMode;
|
||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
import network.loki.messenger.R;
|
||||||
@ -57,9 +57,7 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle icicle, boolean ready) {
|
protected void onCreate(Bundle icicle, boolean ready) {
|
||||||
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
|
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
|
||||||
int displayMode = TextSecurePreferences.isSmsEnabled(this) ? DisplayMode.FLAG_ALL
|
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_ALL);
|
||||||
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_GROUPS;
|
|
||||||
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(R.layout.contact_selection_activity);
|
setContentView(R.layout.contact_selection_activity);
|
||||||
|
@ -1,303 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms;
|
|
||||||
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.app.LoaderManager;
|
|
||||||
import android.support.v4.content.Loader;
|
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.pnikosis.materialishprogress.ProgressWheel;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller;
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter;
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader;
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
|
|
||||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
|
||||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fragment for selecting a one or more contacts from a list.
|
|
||||||
*
|
|
||||||
* @author Moxie Marlinspike
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ContactSelectionListFragment extends Fragment
|
|
||||||
implements LoaderManager.LoaderCallbacks<Cursor>
|
|
||||||
{
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final String TAG = ContactSelectionListFragment.class.getSimpleName();
|
|
||||||
|
|
||||||
public static final String DISPLAY_MODE = "display_mode";
|
|
||||||
public static final String MULTI_SELECT = "multi_select";
|
|
||||||
public static final String REFRESHABLE = "refreshable";
|
|
||||||
public static final String RECENTS = "recents";
|
|
||||||
|
|
||||||
private TextView emptyText;
|
|
||||||
private Set<String> selectedContacts;
|
|
||||||
private OnContactSelectedListener onContactSelectedListener;
|
|
||||||
private SwipeRefreshLayout swipeRefresh;
|
|
||||||
private View showContactsLayout;
|
|
||||||
private Button showContactsButton;
|
|
||||||
private TextView showContactsDescription;
|
|
||||||
private ProgressWheel showContactsProgress;
|
|
||||||
private String cursorFilter;
|
|
||||||
private RecyclerView recyclerView;
|
|
||||||
private RecyclerViewFastScroller fastScroller;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityCreated(Bundle icicle) {
|
|
||||||
super.onActivityCreated(icicle);
|
|
||||||
|
|
||||||
initializeCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
|
|
||||||
handleContactPermissionGranted();
|
|
||||||
|
|
||||||
// Permissions.with(this)
|
|
||||||
// .request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS)
|
|
||||||
// .ifNecessary()
|
|
||||||
// .onAllGranted(() -> {
|
|
||||||
// if (!TextSecurePreferences.hasSuccessfullyRetrievedDirectory(getActivity())) {
|
|
||||||
// handleContactPermissionGranted();
|
|
||||||
// } else {
|
|
||||||
// this.getLoaderManager().initLoader(0, null, this);
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .onAnyDenied(() -> {
|
|
||||||
// getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
|
||||||
//
|
|
||||||
// if (getActivity().getIntent().getBooleanExtra(RECENTS, false)) {
|
|
||||||
// getLoaderManager().initLoader(0, null, ContactSelectionListFragment.this);
|
|
||||||
// } else {
|
|
||||||
// initializeNoContactsPermission();
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
View view = inflater.inflate(R.layout.contact_selection_list_fragment, container, false);
|
|
||||||
|
|
||||||
emptyText = ViewUtil.findById(view, android.R.id.empty);
|
|
||||||
recyclerView = ViewUtil.findById(view, R.id.recycler_view);
|
|
||||||
swipeRefresh = ViewUtil.findById(view, R.id.swipe_refresh);
|
|
||||||
fastScroller = ViewUtil.findById(view, R.id.fast_scroller);
|
|
||||||
showContactsLayout = view.findViewById(R.id.show_contacts_container);
|
|
||||||
showContactsButton = view.findViewById(R.id.show_contacts_button);
|
|
||||||
showContactsDescription = view.findViewById(R.id.show_contacts_description);
|
|
||||||
showContactsProgress = view.findViewById(R.id.progress);
|
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
|
||||||
|
|
||||||
swipeRefresh.setEnabled(getActivity().getIntent().getBooleanExtra(REFRESHABLE, true));
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
||||||
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull List<String> getSelectedContacts() {
|
|
||||||
List<String> selected = new LinkedList<>();
|
|
||||||
if (selectedContacts != null) {
|
|
||||||
selected.addAll(selectedContacts);
|
|
||||||
}
|
|
||||||
|
|
||||||
return selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isMulti() {
|
|
||||||
return getActivity().getIntent().getBooleanExtra(MULTI_SELECT, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeCursor() {
|
|
||||||
ContactSelectionListAdapter adapter = new ContactSelectionListAdapter(getActivity(),
|
|
||||||
GlideApp.with(this),
|
|
||||||
null,
|
|
||||||
new ListClickListener(),
|
|
||||||
isMulti());
|
|
||||||
selectedContacts = adapter.getSelectedContacts();
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
recyclerView.addItemDecoration(new StickyHeaderDecoration(adapter, true, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeNoContactsPermission() {
|
|
||||||
swipeRefresh.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
showContactsLayout.setVisibility(View.VISIBLE);
|
|
||||||
showContactsProgress.setVisibility(View.INVISIBLE);
|
|
||||||
showContactsDescription.setText(R.string.contact_selection_list_fragment__signal_needs_access_to_your_contacts_in_order_to_display_them);
|
|
||||||
showContactsButton.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
showContactsButton.setOnClickListener(v -> {
|
|
||||||
Permissions.with(this)
|
|
||||||
.request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS)
|
|
||||||
.ifNecessary()
|
|
||||||
.withPermanentDenialDialog(getString(R.string.ContactSelectionListFragment_signal_requires_the_contacts_permission_in_order_to_display_your_contacts))
|
|
||||||
.onSomeGranted(permissions -> {
|
|
||||||
if (permissions.contains(Manifest.permission.WRITE_CONTACTS)) {
|
|
||||||
handleContactPermissionGranted();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setQueryFilter(String filter) {
|
|
||||||
this.cursorFilter = filter;
|
|
||||||
this.getLoaderManager().restartLoader(0, null, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetQueryFilter() {
|
|
||||||
setQueryFilter(null);
|
|
||||||
swipeRefresh.setRefreshing(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRefreshing(boolean refreshing) {
|
|
||||||
swipeRefresh.setRefreshing(refreshing);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
selectedContacts.clear();
|
|
||||||
|
|
||||||
if (!isDetached() && !isRemoving() && getActivity() != null && !getActivity().isFinishing()) {
|
|
||||||
getLoaderManager().restartLoader(0, null, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
|
||||||
return new ContactsCursorLoader(getActivity(),
|
|
||||||
getActivity().getIntent().getIntExtra(DISPLAY_MODE, DisplayMode.FLAG_ALL),
|
|
||||||
cursorFilter, getActivity().getIntent().getBooleanExtra(RECENTS, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor data) {
|
|
||||||
swipeRefresh.setVisibility(View.VISIBLE);
|
|
||||||
showContactsLayout.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
((CursorRecyclerViewAdapter) recyclerView.getAdapter()).changeCursor(data);
|
|
||||||
emptyText.setText(R.string.contact_selection_group_activity__no_contacts);
|
|
||||||
boolean useFastScroller = (recyclerView.getAdapter().getItemCount() > 20);
|
|
||||||
recyclerView.setVerticalScrollBarEnabled(!useFastScroller);
|
|
||||||
if (useFastScroller) {
|
|
||||||
fastScroller.setVisibility(View.VISIBLE);
|
|
||||||
fastScroller.setRecyclerView(recyclerView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
|
|
||||||
((CursorRecyclerViewAdapter) recyclerView.getAdapter()).changeCursor(null);
|
|
||||||
fastScroller.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
private void handleContactPermissionGranted() {
|
|
||||||
new AsyncTask<Void, Void, Boolean>() {
|
|
||||||
@Override
|
|
||||||
protected void onPreExecute() {
|
|
||||||
swipeRefresh.setVisibility(View.GONE);
|
|
||||||
showContactsLayout.setVisibility(View.VISIBLE);
|
|
||||||
showContactsButton.setVisibility(View.INVISIBLE);
|
|
||||||
showContactsDescription.setText(R.string.ConversationListFragment_loading);
|
|
||||||
showContactsProgress.setVisibility(View.VISIBLE);
|
|
||||||
showContactsProgress.spin();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(Void... voids) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Boolean result) {
|
|
||||||
if (result) {
|
|
||||||
showContactsLayout.setVisibility(View.GONE);
|
|
||||||
swipeRefresh.setVisibility(View.VISIBLE);
|
|
||||||
reset();
|
|
||||||
} else {
|
|
||||||
Toast.makeText(getContext(), R.string.ContactSelectionListFragment_error_retrieving_contacts_check_your_network_connection, Toast.LENGTH_LONG).show();
|
|
||||||
initializeNoContactsPermission();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ListClickListener implements ContactSelectionListAdapter.ItemClickListener {
|
|
||||||
@Override
|
|
||||||
public void onItemClick(ContactSelectionListItem contact) {
|
|
||||||
if (!isMulti() || !selectedContacts.contains(contact.getNumber())) {
|
|
||||||
selectedContacts.add(contact.getNumber());
|
|
||||||
contact.setChecked(true);
|
|
||||||
if (onContactSelectedListener != null) onContactSelectedListener.onContactSelected(contact.getNumber());
|
|
||||||
} else {
|
|
||||||
selectedContacts.remove(contact.getNumber());
|
|
||||||
contact.setChecked(false);
|
|
||||||
if (onContactSelectedListener != null) onContactSelectedListener.onContactDeselected(contact.getNumber());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnContactSelectedListener(OnContactSelectedListener onContactSelectedListener) {
|
|
||||||
this.onContactSelectedListener = onContactSelectedListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener onRefreshListener) {
|
|
||||||
this.swipeRefresh.setOnRefreshListener(onRefreshListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnContactSelectedListener {
|
|
||||||
void onContactSelected(String number);
|
|
||||||
void onContactDeselected(String number);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -49,8 +49,8 @@ import org.thoughtcrime.securesms.database.Address;
|
|||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||||
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
|
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
|
||||||
import org.thoughtcrime.securesms.loki.RecipientAvatarModifiedEvent;
|
import org.thoughtcrime.securesms.loki.utilities.ProfilePictureModifiedEvent;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.JoinPublicChatActivity;
|
import org.thoughtcrime.securesms.loki.activities.JoinPublicChatActivity;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
@ -86,13 +86,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
|||||||
protected void onPreCreate() {
|
protected void onPreCreate() {
|
||||||
dynamicTheme.onCreate(this);
|
dynamicTheme.onCreate(this);
|
||||||
dynamicLanguage.onCreate(this);
|
dynamicLanguage.onCreate(this);
|
||||||
if (TextSecurePreferences.getLocalNumber(this) != null) {
|
|
||||||
ApplicationContext application = ApplicationContext.getInstance(this);
|
|
||||||
application.createDefaultPublicChatsIfNeeded();
|
|
||||||
application.createRSSFeedsIfNeeded();
|
|
||||||
application.getLokiPublicChatManager().startPollersIfNeeded();
|
|
||||||
application.startRSSFeedPollersIfNeeded();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -330,9 +323,9 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
public void onAvatarModified(RecipientAvatarModifiedEvent event) {
|
public void onAvatarModified(ProfilePictureModifiedEvent event) {
|
||||||
Recipient recipient = event.getRecipient();
|
Recipient recipient = event.getRecipient();
|
||||||
if (recipient.isLocalNumber() || recipient.isOurMasterDevice()) {
|
if (recipient.isLocalNumber() || recipient.isUserMasterDevice()) {
|
||||||
initializeProfileIcon(recipient);
|
initializeProfileIcon(recipient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
|||||||
import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
|
import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
|
||||||
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
|
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
|
||||||
import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob;
|
import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.CreatePrivateChatActivity;
|
import org.thoughtcrime.securesms.loki.activities.CreatePrivateChatActivity;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
|
@ -37,8 +37,8 @@ import org.thoughtcrime.securesms.components.FromTextView;
|
|||||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||||
import org.thoughtcrime.securesms.components.TypingIndicatorView;
|
import org.thoughtcrime.securesms.components.TypingIndicatorView;
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MentionUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.MentionUtilities;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||||
@ -272,7 +272,7 @@ public class ConversationListItem extends RelativeLayout
|
|||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull CharSequence getTrimmedSnippet(@NonNull CharSequence snippet) {
|
private @NonNull CharSequence getTrimmedSnippet(@NonNull CharSequence snippet) {
|
||||||
LokiAPIUtilities.INSTANCE.populateUserHexEncodedPublicKeyCacheIfNeeded(threadId, getContext()); // TODO: Terrible place to do this, but okay for now
|
MentionManagerUtilities.INSTANCE.populateUserHexEncodedPublicKeyCacheIfNeeded(threadId, getContext()); // TODO: Terrible place to do this, but okay for now
|
||||||
snippet = MentionUtilities.highlightMentions(snippet, threadId, getContext());
|
snippet = MentionUtilities.highlightMentions(snippet, threadId, getContext());
|
||||||
return snippet.length() <= MAX_SNIPPET_LENGTH ? snippet : snippet.subSequence(0, MAX_SNIPPET_LENGTH);
|
return snippet.length() <= MAX_SNIPPET_LENGTH ? snippet : snippet.subSequence(0, MAX_SNIPPET_LENGTH);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ import org.whispersystems.signalservice.api.crypto.ProfileCipher;
|
|||||||
import org.whispersystems.signalservice.api.util.StreamDetails;
|
import org.whispersystems.signalservice.api.util.StreamDetails;
|
||||||
import org.whispersystems.signalservice.loki.api.LokiDotNetAPI;
|
import org.whispersystems.signalservice.loki.api.LokiDotNetAPI;
|
||||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI;
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -415,9 +415,9 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
|
|||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
Log.d("Loki", "Profile photo uploaded, the url is " + result.getUrl());
|
Log.d("Loki", "Profile photo uploaded, the url is " + result.getUrl());
|
||||||
TextSecurePreferences.setProfileAvatarUrl(context, result.getUrl());
|
TextSecurePreferences.setProfilePictureURL(context, result.getUrl());
|
||||||
} else {
|
} else {
|
||||||
TextSecurePreferences.setProfileAvatarUrl(context, null);
|
TextSecurePreferences.setProfilePictureURL(context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
AvatarHelper.setAvatar(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), avatarBytes);
|
AvatarHelper.setAvatar(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), avatarBytes);
|
||||||
@ -427,7 +427,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
|
|||||||
ProfileKeyUtil.setEncodedProfileKey(context, newProfileKey);
|
ProfileKeyUtil.setEncodedProfileKey(context, newProfileKey);
|
||||||
|
|
||||||
// Update profile key on the public chat server
|
// Update profile key on the public chat server
|
||||||
ApplicationContext.getInstance(context).updatePublicChatProfilePictureIfNeeded();
|
ApplicationContext.getInstance(context).updateOpenGroupProfilePicturesIfNeeded();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d("Loki", "Failed to upload profile photo: " + e);
|
Log.d("Loki", "Failed to upload profile photo: " + e);
|
||||||
return false;
|
return false;
|
||||||
|
@ -18,7 +18,7 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.SmsMigrator.ProgressDescription;
|
import org.thoughtcrime.securesms.database.SmsMigrator.ProgressDescription;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||||
import org.thoughtcrime.securesms.service.ApplicationMigrationService;
|
import org.thoughtcrime.securesms.service.ApplicationMigrationService;
|
||||||
import org.thoughtcrime.securesms.service.ApplicationMigrationService.ImportState;
|
import org.thoughtcrime.securesms.service.ApplicationMigrationService.ImportState;
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|||||||
import org.thoughtcrime.securesms.database.loaders.DeviceListLoader;
|
import org.thoughtcrime.securesms.database.loaders.DeviceListLoader;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.devicelist.Device;
|
import org.thoughtcrime.securesms.devicelist.Device;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.dialogs.DeviceEditingOptionsBottomSheet;
|
import org.thoughtcrime.securesms.loki.dialogs.DeviceEditingOptionsBottomSheet;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.whispersystems.libsignal.util.guava.Function;
|
import org.whispersystems.libsignal.util.guava.Function;
|
||||||
@ -39,7 +39,7 @@ import kotlin.Pair;
|
|||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
import network.loki.messenger.R;
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.loki.GeneralUtilitiesKt.toPx;
|
import static org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt.toPx;
|
||||||
|
|
||||||
public class DeviceListFragment extends ListFragment
|
public class DeviceListFragment extends ListFragment
|
||||||
implements LoaderManager.LoaderCallbacks<List<Device>>,
|
implements LoaderManager.LoaderCallbacks<List<Device>>,
|
||||||
|
@ -19,7 +19,7 @@ import com.nineoldandroids.animation.ArgbEvaluator;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.IntroPagerAdapter.IntroPage;
|
import org.thoughtcrime.securesms.IntroPagerAdapter.IntroPage;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
@ -43,7 +43,6 @@ import com.bumptech.glide.request.transition.Transition;
|
|||||||
import org.thoughtcrime.securesms.avatar.AvatarSelection;
|
import org.thoughtcrime.securesms.avatar.AvatarSelection;
|
||||||
import org.thoughtcrime.securesms.components.PushRecipientsPanel;
|
import org.thoughtcrime.securesms.components.PushRecipientsPanel;
|
||||||
import org.thoughtcrime.securesms.components.PushRecipientsPanel.RecipientsPanelChangedListener;
|
import org.thoughtcrime.securesms.components.PushRecipientsPanel.RecipientsPanelChangedListener;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
|
|
||||||
import org.thoughtcrime.securesms.contacts.RecipientsEditor;
|
import org.thoughtcrime.securesms.contacts.RecipientsEditor;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
|
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
|
||||||
@ -57,6 +56,8 @@ import org.thoughtcrime.securesms.database.ThreadDatabase;
|
|||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
|
import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment;
|
||||||
|
import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListLoader.DisplayMode;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
@ -321,11 +322,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent intent = new Intent(GroupCreateActivity.this, PushContactSelectionActivity.class);
|
Intent intent = new Intent(GroupCreateActivity.this, PushContactSelectionActivity.class);
|
||||||
if (groupToUpdate.isPresent()) {
|
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_FRIENDS);
|
||||||
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_PUSH);
|
|
||||||
} else {
|
|
||||||
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_PUSH | DisplayMode.FLAG_SMS);
|
|
||||||
}
|
|
||||||
startActivityForResult(intent, PICK_CONTACT);
|
startActivityForResult(intent, PICK_CONTACT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,10 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
|
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
|
||||||
import org.thoughtcrime.securesms.components.ContactFilterToolbar.OnFilterChangedListener;
|
import org.thoughtcrime.securesms.components.ContactFilterToolbar.OnFilterChangedListener;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
|
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment;
|
||||||
|
import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListLoader.DisplayMode;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||||
@ -40,7 +41,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
import network.loki.messenger.R;
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
public class InviteActivity extends PassphraseRequiredActionBarActivity implements ContactSelectionListFragment.OnContactSelectedListener {
|
public class InviteActivity extends PassphraseRequiredActionBarActivity {
|
||||||
|
|
||||||
private ContactSelectionListFragment contactsFragment;
|
private ContactSelectionListFragment contactsFragment;
|
||||||
private EditText inviteText;
|
private EditText inviteText;
|
||||||
@ -52,7 +53,7 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState, boolean ready) {
|
protected void onCreate(Bundle savedInstanceState, boolean ready) {
|
||||||
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_SMS);
|
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_FRIENDS);
|
||||||
getIntent().putExtra(ContactSelectionListFragment.MULTI_SELECT, true);
|
getIntent().putExtra(ContactSelectionListFragment.MULTI_SELECT, true);
|
||||||
getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false);
|
getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false);
|
||||||
|
|
||||||
@ -84,7 +85,6 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
|
|||||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
||||||
heart.getViewTreeObserver().addOnPreDrawListener(new HeartPreDrawListener());
|
heart.getViewTreeObserver().addOnPreDrawListener(new HeartPreDrawListener());
|
||||||
}
|
}
|
||||||
contactsFragment.setOnContactSelectedListener(this);
|
|
||||||
shareButton.setOnClickListener(new ShareClickListener());
|
shareButton.setOnClickListener(new ShareClickListener());
|
||||||
smsButton.setOnClickListener(new SmsClickListener());
|
smsButton.setOnClickListener(new SmsClickListener());
|
||||||
smsCancelButton.setOnClickListener(new SmsCancelClickListener());
|
smsCancelButton.setOnClickListener(new SmsCancelClickListener());
|
||||||
@ -99,12 +99,10 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
|
|||||||
return animation;
|
return animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onContactSelected(String number) {
|
public void onContactSelected(String number) {
|
||||||
updateSmsButtonText();
|
updateSmsButtonText();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onContactDeselected(String number) {
|
public void onContactDeselected(String number) {
|
||||||
updateSmsButtonText();
|
updateSmsButtonText();
|
||||||
}
|
}
|
||||||
@ -132,7 +130,6 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void cancelSmsSelection() {
|
private void cancelSmsSelection() {
|
||||||
contactsFragment.reset();
|
|
||||||
updateSmsButtonText();
|
updateSmsButtonText();
|
||||||
ViewUtil.animateOut(smsSendFrame, slideOutAnimation, View.GONE);
|
ViewUtil.animateOut(smsSendFrame, slideOutAnimation, View.GONE);
|
||||||
}
|
}
|
||||||
@ -241,7 +238,6 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
|
|||||||
ViewUtil.animateOut(smsSendFrame, slideOutAnimation, View.GONE).addListener(new Listener<Boolean>() {
|
ViewUtil.animateOut(smsSendFrame, slideOutAnimation, View.GONE).addListener(new Listener<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Boolean result) {
|
public void onSuccess(Boolean result) {
|
||||||
contactsFragment.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,7 +47,7 @@ import org.thoughtcrime.securesms.database.SmsDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.loaders.MessageDetailsLoader;
|
import org.thoughtcrime.securesms.database.loaders.MessageDetailsLoader;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
|
@ -13,9 +13,9 @@ import android.support.v4.app.Fragment;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||||
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
|
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.LandingActivity;
|
import org.thoughtcrime.securesms.loki.activities.LandingActivity;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.SeedActivity;
|
import org.thoughtcrime.securesms.loki.activities.SeedActivity;
|
||||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
@ -19,6 +19,8 @@ package org.thoughtcrime.securesms;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -618,7 +618,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
unidentifiedAccessKey, universalUnidentifiedAccess);
|
unidentifiedAccessKey, universalUnidentifiedAccess);
|
||||||
|
|
||||||
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(RegistrationActivity.this);
|
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(RegistrationActivity.this);
|
||||||
List<PreKeyRecord> records = PreKeyUtil.generatePreKeys(RegistrationActivity.this);
|
List<PreKeyRecord> records = PreKeyUtil.generatePreKeyRecords(RegistrationActivity.this);
|
||||||
SignedPreKeyRecord signedPreKey = PreKeyUtil.generateSignedPreKey(RegistrationActivity.this, identityKey, true);
|
SignedPreKeyRecord signedPreKey = PreKeyUtil.generateSignedPreKey(RegistrationActivity.this, identityKey, true);
|
||||||
|
|
||||||
accountManager.setPreKeys(identityKey.getPublicKey(), signedPreKey, records);
|
accountManager.setPreKeys(identityKey.getPublicKey(), signedPreKey, records);
|
||||||
|
@ -29,19 +29,19 @@ import android.os.Process;
|
|||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.components.SearchToolbar;
|
import org.thoughtcrime.securesms.components.SearchToolbar;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
|
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationActivity;
|
import org.thoughtcrime.securesms.conversation.ConversationActivity;
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment;
|
||||||
|
import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListLoader.DisplayMode;
|
||||||
import org.thoughtcrime.securesms.mediasend.Media;
|
import org.thoughtcrime.securesms.mediasend.Media;
|
||||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||||
@ -52,7 +52,6 @@ import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
|||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
import org.thoughtcrime.securesms.util.FileUtils;
|
import org.thoughtcrime.securesms.util.FileUtils;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@ -68,7 +67,7 @@ import network.loki.messenger.R;
|
|||||||
* @author Jake McGinty
|
* @author Jake McGinty
|
||||||
*/
|
*/
|
||||||
public class ShareActivity extends PassphraseRequiredActionBarActivity
|
public class ShareActivity extends PassphraseRequiredActionBarActivity
|
||||||
implements ContactSelectionListFragment.OnContactSelectedListener, SwipeRefreshLayout.OnRefreshListener
|
implements ContactSelectionListFragment.OnContactSelectedListener
|
||||||
{
|
{
|
||||||
private static final String TAG = ShareActivity.class.getSimpleName();
|
private static final String TAG = ShareActivity.class.getSimpleName();
|
||||||
|
|
||||||
@ -96,14 +95,10 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle icicle, boolean ready) {
|
protected void onCreate(Bundle icicle, boolean ready) {
|
||||||
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
|
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
|
||||||
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE,
|
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_ALL);
|
||||||
TextSecurePreferences.isSmsEnabled(this)
|
|
||||||
? DisplayMode.FLAG_ALL
|
|
||||||
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_GROUPS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false);
|
getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false);
|
||||||
getIntent().putExtra(ContactSelectionListFragment.RECENTS, true);
|
|
||||||
|
|
||||||
setContentView(R.layout.share_activity);
|
setContentView(R.layout.share_activity);
|
||||||
|
|
||||||
@ -170,7 +165,6 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||||||
searchAction = findViewById(R.id.search_action);
|
searchAction = findViewById(R.id.search_action);
|
||||||
contactsFragment = (ContactSelectionListFragment) getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment);
|
contactsFragment = (ContactSelectionListFragment) getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment);
|
||||||
contactsFragment.setOnContactSelectedListener(this);
|
contactsFragment.setOnContactSelectedListener(this);
|
||||||
contactsFragment.setOnRefreshListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeSearch() {
|
private void initializeSearch() {
|
||||||
@ -281,12 +275,6 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onContactDeselected(String number) {
|
public void onContactDeselected(String number) {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRefresh() {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
@ -11,7 +11,7 @@ import android.support.v7.app.AppCompatActivity;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.conversation.ConversationStickerSuggestionAdap
|
|||||||
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MentionUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.MentionUtilities;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.mms.QuoteModel;
|
import org.thoughtcrime.securesms.mms.QuoteModel;
|
||||||
|
@ -75,7 +75,6 @@ public class LinkPreviewView extends FrameLayout {
|
|||||||
container.setBackgroundColor(Color.TRANSPARENT);
|
container.setBackgroundColor(Color.TRANSPARENT);
|
||||||
container.setPadding(0, 0, 0, 0);
|
container.setPadding(0, 0, 0, 0);
|
||||||
divider.setVisibility(VISIBLE);
|
divider.setVisibility(VISIBLE);
|
||||||
// closeButton.setVisibility(VISIBLE);
|
|
||||||
|
|
||||||
closeButton.setOnClickListener(v -> {
|
closeButton.setOnClickListener(v -> {
|
||||||
if (closeClickedListener != null) {
|
if (closeClickedListener != null) {
|
||||||
|
@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
|||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -108,11 +108,7 @@ public class SendButton extends AppCompatImageButton
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onLongClick(View v) {
|
public boolean onLongClick(View v) {
|
||||||
// if (isEnabled() && transportOptions.getEnabledTransports().size() > 1) {
|
// Loki - Do nothing
|
||||||
// getTransportOptionsPopup().display(transportOptions.getEnabledTransports());
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,6 @@ public class TransferControlView extends FrameLayout {
|
|||||||
|
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
view.setVisibility(VISIBLE);
|
view.setVisibility(VISIBLE);
|
||||||
// setVisibility(VISIBLE);
|
|
||||||
} else {
|
} else {
|
||||||
setVisibility(GONE);
|
setVisibility(GONE);
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,16 @@ import org.thoughtcrime.securesms.database.Address;
|
|||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
||||||
|
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
|
||||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import kotlin.Unit;
|
|
||||||
|
|
||||||
@SuppressLint("UseSparseArrays")
|
@SuppressLint("UseSparseArrays")
|
||||||
public class TypingStatusSender {
|
public class TypingStatusSender {
|
||||||
|
|
||||||
@ -82,25 +81,18 @@ public class TypingStatusSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendTyping(long threadId, boolean typingStarted) {
|
private void sendTyping(long threadId, boolean typingStarted) {
|
||||||
LokiFileServerAPI storageAPI = LokiFileServerAPI.Companion.getShared();
|
|
||||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||||
Recipient recipient = threadDatabase.getRecipientForThreadId(threadId);
|
Recipient recipient = threadDatabase.getRecipientForThreadId(threadId);
|
||||||
|
// Loki - Check whether we want to send a typing indicator to this user
|
||||||
if (recipient == null) {
|
if (!SessionMetaProtocol.shouldSendTypingIndicator(recipient, context)) { return; }
|
||||||
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(threadId, typingStarted));
|
// Loki - Take into account multi device
|
||||||
return;
|
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.getAddress().serialize());
|
||||||
}
|
for (String device : linkedDevices) {
|
||||||
LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(recipient.getAddress().serialize()).success(devices -> {
|
Recipient deviceAsRecipient = Recipient.from(context, Address.fromSerialized(device), false);
|
||||||
for (String device : devices) {
|
long deviceThreadID = threadDatabase.getThreadIdFor(deviceAsRecipient);
|
||||||
Recipient deviceRecipient = Recipient.from(context, Address.fromSerialized(device), false);
|
|
||||||
long deviceThreadID = threadDatabase.getThreadIdIfExistsFor(deviceRecipient);
|
|
||||||
if (deviceThreadID > -1) {
|
|
||||||
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(deviceThreadID, typingStarted));
|
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(deviceThreadID, typingStarted));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Unit.INSTANCE;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private class StartRunnable implements Runnable {
|
private class StartRunnable implements Runnable {
|
||||||
|
|
||||||
|
@ -8,9 +8,9 @@ import android.provider.Telephony;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
public class DefaultSmsReminder extends Reminder {
|
public class DefaultSmsReminder extends Reminder {
|
||||||
|
|
||||||
@ -40,14 +40,5 @@ public class DefaultSmsReminder extends Reminder {
|
|||||||
|
|
||||||
public static boolean isEligible(Context context) {
|
public static boolean isEligible(Context context) {
|
||||||
return false;
|
return false;
|
||||||
// Loki - Original code
|
|
||||||
// ========
|
|
||||||
// final boolean isDefault = Util.isDefaultSmsProvider(context);
|
|
||||||
// if (isDefault) {
|
|
||||||
// TextSecurePreferences.setPromptedDefaultSmsProvider(context, false);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return !isDefault && !TextSecurePreferences.hasPromptedDefaultSmsProvider(context);
|
|
||||||
// ========
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.RegistrationActivity;
|
import org.thoughtcrime.securesms.RegistrationActivity;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
public class PushRegistrationReminder extends Reminder {
|
public class PushRegistrationReminder extends Reminder {
|
||||||
|
|
||||||
@ -30,9 +30,5 @@ public class PushRegistrationReminder extends Reminder {
|
|||||||
|
|
||||||
public static boolean isEligible(Context context) {
|
public static boolean isEligible(Context context) {
|
||||||
return false;
|
return false;
|
||||||
// Loki - Original code
|
|
||||||
// ========
|
|
||||||
// return !TextSecurePreferences.isPushRegistered(context);
|
|
||||||
// ========
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,271 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms.contacts;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.provider.ContactsContract;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.text.SpannableString;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.text.style.ForegroundColorSpan;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller.FastScrollAdapter;
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter.HeaderViewHolder;
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter.ViewHolder;
|
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
|
||||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
|
||||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration.StickyHeaderAdapter;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List adapter to display all contacts and their related information
|
|
||||||
*
|
|
||||||
* @author Jake McGinty
|
|
||||||
*/
|
|
||||||
public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewHolder>
|
|
||||||
implements FastScrollAdapter,
|
|
||||||
StickyHeaderAdapter<HeaderViewHolder>
|
|
||||||
{
|
|
||||||
private final static String TAG = ContactSelectionListAdapter.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final int VIEW_TYPE_CONTACT = 0;
|
|
||||||
private static final int VIEW_TYPE_DIVIDER = 1;
|
|
||||||
|
|
||||||
private final static int STYLE_ATTRIBUTES[] = new int[]{R.attr.contact_selection_push_user,
|
|
||||||
R.attr.contact_selection_lay_user};
|
|
||||||
|
|
||||||
private final boolean multiSelect;
|
|
||||||
private final LayoutInflater li;
|
|
||||||
private final TypedArray drawables;
|
|
||||||
private final ItemClickListener clickListener;
|
|
||||||
private final GlideRequests glideRequests;
|
|
||||||
|
|
||||||
private final Set<String> selectedContacts = new HashSet<>();
|
|
||||||
|
|
||||||
public abstract static class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
|
|
||||||
public ViewHolder(View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void bind(@NonNull GlideRequests glideRequests, int type, String name, String number, String label, int color, boolean multiSelect);
|
|
||||||
public abstract void unbind(@NonNull GlideRequests glideRequests);
|
|
||||||
public abstract void setChecked(boolean checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ContactViewHolder extends ViewHolder {
|
|
||||||
ContactViewHolder(@NonNull final View itemView,
|
|
||||||
@Nullable final ItemClickListener clickListener)
|
|
||||||
{
|
|
||||||
super(itemView);
|
|
||||||
itemView.setOnClickListener(v -> {
|
|
||||||
if (clickListener != null) clickListener.onItemClick(getView());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContactSelectionListItem getView() {
|
|
||||||
return (ContactSelectionListItem) itemView;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void bind(@NonNull GlideRequests glideRequests, int type, String name, String number, String label, int color, boolean multiSelect) {
|
|
||||||
getView().set(glideRequests, type, name, number, label, color, multiSelect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unbind(@NonNull GlideRequests glideRequests) {
|
|
||||||
getView().unbind(glideRequests);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setChecked(boolean checked) {
|
|
||||||
getView().setChecked(checked);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DividerViewHolder extends ViewHolder {
|
|
||||||
|
|
||||||
private final TextView label;
|
|
||||||
|
|
||||||
DividerViewHolder(View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
this.label = itemView.findViewById(R.id.label);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bind(@NonNull GlideRequests glideRequests, int type, String name, String number, String label, int color, boolean multiSelect) {
|
|
||||||
this.label.setText(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unbind(@NonNull GlideRequests glideRequests) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setChecked(boolean checked) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class HeaderViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
HeaderViewHolder(View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContactSelectionListAdapter(@NonNull Context context,
|
|
||||||
@NonNull GlideRequests glideRequests,
|
|
||||||
@Nullable Cursor cursor,
|
|
||||||
@Nullable ItemClickListener clickListener,
|
|
||||||
boolean multiSelect)
|
|
||||||
{
|
|
||||||
super(context, cursor);
|
|
||||||
this.li = LayoutInflater.from(context);
|
|
||||||
this.glideRequests = glideRequests;
|
|
||||||
this.drawables = context.obtainStyledAttributes(STYLE_ATTRIBUTES);
|
|
||||||
this.multiSelect = multiSelect;
|
|
||||||
this.clickListener = clickListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getHeaderId(int i) {
|
|
||||||
if (!isActiveCursor()) return -1;
|
|
||||||
|
|
||||||
int contactType = getContactType(i);
|
|
||||||
|
|
||||||
if (contactType == ContactsDatabase.DIVIDER_TYPE) return -1;
|
|
||||||
return Util.hashCode(getHeaderString(i), getContactType(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
|
|
||||||
if (viewType == VIEW_TYPE_CONTACT) {
|
|
||||||
return new ContactViewHolder(li.inflate(R.layout.contact_selection_list_item, parent, false), clickListener);
|
|
||||||
} else {
|
|
||||||
return new DividerViewHolder(li.inflate(R.layout.contact_selection_list_divider, parent, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) {
|
|
||||||
int contactType = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsDatabase.CONTACT_TYPE_COLUMN));
|
|
||||||
String name = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NAME_COLUMN));
|
|
||||||
String number = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_COLUMN));
|
|
||||||
int numberType = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_TYPE_COLUMN));
|
|
||||||
String label = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.LABEL_COLUMN));
|
|
||||||
String labelText = ContactsContract.CommonDataKinds.Phone.getTypeLabel(getContext().getResources(),
|
|
||||||
numberType, label).toString();
|
|
||||||
|
|
||||||
int color = (contactType == ContactsDatabase.PUSH_TYPE) ? drawables.getColor(0, 0xa0000000) :
|
|
||||||
drawables.getColor(1, 0xff000000);
|
|
||||||
|
|
||||||
viewHolder.unbind(glideRequests);
|
|
||||||
viewHolder.bind(glideRequests, contactType, name, number, labelText, color, multiSelect);
|
|
||||||
viewHolder.setChecked(selectedContacts.contains(number));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemViewType(@NonNull Cursor cursor) {
|
|
||||||
if (cursor.getInt(cursor.getColumnIndexOrThrow(ContactsDatabase.CONTACT_TYPE_COLUMN)) == ContactsDatabase.DIVIDER_TYPE) {
|
|
||||||
return VIEW_TYPE_DIVIDER;
|
|
||||||
} else {
|
|
||||||
return VIEW_TYPE_CONTACT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
|
|
||||||
return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.contact_selection_recyclerview_header, parent, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) {
|
|
||||||
((TextView)viewHolder.itemView).setText(getSpannedHeaderString(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onItemViewRecycled(ViewHolder holder) {
|
|
||||||
holder.unbind(glideRequests);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CharSequence getBubbleText(int position) {
|
|
||||||
return getHeaderString(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getSelectedContacts() {
|
|
||||||
return selectedContacts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CharSequence getSpannedHeaderString(int position) {
|
|
||||||
final String headerString = getHeaderString(position);
|
|
||||||
if (isPush(position)) {
|
|
||||||
SpannableString spannable = new SpannableString(headerString);
|
|
||||||
spannable.setSpan(new ForegroundColorSpan(getContext().getResources().getColor(R.color.signal_primary)), 0, headerString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
||||||
return spannable;
|
|
||||||
} else {
|
|
||||||
return headerString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private @NonNull String getHeaderString(int position) {
|
|
||||||
int contactType = getContactType(position);
|
|
||||||
|
|
||||||
if (contactType == ContactsDatabase.RECENT_TYPE || contactType == ContactsDatabase.DIVIDER_TYPE) {
|
|
||||||
return " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
Cursor cursor = getCursorAtPositionOrThrow(position);
|
|
||||||
String letter = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NAME_COLUMN));
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(letter)) {
|
|
||||||
String firstChar = letter.trim().substring(0, 1).toUpperCase();
|
|
||||||
if (Character.isLetterOrDigit(firstChar.codePointAt(0))) {
|
|
||||||
return firstChar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "#";
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getContactType(int position) {
|
|
||||||
final Cursor cursor = getCursorAtPositionOrThrow(position);
|
|
||||||
return cursor.getInt(cursor.getColumnIndexOrThrow(ContactsDatabase.CONTACT_TYPE_COLUMN));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isPush(int position) {
|
|
||||||
return getContactType(position) == ContactsDatabase.PUSH_TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ItemClickListener {
|
|
||||||
void onItemClick(ContactSelectionListItem item);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,161 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.contacts;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|
||||||
import org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView;
|
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
|
||||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
|
|
||||||
public class ContactSelectionListItem extends LinearLayout implements RecipientModifiedListener {
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final String TAG = ContactSelectionListItem.class.getSimpleName();
|
|
||||||
|
|
||||||
private ProfilePictureView profilePictureView;
|
|
||||||
private TextView numberView;
|
|
||||||
private TextView nameView;
|
|
||||||
private TextView labelView;
|
|
||||||
private CheckBox checkBox;
|
|
||||||
|
|
||||||
private String number;
|
|
||||||
private Recipient recipient;
|
|
||||||
private GlideRequests glideRequests;
|
|
||||||
private long threadID;
|
|
||||||
|
|
||||||
public ContactSelectionListItem(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContactSelectionListItem(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onFinishInflate() {
|
|
||||||
super.onFinishInflate();
|
|
||||||
this.profilePictureView = findViewById(R.id.profilePictureView);
|
|
||||||
this.numberView = findViewById(R.id.number);
|
|
||||||
this.labelView = findViewById(R.id.label);
|
|
||||||
this.nameView = findViewById(R.id.name);
|
|
||||||
this.checkBox = findViewById(R.id.check_box);
|
|
||||||
|
|
||||||
ViewUtil.setTextViewGravityStart(this.nameView, getContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(@NonNull GlideRequests glideRequests, int type, String name, String number, String label, int color, boolean multiSelect) {
|
|
||||||
this.glideRequests = glideRequests;
|
|
||||||
this.number = number;
|
|
||||||
|
|
||||||
if (type == ContactsDatabase.NEW_TYPE) {
|
|
||||||
this.recipient = null;
|
|
||||||
} else if (!TextUtils.isEmpty(number)) {
|
|
||||||
Address address = Address.fromExternal(getContext(), number);
|
|
||||||
this.recipient = Recipient.from(getContext(), address, true);
|
|
||||||
this.recipient.addListener(this);
|
|
||||||
|
|
||||||
if (this.recipient.getName() != null) {
|
|
||||||
name = this.recipient.getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
threadID = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(recipient);
|
|
||||||
|
|
||||||
this.numberView.setTextColor(color);
|
|
||||||
updateProfilePicture(glideRequests, name, threadID);
|
|
||||||
|
|
||||||
if (!multiSelect && recipient != null && recipient.isLocalNumber()) {
|
|
||||||
name = getContext().getString(R.string.note_to_self);
|
|
||||||
}
|
|
||||||
|
|
||||||
setText(type, name, number, label);
|
|
||||||
|
|
||||||
if (multiSelect) this.checkBox.setVisibility(View.VISIBLE);
|
|
||||||
else this.checkBox.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setChecked(boolean selected) {
|
|
||||||
this.checkBox.setChecked(selected);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unbind(GlideRequests glideRequests) {
|
|
||||||
if (recipient != null) {
|
|
||||||
recipient.removeListener(this);
|
|
||||||
recipient = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setText(int type, String name, String number, String label) {
|
|
||||||
if (number == null || number.isEmpty() || GroupUtil.isEncodedGroup(number)) {
|
|
||||||
this.nameView.setEnabled(false);
|
|
||||||
this.numberView.setText("");
|
|
||||||
this.labelView.setVisibility(View.GONE);
|
|
||||||
} else if (type == ContactsDatabase.PUSH_TYPE) {
|
|
||||||
this.numberView.setText(number);
|
|
||||||
this.nameView.setEnabled(true);
|
|
||||||
this.labelView.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
this.numberView.setText(number);
|
|
||||||
this.nameView.setEnabled(true);
|
|
||||||
this.labelView.setText(label);
|
|
||||||
this.labelView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.nameView.setText(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNumber() {
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onModified(final Recipient recipient) {
|
|
||||||
if (this.recipient == recipient) {
|
|
||||||
Util.runOnMain(() -> {
|
|
||||||
threadID = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(recipient);
|
|
||||||
updateProfilePicture(glideRequests, recipient.getName(), threadID);
|
|
||||||
nameView.setText(recipient.toShortString());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateProfilePicture(GlideRequests glide, String name, long threadID) {
|
|
||||||
if (this.recipient.isGroupRecipient()) {
|
|
||||||
Set<String> usersAsSet = LokiAPI.Companion.getUserHexEncodedPublicKeyCache().get(threadID);
|
|
||||||
if (usersAsSet == null) {
|
|
||||||
usersAsSet = new HashSet<>();
|
|
||||||
}
|
|
||||||
ArrayList<String> users = new ArrayList<>(usersAsSet);
|
|
||||||
Collections.sort(users); // Sort to provide a level of stability
|
|
||||||
profilePictureView.setHexEncodedPublicKey(users.size() > 0 ? users.get(0) : "");
|
|
||||||
profilePictureView.setAdditionalHexEncodedPublicKey(users.size() > 1 ? users.get(1) : "");
|
|
||||||
profilePictureView.setRSSFeed(name.equals("Loki News") || name.equals("Session Updates"));
|
|
||||||
} else {
|
|
||||||
profilePictureView.setHexEncodedPublicKey(this.number);
|
|
||||||
profilePictureView.setAdditionalHexEncodedPublicKey(null);
|
|
||||||
profilePictureView.setRSSFeed(false);
|
|
||||||
}
|
|
||||||
profilePictureView.glide = glide;
|
|
||||||
profilePictureView.update();
|
|
||||||
}
|
|
||||||
}
|
|
@ -139,7 +139,6 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
|||||||
import org.thoughtcrime.securesms.database.MmsSmsColumns.Types;
|
import org.thoughtcrime.securesms.database.MmsSmsColumns.Types;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.database.identity.IdentityRecordList;
|
import org.thoughtcrime.securesms.database.identity.IdentityRecordList;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
@ -155,16 +154,17 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
|||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
|
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||||
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.LokiThreadDatabaseDelegate;
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabaseDelegate;
|
||||||
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
|
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities;
|
import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase;
|
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.views.FriendRequestViewDelegate;
|
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.views.MentionCandidateSelectionView;
|
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.views.SessionRestoreBannerView;
|
import org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView;
|
||||||
|
import org.thoughtcrime.securesms.loki.views.SessionRestoreBannerView;
|
||||||
import org.thoughtcrime.securesms.mediasend.Media;
|
import org.thoughtcrime.securesms.mediasend.Media;
|
||||||
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
|
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
|
||||||
import org.thoughtcrime.securesms.mms.AttachmentManager;
|
import org.thoughtcrime.securesms.mms.AttachmentManager;
|
||||||
@ -214,7 +214,6 @@ import org.thoughtcrime.securesms.util.Dialogs;
|
|||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||||
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||||
@ -228,13 +227,12 @@ import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
|||||||
import org.thoughtcrime.securesms.util.views.Stub;
|
import org.thoughtcrime.securesms.util.views.Stub;
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLink;
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat;
|
||||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
import org.whispersystems.signalservice.loki.protocol.mentions.Mention;
|
||||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager;
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol;
|
||||||
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus;
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
|
||||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus;
|
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus;
|
||||||
import org.whispersystems.signalservice.loki.messaging.Mention;
|
|
||||||
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
|
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -242,7 +240,6 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -357,7 +354,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
private final DynamicNoActionBarTheme dynamicTheme = new DynamicNoActionBarTheme();
|
private final DynamicNoActionBarTheme dynamicTheme = new DynamicNoActionBarTheme();
|
||||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||||
|
|
||||||
// Message Status Bar
|
// Message status bar
|
||||||
private ArrayList<BroadcastReceiver> broadcastReceivers = new ArrayList<>();
|
private ArrayList<BroadcastReceiver> broadcastReceivers = new ArrayList<>();
|
||||||
private String messageStatus = null;
|
private String messageStatus = null;
|
||||||
|
|
||||||
@ -368,9 +365,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
private ArrayList<Mention> mentions = new ArrayList<>();
|
private ArrayList<Mention> mentions = new ArrayList<>();
|
||||||
private String oldText = "";
|
private String oldText = "";
|
||||||
|
|
||||||
// Multi Device
|
|
||||||
private boolean isFriendsWithAnyDevice = false;
|
|
||||||
|
|
||||||
// Restoration
|
// Restoration
|
||||||
protected SessionRestoreBannerView sessionRestoreBannerView;
|
protected SessionRestoreBannerView sessionRestoreBannerView;
|
||||||
|
|
||||||
@ -458,7 +452,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
});
|
});
|
||||||
|
|
||||||
sessionRestoreBannerView.setOnRestore(() -> {
|
sessionRestoreBannerView.setOnRestore(() -> {
|
||||||
this.restoreSession();
|
SessionManagementProtocol.startSessionReset(this, recipient, threadId);
|
||||||
|
updateSessionRestoreBanner();
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
sessionRestoreBannerView.setOnDismiss(() -> {
|
sessionRestoreBannerView.setOnDismiss(() -> {
|
||||||
@ -468,7 +463,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
|
|
||||||
LokiAPIUtilities.INSTANCE.populateUserHexEncodedPublicKeyCacheIfNeeded(threadId, this);
|
MentionManagerUtilities.INSTANCE.populateUserHexEncodedPublicKeyCacheIfNeeded(threadId, this);
|
||||||
|
|
||||||
LokiPublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
|
LokiPublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
|
||||||
if (publicChat != null) {
|
if (publicChat != null) {
|
||||||
@ -559,6 +554,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
markThreadAsRead();
|
markThreadAsRead();
|
||||||
|
|
||||||
DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this);
|
DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this);
|
||||||
|
|
||||||
updateInputPanel();
|
updateInputPanel();
|
||||||
|
|
||||||
updateSessionRestoreBanner();
|
updateSessionRestoreBanner();
|
||||||
@ -747,7 +743,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
MenuInflater inflater = this.getMenuInflater();
|
MenuInflater inflater = this.getMenuInflater();
|
||||||
menu.clear();
|
menu.clear();
|
||||||
|
|
||||||
boolean isOpenGroupOrRSSFeed = recipient.getAddress().isPublicChat() || recipient.getAddress().isRSSFeed();
|
boolean isOpenGroupOrRSSFeed = recipient.getAddress().isOpenGroup() || recipient.getAddress().isRSSFeed();
|
||||||
|
|
||||||
if (isSecureText && !isOpenGroupOrRSSFeed) {
|
if (isSecureText && !isOpenGroupOrRSSFeed) {
|
||||||
if (recipient.getExpireMessages() > 0) {
|
if (recipient.getExpireMessages() > 0) {
|
||||||
@ -1154,7 +1150,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
builder.setMessage(getString(R.string.ConversationActivity_are_you_sure_you_want_to_leave_this_group));
|
builder.setMessage(getString(R.string.ConversationActivity_are_you_sure_you_want_to_leave_this_group));
|
||||||
builder.setPositiveButton(R.string.yes, (dialog, which) -> {
|
builder.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||||
Recipient groupRecipient = getRecipient();
|
Recipient groupRecipient = getRecipient();
|
||||||
if (GroupUtil.leaveGroup(this, groupRecipient)) {
|
if (ClosedGroupsProtocol.leaveGroup(this, groupRecipient)) {
|
||||||
initializeEnabledCheck();
|
initializeEnabledCheck();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show();
|
||||||
@ -1240,11 +1236,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
private boolean handleDisplayQuickContact() {
|
private boolean handleDisplayQuickContact() {
|
||||||
return !recipient.getAddress().isGroup();
|
return !recipient.getAddress().isGroup();
|
||||||
|
|
||||||
// if (recipient.getContactUri() != null) {
|
/*
|
||||||
// ContactsContract.QuickContact.showQuickContact(ConversationActivity.this, titleView, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
if (recipient.getContactUri() != null) {
|
||||||
// } else {
|
ContactsContract.QuickContact.showQuickContact(ConversationActivity.this, titleView, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
||||||
// handleAddToContacts();
|
} else {
|
||||||
// }
|
handleAddToContacts();
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleAddAttachment() {
|
private void handleAddAttachment() {
|
||||||
@ -1531,7 +1529,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateSessionRestoreBanner() {
|
private void updateSessionRestoreBanner() {
|
||||||
Set<String> devices = DatabaseFactory.getLokiThreadDatabase(this).getSessionRestoreDevices(threadId);
|
Set<String> devices = DatabaseFactory.getLokiThreadDatabase(this).getSessionRestoreDevices(threadId);
|
||||||
if (devices.size() > 0) {
|
if (devices.size() > 0) {
|
||||||
sessionRestoreBannerView.update(recipient);
|
sessionRestoreBannerView.update(recipient);
|
||||||
@ -1897,6 +1895,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
case AttachmentTypeSelector.TAKE_PHOTO:
|
case AttachmentTypeSelector.TAKE_PHOTO:
|
||||||
attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
|
attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
|
||||||
case AttachmentTypeSelector.ADD_GIF:
|
case AttachmentTypeSelector.ADD_GIF:
|
||||||
|
boolean hasSeenGIFMetaDataWarning = TextSecurePreferences.hasSeenGIFMetaDataWarning(this);
|
||||||
|
if (!hasSeenGIFMetaDataWarning) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setTitle("Search GIFs?");
|
builder.setTitle("Search GIFs?");
|
||||||
builder.setMessage("You will not have full metadata protection when sending GIFs.");
|
builder.setMessage("You will not have full metadata protection when sending GIFs.");
|
||||||
@ -1906,6 +1906,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
});
|
});
|
||||||
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss());
|
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss());
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
|
TextSecurePreferences.setHasSeenGIFMetaDataWarning(this);
|
||||||
|
} else {
|
||||||
|
AttachmentManager.selectGif(this, PICK_GIF, !isSecureText);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2073,7 +2077,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setGroupShareProfileReminder(@NonNull Recipient recipient) {
|
private void setGroupShareProfileReminder(@NonNull Recipient recipient) {
|
||||||
if (recipient.isPushGroupRecipient() && !recipient.isProfileSharing() && !recipient.getAddress().isPublicChat() && !recipient.getAddress().isRSSFeed()) {
|
if (recipient.isPushGroupRecipient() && !recipient.isProfileSharing() && !recipient.getAddress().isOpenGroup() && !recipient.getAddress().isRSSFeed()) {
|
||||||
groupShareProfileView.get().setRecipient(recipient);
|
groupShareProfileView.get().setRecipient(recipient);
|
||||||
groupShareProfileView.get().setVisibility(View.GONE); // Loki - Always hide for now
|
groupShareProfileView.get().setVisibility(View.GONE); // Loki - Always hide for now
|
||||||
} else if (groupShareProfileView.resolved()) {
|
} else if (groupShareProfileView.resolved()) {
|
||||||
@ -2249,72 +2253,39 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleThreadFriendRequestStatusChanged(long threadID) {
|
public void handleThreadFriendRequestStatusChanged(long threadID) {
|
||||||
if (threadID != this.threadId) {
|
if (recipient.isGroupRecipient()) { return; }
|
||||||
Recipient threadRecipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID);
|
boolean isUpdateNeeded = false;
|
||||||
if (threadRecipient != null && !threadRecipient.isGroupRecipient()) {
|
if (threadID == this.threadId) {
|
||||||
LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(threadRecipient.getAddress().serialize()).success(devices -> {
|
isUpdateNeeded = true;
|
||||||
// We should update our input if this thread is a part of the other threads device
|
} else {
|
||||||
if (devices.contains(recipient.getAddress().serialize())) {
|
String thisThreadPublicKey = recipient.getAddress().serialize();
|
||||||
this.updateInputPanel();
|
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; }
|
||||||
}
|
}
|
||||||
return Unit.INSTANCE;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return;
|
if (isUpdateNeeded) {
|
||||||
|
updateInputPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateInputPanel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSessionRestoreDevicesChanged(long threadId) {
|
public void handleSessionRestoreDevicesChanged(long threadID) {
|
||||||
if (threadId == this.threadId) {
|
if (threadID == this.threadId) {
|
||||||
runOnUiThread(this::updateSessionRestoreBanner);
|
runOnUiThread(this::updateSessionRestoreBanner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateInputPanel() {
|
private void updateInputPanel() {
|
||||||
/*
|
boolean shouldInputPanelBeEnabled = FriendRequestProtocol.shouldInputPanelBeEnabled(this, recipient);
|
||||||
isFriendsWithAnyDevice reflects whether we are friends with any of the other user's devices.
|
|
||||||
|
|
||||||
This fixes the case where the input panel disables and enables rapidly, which can occur when we are
|
|
||||||
not friends with the current thread BUT multi device tells us that we are friends with another one of their devices.
|
|
||||||
*/
|
|
||||||
if (recipient.isGroupRecipient() || isNoteToSelf() || isFriendsWithAnyDevice) { setInputPanelEnabled(true); return; }
|
|
||||||
|
|
||||||
// Disable the input panel if a friend request is pending
|
|
||||||
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(this).getFriendRequestStatus(threadId);
|
|
||||||
boolean isPending = friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENDING || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED;
|
|
||||||
setInputPanelEnabled(!isPending);
|
|
||||||
|
|
||||||
// Always enable the input panel if we are friends with the current user
|
|
||||||
isFriendsWithAnyDevice = (friendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS);
|
|
||||||
|
|
||||||
if (!isFriendsWithAnyDevice) {
|
|
||||||
// Enable the input panel if we don't have any pending friend requests OR we are friends with one of the user's linked devices
|
|
||||||
MultiDeviceUtilities.hasPendingFriendRequestWithAnyLinkedDevice(this, recipient).success( hasPendingRequests -> {
|
|
||||||
if (!hasPendingRequests) {
|
|
||||||
setInputPanelEnabled(true);
|
|
||||||
} else {
|
|
||||||
MultiDeviceUtilities.isFriendsWithAnyLinkedDevice(this, recipient).success( isFriends -> {
|
|
||||||
// Enable the input panel if we're friends with any of the user's devices
|
|
||||||
isFriendsWithAnyDevice = isFriends;
|
|
||||||
setInputPanelEnabled(isFriends);
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setInputPanelEnabled(boolean enabled) {
|
|
||||||
Util.runOnMain(() -> {
|
Util.runOnMain(() -> {
|
||||||
updateToggleButtonState();
|
updateToggleButtonState();
|
||||||
String hint = enabled ? "Message" : "Pending session request";
|
String hint = shouldInputPanelBeEnabled ? "Message" : "Pending session request";
|
||||||
inputPanel.setHint(hint);
|
inputPanel.setHint(hint);
|
||||||
inputPanel.setEnabled(enabled);
|
inputPanel.setEnabled(shouldInputPanelBeEnabled);
|
||||||
if (enabled && inputPanel.getVisibility() == View.VISIBLE) {
|
if (shouldInputPanelBeEnabled && inputPanel.getVisibility() == View.VISIBLE) {
|
||||||
inputPanel.composeText.requestFocus();
|
inputPanel.composeText.requestFocus();
|
||||||
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
||||||
inputMethodManager.showSoftInput(inputPanel.composeText, 0);
|
inputMethodManager.showSoftInput(inputPanel.composeText, 0);
|
||||||
@ -2370,7 +2341,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
Log.w(TAG, ex);
|
Log.w(TAG, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageStatus == null && !isGroupConversation()) {
|
if (messageStatus == null && !isGroupConversation() && !SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize())) {
|
||||||
messageStatus = "calculatingPoW";
|
messageStatus = "calculatingPoW";
|
||||||
updateSubtitleTextView();
|
updateSubtitleTextView();
|
||||||
updateMessageStatusProgressBar();
|
updateMessageStatusProgressBar();
|
||||||
@ -2425,7 +2396,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
// Loki - Send a friend request if we're not yet friends with the user in question
|
// Loki - Send a friend request if we're not yet friends with the user in question
|
||||||
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId);
|
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId);
|
||||||
outgoingMessage.isFriendRequest = !isGroupConversation() && friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS; // Needed for stageOutgoingMessage(...)
|
outgoingMessage.isFriendRequest = !isGroupConversation() && friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS
|
||||||
|
&& !SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize()); // Needed for stageOutgoingMessage(...)
|
||||||
|
|
||||||
if (clearComposeBox) {
|
if (clearComposeBox) {
|
||||||
inputPanel.clearQuote();
|
inputPanel.clearQuote();
|
||||||
@ -2477,7 +2449,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
// Loki - Send a friend request if we're not yet friends with the user in question
|
// Loki - Send a friend request if we're not yet friends with the user in question
|
||||||
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId);
|
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId);
|
||||||
message.isFriendRequest = !isGroupConversation() && friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS; // Needed for stageOutgoingMessage(...)
|
message.isFriendRequest = !isGroupConversation() && friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS
|
||||||
|
&& !SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize()); // Needed for stageOutgoingMessage(...)
|
||||||
|
|
||||||
silentlySetComposeText("");
|
silentlySetComposeText("");
|
||||||
final long id = fragment.stageOutgoingMessage(message);
|
final long id = fragment.stageOutgoingMessage(message);
|
||||||
@ -2508,8 +2481,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateToggleButtonState() {
|
private void updateToggleButtonState() {
|
||||||
// Don't allow attachments if we're not friends with any of the user's devices
|
if (!FriendRequestProtocol.shouldAttachmentButtonBeEnabled(this, recipient)) {
|
||||||
if (!isNoteToSelf() && !recipient.isGroupRecipient() && !isFriendsWithAnyDevice) {
|
|
||||||
buttonToggle.display(sendButton);
|
buttonToggle.display(sendButton);
|
||||||
quickAttachmentToggle.hide();
|
quickAttachmentToggle.hide();
|
||||||
inlineAttachmentToggle.hide();
|
inlineAttachmentToggle.hide();
|
||||||
@ -2745,7 +2717,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
private void silentlySetComposeText(String text) {
|
private void silentlySetComposeText(String text) {
|
||||||
typingTextWatcher.setEnabled(false);
|
typingTextWatcher.setEnabled(false);
|
||||||
composeText.setText(text);
|
composeText.setText(text);
|
||||||
if (text.isEmpty()) resetMentions();
|
if (text.isEmpty()) { resetMentions(); }
|
||||||
typingTextWatcher.setEnabled(true);
|
typingTextWatcher.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2905,7 +2877,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
LokiThreadDatabase threadDatabase = DatabaseFactory.getLokiThreadDatabase(ConversationActivity.this);
|
LokiThreadDatabase threadDatabase = DatabaseFactory.getLokiThreadDatabase(ConversationActivity.this);
|
||||||
LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(ConversationActivity.this);
|
LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(ConversationActivity.this);
|
||||||
if (lastCharacter == '@' && Character.isWhitespace(secondToLastCharacter)) {
|
if (lastCharacter == '@' && Character.isWhitespace(secondToLastCharacter)) {
|
||||||
List<Mention> mentionCandidates = LokiAPI.Companion.getMentionCandidates("", threadId, userHexEncodedPublicKey, threadDatabase, userDatabase);
|
List<Mention> mentionCandidates = MentionsManager.shared.getMentionCandidates("", threadId);
|
||||||
currentMentionStartIndex = lastCharacterIndex;
|
currentMentionStartIndex = lastCharacterIndex;
|
||||||
mentionCandidateSelectionViewContainer.setVisibility(View.VISIBLE);
|
mentionCandidateSelectionViewContainer.setVisibility(View.VISIBLE);
|
||||||
mentionCandidateSelectionView.show(mentionCandidates, threadId);
|
mentionCandidateSelectionView.show(mentionCandidates, threadId);
|
||||||
@ -2916,7 +2888,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
} else {
|
} else {
|
||||||
if (currentMentionStartIndex != -1) {
|
if (currentMentionStartIndex != -1) {
|
||||||
String query = text.substring(currentMentionStartIndex + 1); // + 1 to get rid of the @
|
String query = text.substring(currentMentionStartIndex + 1); // + 1 to get rid of the @
|
||||||
List<Mention> mentionCandidates = LokiAPI.Companion.getMentionCandidates(query, threadId, userHexEncodedPublicKey, threadDatabase, userDatabase);
|
List<Mention> mentionCandidates = MentionsManager.shared.getMentionCandidates(query, threadId);
|
||||||
mentionCandidateSelectionViewContainer.setVisibility(View.VISIBLE);
|
mentionCandidateSelectionViewContainer.setVisibility(View.VISIBLE);
|
||||||
mentionCandidateSelectionView.show(mentionCandidates, threadId);
|
mentionCandidateSelectionView.show(mentionCandidates, threadId);
|
||||||
}
|
}
|
||||||
@ -3106,17 +3078,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
// region Loki
|
// region Loki
|
||||||
private void updateTitleTextView(Recipient recipient) {
|
private void updateTitleTextView(Recipient recipient) {
|
||||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
|
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||||
Set<DeviceLink> deviceLinks = DatabaseFactory.getLokiAPIDatabase(this).getDeviceLinks(userHexEncodedPublicKey);
|
Set<String> allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey);
|
||||||
HashSet<String> userLinkedDeviceHexEncodedPublicKeys = new HashSet<>();
|
|
||||||
for (DeviceLink deviceLink : deviceLinks) {
|
|
||||||
userLinkedDeviceHexEncodedPublicKeys.add(deviceLink.getMasterHexEncodedPublicKey().toLowerCase());
|
|
||||||
userLinkedDeviceHexEncodedPublicKeys.add(deviceLink.getSlaveHexEncodedPublicKey().toLowerCase());
|
|
||||||
}
|
|
||||||
userLinkedDeviceHexEncodedPublicKeys.add(userHexEncodedPublicKey.toLowerCase());
|
|
||||||
if (recipient == null) {
|
if (recipient == null) {
|
||||||
titleTextView.setText("Compose");
|
titleTextView.setText("Compose");
|
||||||
} else if (userLinkedDeviceHexEncodedPublicKeys.contains(recipient.getAddress().toString().toLowerCase())) {
|
} else if (allUserDevices.contains(recipient.getAddress().toString().toLowerCase())) {
|
||||||
titleTextView.setText("Note to Self");
|
titleTextView.setText("Note to Self");
|
||||||
} else {
|
} else {
|
||||||
boolean hasName = (recipient.getName() != null && !recipient.getName().isEmpty());
|
boolean hasName = (recipient.getName() != null && !recipient.getName().isEmpty());
|
||||||
@ -3192,7 +3158,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleMessageStatusChanged(String newMessageStatus, long timestamp) {
|
private void handleMessageStatusChanged(String newMessageStatus, long timestamp) {
|
||||||
if (timestamp == 0) { return; }
|
if (timestamp == 0 || SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize()) ) { return; }
|
||||||
updateForNewMessageStatusIfNeeded(newMessageStatus, timestamp);
|
updateForNewMessageStatusIfNeeded(newMessageStatus, timestamp);
|
||||||
if (newMessageStatus.equals("messageFailed") || newMessageStatus.equals("messageSent")) {
|
if (newMessageStatus.equals("messageFailed") || newMessageStatus.equals("messageSent")) {
|
||||||
new Handler().postDelayed(() -> clearMessageStatusIfNeeded(timestamp), 1000);
|
new Handler().postDelayed(() -> clearMessageStatusIfNeeded(timestamp), 1000);
|
||||||
@ -3232,48 +3198,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acceptFriendRequest(@NotNull MessageRecord friendRequest) {
|
public void acceptFriendRequest(@NotNull MessageRecord friendRequest) {
|
||||||
// Send the accept to the original friend request thread ID
|
if (recipient.isGroupRecipient()) { return; }
|
||||||
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(this);
|
FriendRequestProtocol.acceptFriendRequest(this, recipient);
|
||||||
long originalThreadID = lokiMessageDatabase.getOriginalThreadID(friendRequest.id);
|
|
||||||
long threadID = originalThreadID < 0 ? this.threadId : originalThreadID;
|
|
||||||
Recipient contact = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID);
|
|
||||||
Address address = contact.getAddress();
|
|
||||||
String contactHexEncodedPublicKey = address.serialize();
|
|
||||||
DatabaseFactory.getLokiThreadDatabase(this).setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS);
|
|
||||||
lokiMessageDatabase.setFriendRequestStatus(friendRequest.id, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED);
|
|
||||||
DatabaseFactory.getRecipientDatabase(this).setProfileSharing(contact, true);
|
|
||||||
MessageSender.sendBackgroundMessageToAllDevices(this, contactHexEncodedPublicKey);
|
|
||||||
MessageSender.syncContact(this, address);
|
|
||||||
updateInputPanel();
|
updateInputPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void rejectFriendRequest(@NotNull MessageRecord friendRequest) {
|
public void rejectFriendRequest(@NotNull MessageRecord friendRequest) {
|
||||||
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(this);
|
|
||||||
long originalThreadID = lokiMessageDatabase.getOriginalThreadID(friendRequest.id);
|
|
||||||
long threadID = originalThreadID < 0 ? this.threadId : originalThreadID;
|
|
||||||
DatabaseFactory.getLokiThreadDatabase(this).setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.NONE);
|
|
||||||
String contactID = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID).getAddress().toString();
|
|
||||||
DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(contactID);
|
|
||||||
updateInputPanel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNoteToSelf() {
|
|
||||||
return TextSecurePreferences.getLocalNumber(this).equals(recipient.getAddress().serialize());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void restoreSession() {
|
|
||||||
if (recipient.isGroupRecipient()) { return; }
|
if (recipient.isGroupRecipient()) { return; }
|
||||||
LokiThreadDatabase lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(this);
|
FriendRequestProtocol.rejectFriendRequest(this, recipient);
|
||||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(this);
|
updateInputPanel();
|
||||||
Set<String> devices = lokiThreadDatabase.getSessionRestoreDevices(threadId);
|
|
||||||
for (String device : devices) { MessageSender.sendRestoreSessionMessage(this, device); }
|
|
||||||
long messageID = smsDatabase.insertMessageOutbox(threadId, new OutgoingTextMessage(recipient,"", 0, 0), false, System.currentTimeMillis(), null);
|
|
||||||
if (messageID > -1) {
|
|
||||||
smsDatabase.markAsLokiSessionRestoreSent(messageID);
|
|
||||||
}
|
|
||||||
lokiThreadDatabase.removeAllSessionRestoreDevices(threadId);
|
|
||||||
updateSessionRestoreBanner();
|
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.views.FriendRequestViewDelegate;
|
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
@ -79,7 +79,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
|||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.views.FriendRequestViewDelegate;
|
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
|
||||||
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
|
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
|
||||||
import org.thoughtcrime.securesms.mediasend.Media;
|
import org.thoughtcrime.securesms.mediasend.Media;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
@ -101,8 +101,8 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
|||||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat;
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI;
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -86,11 +86,11 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob;
|
|||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MentionUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.MentionUtilities;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.views.FriendRequestView;
|
import org.thoughtcrime.securesms.loki.views.FriendRequestView;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.views.FriendRequestViewDelegate;
|
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView;
|
import org.thoughtcrime.securesms.loki.views.ProfilePictureView;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.mms.ImageSlide;
|
import org.thoughtcrime.securesms.mms.ImageSlide;
|
||||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||||
@ -112,8 +112,8 @@ import org.thoughtcrime.securesms.util.Util;
|
|||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.thoughtcrime.securesms.util.views.Stub;
|
import org.thoughtcrime.securesms.util.views.Stub;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat;
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI;
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -49,8 +49,6 @@ public class ConversationPopupActivity extends ConversationActivity {
|
|||||||
else getWindow().setLayout((int) (width * .7), (int) (height * .75));
|
else getWindow().setLayout((int) (width * .7), (int) (height * .75));
|
||||||
|
|
||||||
super.onCreate(bundle, ready);
|
super.onCreate(bundle, ready);
|
||||||
|
|
||||||
// titleView.setOnClickListener(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,7 +43,7 @@ public class PreKeyUtil {
|
|||||||
|
|
||||||
private static final int BATCH_SIZE = 100;
|
private static final int BATCH_SIZE = 100;
|
||||||
|
|
||||||
public synchronized static List<PreKeyRecord> generatePreKeys(Context context) {
|
public synchronized static List<PreKeyRecord> generatePreKeyRecords(Context context) {
|
||||||
PreKeyStore preKeyStore = new TextSecurePreKeyStore(context);
|
PreKeyStore preKeyStore = new TextSecurePreKeyStore(context);
|
||||||
List<PreKeyRecord> records = new LinkedList<>();
|
List<PreKeyRecord> records = new LinkedList<>();
|
||||||
int preKeyIdOffset = TextSecurePreferences.getNextPreKeyId(context);
|
int preKeyIdOffset = TextSecurePreferences.getNextPreKeyId(context);
|
||||||
@ -101,7 +101,7 @@ public class PreKeyUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized static List<PreKeyRecord> generatePreKeys(Context context, int amount) {
|
public synchronized static List<PreKeyRecord> generatePreKeyRecords(Context context, int amount) {
|
||||||
List<PreKeyRecord> records = new LinkedList<>();
|
List<PreKeyRecord> records = new LinkedList<>();
|
||||||
int preKeyIDOffset = TextSecurePreferences.getNextPreKeyId(context);
|
int preKeyIDOffset = TextSecurePreferences.getNextPreKeyId(context);
|
||||||
for (int i = 0; i < amount; i++) {
|
for (int i = 0; i < amount; i++) {
|
||||||
|
@ -9,22 +9,15 @@ import android.support.annotation.WorkerThread;
|
|||||||
import org.signal.libsignal.metadata.SignalProtos;
|
import org.signal.libsignal.metadata.SignalProtos;
|
||||||
import org.signal.libsignal.metadata.certificate.CertificateValidator;
|
import org.signal.libsignal.metadata.certificate.CertificateValidator;
|
||||||
import org.signal.libsignal.metadata.certificate.InvalidCertificateException;
|
import org.signal.libsignal.metadata.certificate.InvalidCertificateException;
|
||||||
import network.loki.messenger.BuildConfig;
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.InvalidKeyException;
|
|
||||||
import org.whispersystems.libsignal.ecc.Curve;
|
|
||||||
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
||||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class UnidentifiedAccessUtil {
|
public class UnidentifiedAccessUtil {
|
||||||
|
|
||||||
private static final String TAG = UnidentifiedAccessUtil.class.getSimpleName();
|
private static final String TAG = UnidentifiedAccessUtil.class.getSimpleName();
|
||||||
|
@ -105,11 +105,11 @@ public class Address implements Parcelable, Comparable<Address> {
|
|||||||
|
|
||||||
public boolean isGroup() { return GroupUtil.isEncodedGroup(address); }
|
public boolean isGroup() { return GroupUtil.isEncodedGroup(address); }
|
||||||
|
|
||||||
public boolean isSignalGroup() { return GroupUtil.isSignalGroup(address); }
|
public boolean isClosedGroup() { return GroupUtil.isClosedGroup(address); }
|
||||||
|
|
||||||
public boolean isPublicChat() { return GroupUtil.isPublicChat(address); }
|
public boolean isOpenGroup() { return GroupUtil.isOpenGroup(address); }
|
||||||
|
|
||||||
public boolean isRSSFeed() { return GroupUtil.isRssFeed(address); }
|
public boolean isRSSFeed() { return GroupUtil.isRSSFeed(address); }
|
||||||
|
|
||||||
public boolean isMmsGroup() { return GroupUtil.isMmsGroup(address); }
|
public boolean isMmsGroup() { return GroupUtil.isMmsGroup(address); }
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ public class Address implements Parcelable, Comparable<Address> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull String toPhoneString() {
|
public @NonNull String toPhoneString() {
|
||||||
if (!isPhone() && !isPublicChat()) {
|
if (!isPhone() && !isOpenGroup()) {
|
||||||
if (isEmail()) throw new AssertionError("Not e164, is email");
|
if (isEmail()) throw new AssertionError("Not e164, is email");
|
||||||
if (isGroup()) throw new AssertionError("Not e164, is group");
|
if (isGroup()) throw new AssertionError("Not e164, is group");
|
||||||
throw new AssertionError("Not e164, unknown");
|
throw new AssertionError("Not e164, unknown");
|
||||||
|
@ -31,11 +31,12 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
|
|||||||
import org.thoughtcrime.securesms.database.helpers.ClassicOpenHelper;
|
import org.thoughtcrime.securesms.database.helpers.ClassicOpenHelper;
|
||||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherMigrationHelper;
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherMigrationHelper;
|
||||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||||
import org.thoughtcrime.securesms.loki.*;
|
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyBundleDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiPreKeyBundleDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyRecordDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiPreKeyRecordDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||||
|
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
|
||||||
public class DatabaseFactory {
|
public class DatabaseFactory {
|
||||||
|
@ -160,13 +160,14 @@ public class GroupDatabase extends Database {
|
|||||||
return recipients;
|
return recipients;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean signalGroupsHaveMember(String hexEncodedPublicKey) {
|
public boolean isClosedGroupMember(String hexEncodedPublicKey) {
|
||||||
try {
|
try {
|
||||||
Address address = Address.fromSerialized(hexEncodedPublicKey);
|
Address address = Address.fromSerialized(hexEncodedPublicKey);
|
||||||
Reader reader = DatabaseFactory.getGroupDatabase(context).getGroups();
|
Reader reader = DatabaseFactory.getGroupDatabase(context).getGroups();
|
||||||
|
|
||||||
GroupRecord record;
|
GroupRecord record;
|
||||||
while ((record = reader.getNext()) != null) {
|
while ((record = reader.getNext()) != null) {
|
||||||
if (record.isSignalGroup() && record.members.contains(address)) {
|
if (record.isClosedGroup() && record.members.contains(address)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,8 +293,7 @@ public class GroupDatabase extends Database {
|
|||||||
contents.put(ADMINS, Address.toSerializedList(admins, ','));
|
contents.put(ADMINS, Address.toSerializedList(admins, ','));
|
||||||
contents.put(ACTIVE, 1);
|
contents.put(ACTIVE, 1);
|
||||||
|
|
||||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
|
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", new String[] {groupId});
|
||||||
new String[] {groupId});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(String groupId, Address source) {
|
public void remove(String groupId, Address source) {
|
||||||
@ -489,11 +489,11 @@ public class GroupDatabase extends Database {
|
|||||||
return mms;
|
return mms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPublicChat() { return Address.fromSerialized(id).isPublicChat(); }
|
public boolean isOpenGroup() { return Address.fromSerialized(id).isOpenGroup(); }
|
||||||
|
|
||||||
public boolean isRSSFeed() { return Address.fromSerialized(id).isRSSFeed(); }
|
public boolean isRSSFeed() { return Address.fromSerialized(id).isRSSFeed(); }
|
||||||
|
|
||||||
public boolean isSignalGroup() { return Address.fromSerialized(id).isSignalGroup(); }
|
public boolean isClosedGroup() { return Address.fromSerialized(id).isClosedGroup(); }
|
||||||
|
|
||||||
public String getUrl() { return url; }
|
public String getUrl() { return url; }
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -252,7 +251,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_NO_SESSION_BIT);
|
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_NO_SESSION_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markAsLokiSessionRestoreSent(long id) {
|
public void markAsSentLokiSessionRestorationRequest(long id) {
|
||||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_LOKI_SESSION_RESTORE_SENT_BIT);
|
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_LOKI_SESSION_RESTORE_SENT_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,7 +537,7 @@ public class ThreadDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Recipient getRecipientForThreadId(long threadId) {
|
public @Nullable Recipient getRecipientForThreadId(long threadId) {
|
||||||
// Loki - Cache the address.
|
// Loki - Cache the address
|
||||||
if (addressCache.containsKey(threadId) && addressCache.get(threadId) != null) {
|
if (addressCache.containsKey(threadId) && addressCache.get(threadId) != null) {
|
||||||
return Recipient.from(context, addressCache.get(threadId), false);
|
return Recipient.from(context, addressCache.get(threadId), false);
|
||||||
}
|
}
|
||||||
|
@ -35,17 +35,17 @@ import org.thoughtcrime.securesms.database.StickerDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
|
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiPreKeyBundleDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyBundleDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiPreKeyRecordDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyRecordDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
@ -81,8 +81,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
private static final int lokiV5 = 26;
|
private static final int lokiV5 = 26;
|
||||||
private static final int lokiV6 = 27;
|
private static final int lokiV6 = 27;
|
||||||
private static final int lokiV7 = 28;
|
private static final int lokiV7 = 28;
|
||||||
|
private static final int lokiV8 = 29;
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = lokiV7; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
private static final int DATABASE_VERSION = lokiV8; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
||||||
private static final String DATABASE_NAME = "signal.db";
|
private static final String DATABASE_NAME = "signal.db";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@ -138,6 +139,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(LokiAPIDatabase.getCreateLastDeletionServerIDTableCommand());
|
db.execSQL(LokiAPIDatabase.getCreateLastDeletionServerIDTableCommand());
|
||||||
db.execSQL(LokiAPIDatabase.getCreateDeviceLinkTableCommand());
|
db.execSQL(LokiAPIDatabase.getCreateDeviceLinkTableCommand());
|
||||||
db.execSQL(LokiAPIDatabase.getCreateUserCountTableCommand());
|
db.execSQL(LokiAPIDatabase.getCreateUserCountTableCommand());
|
||||||
|
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampTableCommand());
|
||||||
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
|
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
|
||||||
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
|
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
|
||||||
db.execSQL(LokiMessageDatabase.getCreateMessageFriendRequestTableCommand());
|
db.execSQL(LokiMessageDatabase.getCreateMessageFriendRequestTableCommand());
|
||||||
@ -181,8 +183,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
@Override
|
@Override
|
||||||
public void onConfigure(SQLiteDatabase db) {
|
public void onConfigure(SQLiteDatabase db) {
|
||||||
super.onConfigure(db);
|
super.onConfigure(db);
|
||||||
// Loki: Enable Write Ahead Logging Mode, increase the cache size
|
// Loki - Enable write ahead logging mode and increase the cache size.
|
||||||
// This should be disabled if we ever run into serious race condition bugs
|
// This should be disabled if we ever run into serious race condition bugs.
|
||||||
db.enableWriteAheadLogging();
|
db.enableWriteAheadLogging();
|
||||||
db.execSQL("PRAGMA cache_size = 10000");
|
db.execSQL("PRAGMA cache_size = 10000");
|
||||||
}
|
}
|
||||||
@ -544,7 +546,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
if (publicChat != null) {
|
if (publicChat != null) {
|
||||||
byte[] groupId = publicChat.getId().getBytes();
|
byte[] groupId = publicChat.getId().getBytes();
|
||||||
String oldId = GroupUtil.getEncodedId(groupId, false);
|
String oldId = GroupUtil.getEncodedId(groupId, false);
|
||||||
String newId = GroupUtil.getEncodedPublicChatId(groupId);
|
String newId = GroupUtil.getEncodedOpenGroupId(groupId);
|
||||||
ContentValues threadUpdate = new ContentValues();
|
ContentValues threadUpdate = new ContentValues();
|
||||||
threadUpdate.put("recipient_ids", newId);
|
threadUpdate.put("recipient_ids", newId);
|
||||||
db.update("thread", threadUpdate, "recipient_ids = ?", new String[]{ oldId });
|
db.update("thread", threadUpdate, "recipient_ids = ?", new String[]{ oldId });
|
||||||
@ -555,7 +557,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate rss feeds from __textsecure_group__ to __loki_rss_feed_group__
|
// Migrate RSS feeds from __textsecure_group__ to __loki_rss_feed_group__
|
||||||
String[] rssFeedIds = new String[] { "loki.network.feed", "loki.network.messenger-updates.feed" };
|
String[] rssFeedIds = new String[] { "loki.network.feed", "loki.network.messenger-updates.feed" };
|
||||||
for (String groupId : rssFeedIds) {
|
for (String groupId : rssFeedIds) {
|
||||||
String oldId = GroupUtil.getEncodedId(groupId.getBytes(), false);
|
String oldId = GroupUtil.getEncodedId(groupId.getBytes(), false);
|
||||||
@ -576,6 +578,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand());
|
db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < lokiV8) {
|
||||||
|
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampTableCommand());
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
@ -8,11 +8,11 @@ import com.annimon.stream.Stream;
|
|||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.devicelist.Device;
|
import org.thoughtcrime.securesms.devicelist.Device;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities;
|
||||||
import org.thoughtcrime.securesms.util.AsyncLoader;
|
import org.thoughtcrime.securesms.util.AsyncLoader;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
|
||||||
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec;
|
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec;
|
||||||
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -33,9 +33,9 @@ public class DeviceListLoader extends AsyncLoader<List<Device>> {
|
|||||||
@Override
|
@Override
|
||||||
public List<Device> loadInBackground() {
|
public List<Device> loadInBackground() {
|
||||||
try {
|
try {
|
||||||
String ourPublicKey = TextSecurePreferences.getLocalNumber(getContext());
|
String userPublicKey = TextSecurePreferences.getLocalNumber(getContext());
|
||||||
Set<String> secondaryDevicePublicKeys = LokiDeviceLinkUtilities.INSTANCE.getSlaveHexEncodedPublicKeys(ourPublicKey).get();
|
Set<String> slaveDevicePublicKeys = MultiDeviceProtocol.shared.getSlaveDevices(userPublicKey);
|
||||||
List<Device> devices = Stream.of(secondaryDevicePublicKeys).map(this::mapToDevice).toList();
|
List<Device> devices = Stream.of(slaveDevicePublicKeys).map(this::mapToDevice).toList();
|
||||||
Collections.sort(devices, new DeviceComparator());
|
Collections.sort(devices, new DeviceComparator());
|
||||||
return devices;
|
return devices;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -21,7 +21,6 @@ import android.content.Context;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||||
@ -30,6 +29,8 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message record model which represents standard SMS messages.
|
* The message record model which represents standard SMS messages.
|
||||||
*
|
*
|
||||||
|
@ -45,9 +45,8 @@ import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
|
|||||||
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.LokiSessionResetImplementation;
|
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation;
|
||||||
import org.thoughtcrime.securesms.loki.MultiDeviceOpenGroupUpdateJob;
|
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceOpenGroupUpdateJob;
|
||||||
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
|
||||||
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
||||||
import org.thoughtcrime.securesms.push.MessageSenderEventListener;
|
import org.thoughtcrime.securesms.push.MessageSenderEventListener;
|
||||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||||
@ -112,7 +111,6 @@ import network.loki.messenger.BuildConfig;
|
|||||||
MultiDeviceStickerPackOperationJob.class,
|
MultiDeviceStickerPackOperationJob.class,
|
||||||
MultiDeviceStickerPackSyncJob.class,
|
MultiDeviceStickerPackSyncJob.class,
|
||||||
LinkPreviewRepository.class,
|
LinkPreviewRepository.class,
|
||||||
PushMessageSyncSendJob.class,
|
|
||||||
MultiDeviceOpenGroupUpdateJob.class})
|
MultiDeviceOpenGroupUpdateJob.class})
|
||||||
|
|
||||||
public class SignalCommunicationModule {
|
public class SignalCommunicationModule {
|
||||||
@ -154,6 +152,7 @@ public class SignalCommunicationModule {
|
|||||||
Optional.fromNullable(IncomingMessageObserver.getUnidentifiedPipe()),
|
Optional.fromNullable(IncomingMessageObserver.getUnidentifiedPipe()),
|
||||||
Optional.of(new MessageSenderEventListener(context)),
|
Optional.of(new MessageSenderEventListener(context)),
|
||||||
TextSecurePreferences.getLocalNumber(context),
|
TextSecurePreferences.getLocalNumber(context),
|
||||||
|
TextSecurePreferences.getMasterHexEncodedPublicKey(context),
|
||||||
DatabaseFactory.getLokiAPIDatabase(context),
|
DatabaseFactory.getLokiAPIDatabase(context),
|
||||||
DatabaseFactory.getLokiThreadDatabase(context),
|
DatabaseFactory.getLokiThreadDatabase(context),
|
||||||
DatabaseFactory.getLokiMessageDatabase(context),
|
DatabaseFactory.getLokiMessageDatabase(context),
|
||||||
|
@ -36,18 +36,18 @@ import java.util.Set;
|
|||||||
|
|
||||||
public class GroupManager {
|
public class GroupManager {
|
||||||
|
|
||||||
public static long getPublicChatThreadId(String id, @NonNull Context context) {
|
public static long getOpenGroupThreadID(String id, @NonNull Context context) {
|
||||||
final String groupId = GroupUtil.getEncodedPublicChatId(id.getBytes());
|
final String groupID = GroupUtil.getEncodedOpenGroupId(id.getBytes());
|
||||||
return getThreadIdFromGroupId(groupId, context);
|
return getThreadIDFromGroupID(groupID, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getRSSFeedThreadId(String id, @NonNull Context context) {
|
public static long getRSSFeedThreadID(String id, @NonNull Context context) {
|
||||||
final String groupId = GroupUtil.getEncodedRSSFeedId(id.getBytes());
|
final String groupID = GroupUtil.getEncodedRSSFeedId(id.getBytes());
|
||||||
return getThreadIdFromGroupId(groupId, context);
|
return getThreadIDFromGroupID(groupID, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getThreadIdFromGroupId(String groupId, @NonNull Context context) {
|
public static long getThreadIDFromGroupID(String groupID, @NonNull Context context) {
|
||||||
final Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupId), false);
|
final Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupID), false);
|
||||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(groupRecipient);
|
return DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(groupRecipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,10 +78,10 @@ public class GroupManager {
|
|||||||
final Set<Address> memberAddresses = getMemberAddresses(members);
|
final Set<Address> memberAddresses = getMemberAddresses(members);
|
||||||
final Set<Address> adminAddresses = getMemberAddresses(admins);
|
final Set<Address> adminAddresses = getMemberAddresses(admins);
|
||||||
|
|
||||||
String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
String masterPublicKeyOrNull = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||||
String ourNumber = masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : TextSecurePreferences.getLocalNumber(context);
|
String masterPublicKey = masterPublicKeyOrNull != null ? masterPublicKeyOrNull : TextSecurePreferences.getLocalNumber(context);
|
||||||
|
|
||||||
memberAddresses.add(Address.fromSerialized(ourNumber));
|
memberAddresses.add(Address.fromSerialized(masterPublicKey));
|
||||||
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null, new LinkedList<>(adminAddresses));
|
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null, new LinkedList<>(adminAddresses));
|
||||||
|
|
||||||
if (!mms) {
|
if (!mms) {
|
||||||
@ -94,22 +94,22 @@ public class GroupManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull GroupActionResult createPublicChatGroup(@NonNull String id,
|
public static @NonNull GroupActionResult createOpenGroup(@NonNull String id,
|
||||||
@NonNull Context context,
|
@NonNull Context context,
|
||||||
@Nullable Bitmap avatar,
|
@Nullable Bitmap avatar,
|
||||||
@Nullable String name)
|
@Nullable String name)
|
||||||
{
|
{
|
||||||
final String groupId = GroupUtil.getEncodedPublicChatId(id.getBytes());
|
final String groupID = GroupUtil.getEncodedOpenGroupId(id.getBytes());
|
||||||
return createLokiGroup(groupId, context, avatar, name);
|
return createLokiGroup(groupID, context, avatar, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull GroupActionResult createRSSFeedGroup(@NonNull String id,
|
public static @NonNull GroupActionResult createRSSFeed(@NonNull String id,
|
||||||
@NonNull Context context,
|
@NonNull Context context,
|
||||||
@Nullable Bitmap avatar,
|
@Nullable Bitmap avatar,
|
||||||
@Nullable String name)
|
@Nullable String name)
|
||||||
{
|
{
|
||||||
final String groupId = GroupUtil.getEncodedRSSFeedId(id.getBytes());
|
final String groupID = GroupUtil.getEncodedRSSFeedId(id.getBytes());
|
||||||
return createLokiGroup(groupId, context, avatar, name);
|
return createLokiGroup(groupID, context, avatar, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @NonNull GroupActionResult createLokiGroup(@NonNull String groupId,
|
private static @NonNull GroupActionResult createLokiGroup(@NonNull String groupId,
|
||||||
@ -127,8 +127,8 @@ public class GroupManager {
|
|||||||
|
|
||||||
groupDatabase.updateAvatar(groupId, avatarBytes);
|
groupDatabase.updateAvatar(groupId, avatarBytes);
|
||||||
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||||
return new GroupActionResult(groupRecipient, threadId);
|
return new GroupActionResult(groupRecipient, threadID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GroupActionResult updateGroup(@NonNull Context context,
|
public static GroupActionResult updateGroup(@NonNull Context context,
|
||||||
|
@ -8,7 +8,6 @@ import android.support.annotation.Nullable;
|
|||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
@ -18,26 +17,23 @@ import org.thoughtcrime.securesms.database.SmsDatabase;
|
|||||||
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
||||||
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
|
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
|
||||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
|
||||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -45,8 +41,6 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import kotlin.Unit;
|
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer;
|
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer;
|
||||||
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||||
@ -95,7 +89,7 @@ public class GroupMessageProcessor {
|
|||||||
builder.setType(GroupContext.Type.UPDATE);
|
builder.setType(GroupContext.Type.UPDATE);
|
||||||
|
|
||||||
SignalServiceAttachment avatar = group.getAvatar().orNull();
|
SignalServiceAttachment avatar = group.getAvatar().orNull();
|
||||||
List<Address> members = group.getMembers().isPresent() ? new LinkedList<Address>() : null;
|
List<Address> members = group.getMembers().isPresent() ? new LinkedList<>() : null;
|
||||||
List<Address> admins = group.getAdmins().isPresent() ? new LinkedList<>() : null;
|
List<Address> admins = group.getAdmins().isPresent() ? new LinkedList<>() : null;
|
||||||
|
|
||||||
if (group.getMembers().isPresent()) {
|
if (group.getMembers().isPresent()) {
|
||||||
@ -104,13 +98,12 @@ public class GroupMessageProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should only create the group if we are part of the member list
|
// Loki - Ignore message if needed
|
||||||
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, TextSecurePreferences.getLocalNumber(context));
|
if (ClosedGroupsProtocol.shouldIgnoreGroupCreatedMessage(context, group)) {
|
||||||
if (members == null || !members.contains(Address.fromSerialized(hexEncodedPublicKey))) {
|
|
||||||
Log.d("Loki - Group Message", "Received a group create message which doesn't include us in the member list. Ignoring.");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loki - Parse admins
|
||||||
if (group.getAdmins().isPresent()) {
|
if (group.getAdmins().isPresent()) {
|
||||||
for (String admin : group.getAdmins().get()) {
|
for (String admin : group.getAdmins().get()) {
|
||||||
admins.add(Address.fromExternal(context, admin));
|
admins.add(Address.fromExternal(context, admin));
|
||||||
@ -121,7 +114,7 @@ public class GroupMessageProcessor {
|
|||||||
avatar != null && avatar.isPointer() ? avatar.asPointer() : null, null, admins);
|
avatar != null && avatar.isPointer() ? avatar.asPointer() : null, null, admins);
|
||||||
|
|
||||||
if (group.getMembers().isPresent()) {
|
if (group.getMembers().isPresent()) {
|
||||||
establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
|
ClosedGroupsProtocol.establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
return storeMessage(context, content, group, builder.build(), outgoing);
|
return storeMessage(context, content, group, builder.build(), outgoing);
|
||||||
@ -137,21 +130,21 @@ public class GroupMessageProcessor {
|
|||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
String id = GroupUtil.getEncodedId(group);
|
String id = GroupUtil.getEncodedId(group);
|
||||||
|
|
||||||
String ourHexEncodedPublicKey = getMasterHexEncodedPublicKey(context, TextSecurePreferences.getLocalNumber(context));
|
String userMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||||
|
|
||||||
if (group.getGroupType() == SignalServiceGroup.GroupType.SIGNAL) {
|
if (group.getGroupType() == SignalServiceGroup.GroupType.SIGNAL) {
|
||||||
// Only update group if the group admin sent the message
|
// Loki - Only update the group if the group admin sent the message
|
||||||
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender());
|
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
|
||||||
if (!groupRecord.getAdmins().contains(Address.fromSerialized(hexEncodedPublicKey))) {
|
if (!groupRecord.getAdmins().contains(Address.fromSerialized(masterDevice))) {
|
||||||
Log.d("Loki - Group Message", "Received a group update message from a non-admin user for " + id +". Ignoring.");
|
Log.d("Loki", "Received a group update message from a non-admin user for: " + id +"; ignoring.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should only process update messages if we're in the group
|
// Loki - Only process update messages if we're part of the group
|
||||||
Address ourAddress = Address.fromSerialized(ourHexEncodedPublicKey);
|
Address userMasterDeviceAddress = Address.fromSerialized(userMasterDevice);
|
||||||
if (!groupRecord.getMembers().contains(ourAddress) &&
|
if (!groupRecord.getMembers().contains(userMasterDeviceAddress) &&
|
||||||
!group.getMembers().or(Collections.emptyList()).contains(ourHexEncodedPublicKey)) {
|
!group.getMembers().or(Collections.emptyList()).contains(userMasterDevice)) {
|
||||||
Log.d("Loki - Group Message", "Received a group update message from a group we are not a member of: " + id + "; ignoring.");
|
Log.d("Loki", "Received a group update message from a group we're not a member of: " + id + "; ignoring.");
|
||||||
database.setActive(id, false);
|
database.setActive(id, false);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -180,8 +173,8 @@ public class GroupMessageProcessor {
|
|||||||
database.updateMembers(id, new LinkedList<>(newMembers));
|
database.updateMembers(id, new LinkedList<>(newMembers));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We add any new or removed members to the group context
|
// Add any new or removed members to the group context.
|
||||||
// This will allow us later to iterate over them to check if they left or were added for UI purposes
|
// This will allow us later to iterate over them to check if they left or were added for UI purposes.
|
||||||
for (Address addedMember : addedMembers) {
|
for (Address addedMember : addedMembers) {
|
||||||
builder.addNewMembers(addedMember.serialize());
|
builder.addNewMembers(addedMember.serialize());
|
||||||
}
|
}
|
||||||
@ -200,13 +193,13 @@ public class GroupMessageProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we were removed then we need to disable the chat
|
// If we were removed then we need to disable the chat
|
||||||
if (removedMembers.contains(Address.fromSerialized(ourHexEncodedPublicKey))) {
|
if (removedMembers.contains(Address.fromSerialized(userMasterDevice))) {
|
||||||
database.setActive(id, false);
|
database.setActive(id, false);
|
||||||
} else {
|
} else {
|
||||||
if (!groupRecord.isActive()) database.setActive(id, true);
|
if (!groupRecord.isActive()) database.setActive(id, true);
|
||||||
|
|
||||||
if (group.getMembers().isPresent()) {
|
if (group.getMembers().isPresent()) {
|
||||||
establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
|
ClosedGroupsProtocol.establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,8 +211,8 @@ public class GroupMessageProcessor {
|
|||||||
@NonNull SignalServiceGroup group,
|
@NonNull SignalServiceGroup group,
|
||||||
@NonNull GroupRecord record)
|
@NonNull GroupRecord record)
|
||||||
{
|
{
|
||||||
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender());
|
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
|
||||||
if (record.getMembers().contains(Address.fromSerialized(hexEncodedPublicKey))) {
|
if (record.getMembers().contains(Address.fromSerialized(masterDevice))) {
|
||||||
ApplicationContext.getInstance(context)
|
ApplicationContext.getInstance(context)
|
||||||
.getJobManager()
|
.getJobManager()
|
||||||
.add(new PushGroupUpdateJob(content.getSender(), group.getGroupId()));
|
.add(new PushGroupUpdateJob(content.getSender(), group.getGroupId()));
|
||||||
@ -240,9 +233,9 @@ public class GroupMessageProcessor {
|
|||||||
GroupContext.Builder builder = createGroupContext(group);
|
GroupContext.Builder builder = createGroupContext(group);
|
||||||
builder.setType(GroupContext.Type.QUIT);
|
builder.setType(GroupContext.Type.QUIT);
|
||||||
|
|
||||||
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender());
|
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
|
||||||
if (members.contains(Address.fromExternal(context, hexEncodedPublicKey))) {
|
if (members.contains(Address.fromExternal(context, masterDevice))) {
|
||||||
database.remove(id, Address.fromExternal(context, hexEncodedPublicKey));
|
database.remove(id, Address.fromExternal(context, masterDevice));
|
||||||
if (outgoing) database.setActive(id, false);
|
if (outgoing) database.setActive(id, false);
|
||||||
|
|
||||||
return storeMessage(context, content, group, builder.build(), outgoing);
|
return storeMessage(context, content, group, builder.build(), outgoing);
|
||||||
@ -322,32 +315,4 @@ public class GroupMessageProcessor {
|
|||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getMasterHexEncodedPublicKey(Context context, String hexEncodedPublicKey) {
|
|
||||||
String ourPublicKey = TextSecurePreferences.getLocalNumber(context);
|
|
||||||
try {
|
|
||||||
String masterHexEncodedPublicKey = hexEncodedPublicKey.equalsIgnoreCase(ourPublicKey)
|
|
||||||
? TextSecurePreferences.getMasterHexEncodedPublicKey(context)
|
|
||||||
: PromiseUtil.timeout(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(hexEncodedPublicKey), 5000).get();
|
|
||||||
return masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : hexEncodedPublicKey;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return hexEncodedPublicKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void establishSessionsWithMembersIfNeeded(Context context, List<String> members) {
|
|
||||||
String ourNumber = TextSecurePreferences.getLocalNumber(context);
|
|
||||||
for (String member : members) {
|
|
||||||
// Make sure we have session with all of the members secondary devices
|
|
||||||
LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(member).success(devices -> {
|
|
||||||
if (devices.contains(ourNumber)) { return Unit.INSTANCE; }
|
|
||||||
for (String device : devices) {
|
|
||||||
SignalProtocolAddress protocolAddress = new SignalProtocolAddress(device, SignalServiceAddress.DEFAULT_DEVICE_ID);
|
|
||||||
boolean haveSession = new TextSecureSessionStore(context).containsSession(protocolAddress);
|
|
||||||
if (!haveSession) { MessageSender.sendBackgroundSessionRequest(context, device); }
|
|
||||||
}
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -196,10 +196,13 @@ public class AttachmentDownloadJob extends BaseJob implements InjectableType {
|
|||||||
try {
|
try {
|
||||||
long id = Long.parseLong(attachment.getLocation());
|
long id = Long.parseLong(attachment.getLocation());
|
||||||
if (isPublicAttachment) {
|
if (isPublicAttachment) {
|
||||||
return new SignalServiceAttachmentPointer(id, null, new byte[0],
|
return new SignalServiceAttachmentPointer(id,
|
||||||
|
null,
|
||||||
|
new byte[0],
|
||||||
Optional.of(Util.toIntExact(attachment.getSize())),
|
Optional.of(Util.toIntExact(attachment.getSize())),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
0, 0,
|
0,
|
||||||
|
0,
|
||||||
Optional.fromNullable(attachment.getDigest()),
|
Optional.fromNullable(attachment.getDigest()),
|
||||||
Optional.fromNullable(attachment.getFileName()),
|
Optional.fromNullable(attachment.getFileName()),
|
||||||
attachment.isVoiceNote(),
|
attachment.isVoiceNote(),
|
||||||
|
@ -40,7 +40,7 @@ public class CleanPreKeysJob extends BaseJob implements InjectableType {
|
|||||||
public CleanPreKeysJob() {
|
public CleanPreKeysJob() {
|
||||||
this(new Job.Parameters.Builder()
|
this(new Job.Parameters.Builder()
|
||||||
.setQueue("CleanPreKeysJob")
|
.setQueue("CleanPreKeysJob")
|
||||||
.setMaxAttempts(5)
|
.setMaxAttempts(3)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,9 +13,8 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraintObserver;
|
|||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver;
|
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver;
|
||||||
import org.thoughtcrime.securesms.loki.MultiDeviceOpenGroupUpdateJob;
|
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceOpenGroupUpdateJob;
|
||||||
import org.thoughtcrime.securesms.loki.PushBackgroundMessageSendJob;
|
import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob;
|
||||||
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -71,8 +70,7 @@ public final class JobManagerFactories {
|
|||||||
put(TrimThreadJob.KEY, new TrimThreadJob.Factory());
|
put(TrimThreadJob.KEY, new TrimThreadJob.Factory());
|
||||||
put(TypingSendJob.KEY, new TypingSendJob.Factory());
|
put(TypingSendJob.KEY, new TypingSendJob.Factory());
|
||||||
put(UpdateApkJob.KEY, new UpdateApkJob.Factory());
|
put(UpdateApkJob.KEY, new UpdateApkJob.Factory());
|
||||||
put(PushMessageSyncSendJob.KEY, new PushMessageSyncSendJob.Factory());
|
put(PushEphemeralMessageSendJob.KEY, new PushEphemeralMessageSendJob.Factory());
|
||||||
put(PushBackgroundMessageSendJob.KEY, new PushBackgroundMessageSendJob.Factory());
|
|
||||||
put(MultiDeviceOpenGroupUpdateJob.KEY, new MultiDeviceOpenGroupUpdateJob.Factory());
|
put(MultiDeviceOpenGroupUpdateJob.KEY, new MultiDeviceOpenGroupUpdateJob.Factory());
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,6 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
import com.android.mms.dom.smil.parser.SmilXmlSerializer;
|
import com.android.mms.dom.smil.parser.SmilXmlSerializer;
|
||||||
@ -30,6 +25,10 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
|
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
|
||||||
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
@ -64,7 +63,7 @@ public class MmsSendJob extends SendJob {
|
|||||||
this(new Job.Parameters.Builder()
|
this(new Job.Parameters.Builder()
|
||||||
.setQueue("mms-operation")
|
.setQueue("mms-operation")
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setMaxAttempts(15)
|
.setMaxAttempts(25)
|
||||||
.build(),
|
.build(),
|
||||||
messageId);
|
messageId);
|
||||||
}
|
}
|
||||||
|
@ -84,8 +84,7 @@ public class MultiDeviceBlockedUpdateJob extends BaseJob implements InjectableTy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Message ID
|
messageSender.sendMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(blockedIndividuals, blockedGroups)),
|
||||||
messageSender.sendMessage(0, SignalServiceSyncMessage.forBlocked(new BlockedListMessage(blockedIndividuals, blockedGroups)),
|
|
||||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,8 +91,7 @@ public class MultiDeviceConfigurationUpdateJob extends BaseJob implements Inject
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Message ID
|
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(readReceiptsEnabled),
|
||||||
messageSender.sendMessage(0, SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(readReceiptsEnabled),
|
|
||||||
Optional.of(unidentifiedDeliveryIndicatorsEnabled),
|
Optional.of(unidentifiedDeliveryIndicatorsEnabled),
|
||||||
Optional.of(typingIndicatorsEnabled),
|
Optional.of(typingIndicatorsEnabled),
|
||||||
Optional.of(linkPreviewsEnabled))),
|
Optional.of(linkPreviewsEnabled))),
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
package org.thoughtcrime.securesms.jobs;
|
package org.thoughtcrime.securesms.jobs;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.AssetFileDescriptor;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
|
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
|
||||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.Database;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
@ -23,13 +18,12 @@ import org.thoughtcrime.securesms.jobmanager.Data;
|
|||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
import org.thoughtcrime.securesms.loki.protocol.SyncMessagesProtocol;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
|
||||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||||
@ -39,18 +33,13 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContact;
|
|||||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsOutputStream;
|
import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsOutputStream;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus;
|
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@ -65,57 +54,47 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
private static final long FULL_SYNC_TIME = TimeUnit.HOURS.toMillis(6);
|
private static final long FULL_SYNC_TIME = TimeUnit.HOURS.toMillis(6);
|
||||||
|
|
||||||
private static final String KEY_ADDRESS = "address";
|
private static final String KEY_ADDRESS = "address";
|
||||||
private static final String KEY_RECIPIENT = "recipient";
|
|
||||||
private static final String KEY_FORCE_SYNC = "force_sync";
|
private static final String KEY_FORCE_SYNC = "force_sync";
|
||||||
|
|
||||||
@Inject SignalServiceMessageSender messageSender;
|
@Inject SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
private @Nullable String address;
|
private @Nullable String address;
|
||||||
|
|
||||||
// The recipient of this sync message. If null then we send to all devices
|
|
||||||
private @Nullable String recipient;
|
|
||||||
|
|
||||||
private boolean forceSync;
|
private boolean forceSync;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a full contact sync job which syncs across to all other devices
|
* Create a full contact sync job that syncs to all linked devices.
|
||||||
*/
|
*/
|
||||||
public MultiDeviceContactUpdateJob(@NonNull Context context) {
|
public MultiDeviceContactUpdateJob(@NonNull Context context) {
|
||||||
this(context, false);
|
this(context, false);
|
||||||
}
|
}
|
||||||
public MultiDeviceContactUpdateJob(@NonNull Context context, boolean forceSync) { this(context, null, forceSync); }
|
|
||||||
|
|
||||||
/**
|
public MultiDeviceContactUpdateJob(@NonNull Context context, boolean forceSync) {
|
||||||
* Create a full contact sync job which only gets sent to `recipient`
|
this(context, null, forceSync);
|
||||||
*/
|
|
||||||
public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address recipient, boolean forceSync) {
|
|
||||||
this(context, recipient, null, forceSync);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a single contact sync job which syncs across `address` to the all other devices
|
* Create a single contact sync job that syncs `address` to all linked devices.
|
||||||
*/
|
*/
|
||||||
public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address address) {
|
public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address address) {
|
||||||
this(context, null, address, true);
|
this(context, address, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address recipient, @Nullable Address address, boolean forceSync) {
|
public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address address, boolean forceSync) {
|
||||||
this(new Job.Parameters.Builder()
|
this(new Job.Parameters.Builder()
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setQueue("MultiDeviceContactUpdateJob")
|
.setQueue("MultiDeviceContactUpdateJob")
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
.setMaxAttempts(1)
|
.setMaxAttempts(1)
|
||||||
.build(),
|
.build(),
|
||||||
recipient,
|
|
||||||
address,
|
address,
|
||||||
forceSync);
|
forceSync);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultiDeviceContactUpdateJob(@NonNull Job.Parameters parameters, @Nullable Address recipient, @Nullable Address address, boolean forceSync) {
|
private MultiDeviceContactUpdateJob(@NonNull Job.Parameters parameters, @Nullable Address address, boolean forceSync) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
|
|
||||||
this.forceSync = forceSync;
|
this.forceSync = forceSync;
|
||||||
this.recipient = (recipient != null) ? recipient.serialize() : null;
|
|
||||||
|
|
||||||
if (address != null) this.address = address.serialize();
|
if (address != null) this.address = address.serialize();
|
||||||
else this.address = null;
|
else this.address = null;
|
||||||
@ -125,7 +104,6 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
public @NonNull Data serialize() {
|
public @NonNull Data serialize() {
|
||||||
return new Data.Builder().putString(KEY_ADDRESS, address)
|
return new Data.Builder().putString(KEY_ADDRESS, address)
|
||||||
.putBoolean(KEY_FORCE_SYNC, forceSync)
|
.putBoolean(KEY_FORCE_SYNC, forceSync)
|
||||||
.putString(KEY_RECIPIENT, recipient)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,14 +122,14 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (address == null) generateFullContactUpdate();
|
if (address == null) generateFullContactUpdate();
|
||||||
else if (!address.equals(TextSecurePreferences.getMasterHexEncodedPublicKey(context))) generateSingleContactUpdate(Address.fromSerialized(address));
|
else if (SyncMessagesProtocol.shouldSyncContact(context, Address.fromSerialized(address))) generateSingleContactUpdate(Address.fromSerialized(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateSingleContactUpdate(@NonNull Address address)
|
private void generateSingleContactUpdate(@NonNull Address address)
|
||||||
throws IOException, UntrustedIdentityException, NetworkException
|
throws IOException, UntrustedIdentityException, NetworkException
|
||||||
{
|
{
|
||||||
// Loki - Only sync regular contacts
|
// Loki - Only sync regular contacts
|
||||||
if (!address.isPhone()) { return; }
|
if (!PublicKeyValidation.isValid(address.serialize())) { return; }
|
||||||
|
|
||||||
File contactDataFile = createTempFile("multidevice-contact-update");
|
File contactDataFile = createTempFile("multidevice-contact-update");
|
||||||
|
|
||||||
@ -162,7 +140,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
Optional<VerifiedMessage> verifiedMessage = getVerifiedMessage(recipient, identityRecord);
|
Optional<VerifiedMessage> verifiedMessage = getVerifiedMessage(recipient, identityRecord);
|
||||||
|
|
||||||
// Loki - Only sync contacts we are friends with
|
// Loki - Only sync contacts we are friends with
|
||||||
if (getFriendRequestStatus(recipient) == LokiThreadFriendRequestStatus.FRIENDS) {
|
if (SyncMessagesProtocol.shouldSyncContact(context, address)) {
|
||||||
out.write(new DeviceContact(address.toPhoneString(),
|
out.write(new DeviceContact(address.toPhoneString(),
|
||||||
Optional.fromNullable(recipient.getName()),
|
Optional.fromNullable(recipient.getName()),
|
||||||
getAvatar(recipient.getContactUri()),
|
getAvatar(recipient.getContactUri()),
|
||||||
@ -170,9 +148,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
verifiedMessage,
|
verifiedMessage,
|
||||||
Optional.fromNullable(recipient.getProfileKey()),
|
Optional.fromNullable(recipient.getProfileKey()),
|
||||||
recipient.isBlocked(),
|
recipient.isBlocked(),
|
||||||
recipient.getExpireMessages() > 0 ?
|
recipient.getExpireMessages() > 0 ? Optional.of(recipient.getExpireMessages()) : Optional.absent()));
|
||||||
Optional.of(recipient.getExpireMessages()) :
|
|
||||||
Optional.absent()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.close();
|
out.close();
|
||||||
@ -206,7 +182,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile));
|
DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile));
|
||||||
List<ContactData> contacts = getAllContacts();
|
List<ContactData> contacts = SyncMessagesProtocol.getContactsToSync(context);
|
||||||
|
|
||||||
for (ContactData contactData : contacts) {
|
for (ContactData contactData : contacts) {
|
||||||
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactData.id));
|
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactData.id));
|
||||||
@ -220,11 +196,8 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
boolean blocked = recipient.isBlocked();
|
boolean blocked = recipient.isBlocked();
|
||||||
Optional<Integer> expireTimer = recipient.getExpireMessages() > 0 ? Optional.of(recipient.getExpireMessages()) : Optional.absent();
|
Optional<Integer> expireTimer = recipient.getExpireMessages() > 0 ? Optional.of(recipient.getExpireMessages()) : Optional.absent();
|
||||||
|
|
||||||
// Loki - Only sync contacts we are friends with
|
|
||||||
if (getFriendRequestStatus(recipient) == LokiThreadFriendRequestStatus.FRIENDS) {
|
|
||||||
out.write(new DeviceContact(address.toPhoneString(), name, getAvatar(contactUri), color, verified, profileKey, blocked, expireTimer));
|
out.write(new DeviceContact(address.toPhoneString(), name, getAvatar(contactUri), color, verified, profileKey, blocked, expireTimer));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ProfileKeyUtil.hasProfileKey(context)) {
|
if (ProfileKeyUtil.hasProfileKey(context)) {
|
||||||
Recipient self = Recipient.from(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), false);
|
Recipient self = Recipient.from(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), false);
|
||||||
@ -244,29 +217,9 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ContactData> getAllContacts() {
|
|
||||||
List<Address> contactAddresses = new ArrayList<>(DatabaseFactory.getRecipientDatabase(context).getAllAddresses());
|
|
||||||
List<ContactData> contacts = new ArrayList<>(contactAddresses.size());
|
|
||||||
for (Address address : contactAddresses) {
|
|
||||||
if (!address.isPhone()) { continue; }
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, address, false));
|
|
||||||
String name = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(address.serialize());
|
|
||||||
ContactData contactData = new ContactData(threadId, name);
|
|
||||||
contactData.numbers.add(new ContactAccessor.NumberData("TextSecure", address.serialize()));
|
|
||||||
contacts.add(contactData);
|
|
||||||
}
|
|
||||||
return contacts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LokiThreadFriendRequestStatus getFriendRequestStatus(Recipient recipient) {
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient);
|
|
||||||
return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onShouldRetry(@NonNull Exception exception) {
|
public boolean onShouldRetry(@NonNull Exception exception) {
|
||||||
// Loki - Disabled because we have our own retrying
|
// Loki - Disabled since we have our own retrying
|
||||||
// if (exception instanceof PushNetworkException) return true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,13 +239,10 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
.withLength(contactsFile.length())
|
.withLength(contactsFile.length())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
SignalServiceAddress messageRecipient = recipient != null ? new SignalServiceAddress(recipient) : null;
|
Optional<UnidentifiedAccessPair> unidentifiedAccess = address != null ? UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(address), false)) : Optional.absent();
|
||||||
Address address = recipient != null ? Address.fromSerialized(recipient) : null;
|
|
||||||
|
|
||||||
Optional<UnidentifiedAccessPair> unidentifiedAccess = address != null ? UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, address, false)) : Optional.absent();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
messageSender.sendMessage(0, SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, complete)), unidentifiedAccess, Optional.fromNullable(messageRecipient));
|
messageSender.sendMessage(SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, complete)), unidentifiedAccess);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new NetworkException(ioe);
|
throw new NetworkException(ioe);
|
||||||
}
|
}
|
||||||
@ -302,7 +252,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
private Optional<SignalServiceAttachmentStream> getAvatar(@Nullable Uri uri) throws IOException {
|
private Optional<SignalServiceAttachmentStream> getAvatar(@Nullable Uri uri) throws IOException {
|
||||||
return Optional.absent();
|
return Optional.absent();
|
||||||
|
|
||||||
/* Loki - Disabled until we support custom avatars. This will need to be reworked
|
/* Loki - Disabled until we support custom profile pictures. This will then need to be reworked.
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
return Optional.absent();
|
return Optional.absent();
|
||||||
}
|
}
|
||||||
@ -397,10 +347,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
String serialized = data.getString(KEY_ADDRESS);
|
String serialized = data.getString(KEY_ADDRESS);
|
||||||
Address address = serialized != null ? Address.fromSerialized(serialized) : null;
|
Address address = serialized != null ? Address.fromSerialized(serialized) : null;
|
||||||
|
|
||||||
String recipientSerialized = data.getString(KEY_RECIPIENT);
|
return new MultiDeviceContactUpdateJob(parameters, address, data.getBoolean(KEY_FORCE_SYNC));
|
||||||
Address recipient = recipientSerialized != null ? Address.fromSerialized(recipientSerialized) : null;
|
|
||||||
|
|
||||||
return new MultiDeviceContactUpdateJob(parameters, recipient, address, data.getBoolean(KEY_FORCE_SYNC));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStre
|
|||||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
|
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
|
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -85,7 +84,7 @@ public class MultiDeviceGroupUpdateJob extends BaseJob implements InjectableType
|
|||||||
reader = DatabaseFactory.getGroupDatabase(context).getGroups();
|
reader = DatabaseFactory.getGroupDatabase(context).getGroups();
|
||||||
|
|
||||||
while ((record = reader.getNext()) != null) {
|
while ((record = reader.getNext()) != null) {
|
||||||
if (record.isSignalGroup()) {
|
if (record.isClosedGroup()) {
|
||||||
List<String> members = new LinkedList<>();
|
List<String> members = new LinkedList<>();
|
||||||
List<String> admins = new LinkedList<>();
|
List<String> admins = new LinkedList<>();
|
||||||
|
|
||||||
@ -125,8 +124,7 @@ public class MultiDeviceGroupUpdateJob extends BaseJob implements InjectableType
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onShouldRetry(@NonNull Exception exception) {
|
public boolean onShouldRetry(@NonNull Exception exception) {
|
||||||
// Loki - Disabled because we have our own retrying
|
// Loki - Disabled since we have our own retrying
|
||||||
// if (exception instanceof PushNetworkException) return true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +143,7 @@ public class MultiDeviceGroupUpdateJob extends BaseJob implements InjectableType
|
|||||||
.withLength(contactsFile.length())
|
.withLength(contactsFile.length())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
messageSender.sendMessage(0, SignalServiceSyncMessage.forGroups(attachmentStream),
|
messageSender.sendMessage(SignalServiceSyncMessage.forGroups(attachmentStream),
|
||||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +89,7 @@ public class MultiDeviceProfileKeyUpdateJob extends BaseJob implements Injectabl
|
|||||||
|
|
||||||
SignalServiceSyncMessage syncMessage = SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, false));
|
SignalServiceSyncMessage syncMessage = SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, false));
|
||||||
|
|
||||||
// TODO: Message ID
|
messageSender.sendMessage(syncMessage, UnidentifiedAccessUtil.getAccessForSync(context));
|
||||||
messageSender.sendMessage(0, syncMessage, UnidentifiedAccessUtil.getAccessForSync(context));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -94,8 +94,7 @@ public class MultiDeviceReadUpdateJob extends BaseJob implements InjectableType
|
|||||||
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
|
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Message ID
|
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages), UnidentifiedAccessUtil.getAccessForSync(context));
|
||||||
messageSender.sendMessage(0, SignalServiceSyncMessage.forRead(readMessages), UnidentifiedAccessUtil.getAccessForSync(context));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2,20 +2,14 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.util.Hex;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
|
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -76,6 +70,7 @@ public class MultiDeviceStickerPackOperationJob extends BaseJob implements Injec
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRun() throws Exception {
|
protected void onRun() throws Exception {
|
||||||
|
/*
|
||||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||||
Log.i(TAG, "Not multi device, aborting...");
|
Log.i(TAG, "Not multi device, aborting...");
|
||||||
return;
|
return;
|
||||||
@ -94,8 +89,9 @@ public class MultiDeviceStickerPackOperationJob extends BaseJob implements Injec
|
|||||||
|
|
||||||
StickerPackOperationMessage stickerPackOperation = new StickerPackOperationMessage(packIdBytes, packKeyBytes, remoteType);
|
StickerPackOperationMessage stickerPackOperation = new StickerPackOperationMessage(packIdBytes, packKeyBytes, remoteType);
|
||||||
|
|
||||||
messageSender.sendMessage(0, SignalServiceSyncMessage.forStickerPackOperations(Collections.singletonList(stickerPackOperation)), // The message ID doesn't matter
|
messageSender.sendMessage(SignalServiceSyncMessage.forStickerPackOperations(Collections.singletonList(stickerPackOperation)),
|
||||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2,24 +2,14 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|
||||||
import org.thoughtcrime.securesms.database.StickerDatabase.StickerPackRecordReader;
|
|
||||||
import org.thoughtcrime.securesms.database.model.StickerPackRecord;
|
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.util.Hex;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
|
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -59,6 +49,8 @@ public class MultiDeviceStickerPackSyncJob extends BaseJob implements Injectable
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRun() throws Exception {
|
protected void onRun() throws Exception {
|
||||||
|
return;
|
||||||
|
/*
|
||||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||||
Log.i(TAG, "Not multi device, aborting...");
|
Log.i(TAG, "Not multi device, aborting...");
|
||||||
return;
|
return;
|
||||||
@ -76,8 +68,9 @@ public class MultiDeviceStickerPackSyncJob extends BaseJob implements Injectable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
messageSender.sendMessage(0, SignalServiceSyncMessage.forStickerPackOperations(operations), // The message ID doesn't matter
|
messageSender.sendMessage(SignalServiceSyncMessage.forStickerPackOperations(operations),
|
||||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -3,23 +3,16 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
import org.whispersystems.libsignal.InvalidKeyException;
|
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
|
|
||||||
@ -89,6 +82,7 @@ public class MultiDeviceVerifiedUpdateJob extends BaseJob implements InjectableT
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRun() throws IOException, UntrustedIdentityException {
|
public void onRun() throws IOException, UntrustedIdentityException {
|
||||||
|
/*
|
||||||
try {
|
try {
|
||||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||||
Log.i(TAG, "Not multi device...");
|
Log.i(TAG, "Not multi device...");
|
||||||
@ -104,12 +98,12 @@ public class MultiDeviceVerifiedUpdateJob extends BaseJob implements InjectableT
|
|||||||
VerifiedMessage.VerifiedState verifiedState = getVerifiedState(verifiedStatus);
|
VerifiedMessage.VerifiedState verifiedState = getVerifiedState(verifiedStatus);
|
||||||
VerifiedMessage verifiedMessage = new VerifiedMessage(canonicalDestination.toPhoneString(), new IdentityKey(identityKey, 0), verifiedState, timestamp);
|
VerifiedMessage verifiedMessage = new VerifiedMessage(canonicalDestination.toPhoneString(), new IdentityKey(identityKey, 0), verifiedState, timestamp);
|
||||||
|
|
||||||
// TODO: Message ID
|
messageSender.sendMessage(SignalServiceSyncMessage.forVerified(verifiedMessage),
|
||||||
messageSender.sendMessage(0, SignalServiceSyncMessage.forVerified(verifiedMessage),
|
|
||||||
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(destination), false)));
|
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(destination), false)));
|
||||||
} catch (InvalidKeyException e) {
|
} catch (InvalidKeyException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private VerifiedMessage.VerifiedState getVerifiedState(VerifiedStatus status) {
|
private VerifiedMessage.VerifiedState getVerifiedState(VerifiedStatus status) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -12,31 +12,26 @@ import org.thoughtcrime.securesms.ApplicationContext;
|
|||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo;
|
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
|
||||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||||
@ -50,14 +45,10 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
|||||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
|
||||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
|
||||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -159,36 +150,13 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
try {
|
try {
|
||||||
log(TAG, "Sending message: " + messageId);
|
log(TAG, "Sending message: " + messageId);
|
||||||
|
|
||||||
List<Address> target;
|
List<Address> targets;
|
||||||
|
|
||||||
if (filterAddress != null) target = Collections.singletonList(Address.fromSerialized(filterAddress));
|
if (filterAddress != null) targets = Collections.singletonList(Address.fromSerialized(filterAddress));
|
||||||
else if (!existingNetworkFailures.isEmpty()) target = Stream.of(existingNetworkFailures).map(NetworkFailure::getAddress).toList();
|
else if (!existingNetworkFailures.isEmpty()) targets = Stream.of(existingNetworkFailures).map(NetworkFailure::getAddress).toList();
|
||||||
else target = getGroupMessageRecipients(message.getRecipient().getAddress().toGroupString(), messageId);
|
else targets = ClosedGroupsProtocol.getDestinations(message.getRecipient().getAddress().toGroupString(), context).get();
|
||||||
|
|
||||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
List<SendMessageResult> results = deliver(message, targets);
|
||||||
|
|
||||||
// Only send messages to the contacts we have sessions with
|
|
||||||
List<Address> validTargets = Stream.of(target).filter(member -> {
|
|
||||||
if (member.isPublicChat()) { return true; }
|
|
||||||
|
|
||||||
// Our device is always valid
|
|
||||||
if (member.serialize().equalsIgnoreCase(localNumber)) { return true; }
|
|
||||||
|
|
||||||
SignalProtocolAddress protocolAddress = new SignalProtocolAddress(member.toPhoneString(), SignalServiceAddress.DEFAULT_DEVICE_ID);
|
|
||||||
boolean hasSession = new TextSecureSessionStore(context).containsSession(protocolAddress);
|
|
||||||
if (hasSession) { return true; }
|
|
||||||
|
|
||||||
// We should allow sending if we have a prekeybundle for the contact
|
|
||||||
return DatabaseFactory.getLokiPreKeyBundleDatabase(context).hasPreKeyBundle(member.toPhoneString());
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
// Send a session request to the other devices
|
|
||||||
List<Address> others = Stream.of(target).filter(t -> !validTargets.contains(t)).toList();
|
|
||||||
for (Address device : others) {
|
|
||||||
MessageSender.sendBackgroundSessionRequest(context, device.toPhoneString());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<SendMessageResult> results = deliver(message, validTargets);
|
|
||||||
List<NetworkFailure> networkFailures = Stream.of(results).filter(SendMessageResult::isNetworkFailure).map(result -> new NetworkFailure(Address.fromSerialized(result.getAddress().getNumber()))).toList();
|
List<NetworkFailure> networkFailures = Stream.of(results).filter(SendMessageResult::isNetworkFailure).map(result -> new NetworkFailure(Address.fromSerialized(result.getAddress().getNumber()))).toList();
|
||||||
List<IdentityKeyMismatch> identityMismatches = Stream.of(results).filter(result -> result.getIdentityFailure() != null).map(result -> new IdentityKeyMismatch(Address.fromSerialized(result.getAddress().getNumber()), result.getIdentityFailure().getIdentityKey())).toList();
|
List<IdentityKeyMismatch> identityMismatches = Stream.of(results).filter(result -> result.getIdentityFailure() != null).map(result -> new IdentityKeyMismatch(Address.fromSerialized(result.getAddress().getNumber()), result.getIdentityFailure().getIdentityKey())).toList();
|
||||||
Set<Address> successAddresses = Stream.of(results).filter(result -> result.getSuccess() != null).map(result -> Address.fromSerialized(result.getAddress().getNumber())).collect(Collectors.toSet());
|
Set<Address> successAddresses = Stream.of(results).filter(result -> result.getSuccess() != null).map(result -> Address.fromSerialized(result.getAddress().getNumber())).collect(Collectors.toSet());
|
||||||
@ -237,7 +205,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
database.markAsSentFailed(messageId);
|
database.markAsSentFailed(messageId);
|
||||||
notifyMediaMessageDeliveryFailed(context, messageId);
|
notifyMediaMessageDeliveryFailed(context, messageId);
|
||||||
}
|
}
|
||||||
} catch (UntrustedIdentityException | UndeliverableMessageException e) {
|
} catch (Exception e) {
|
||||||
warn(TAG, e);
|
warn(TAG, e);
|
||||||
database.markAsSentFailed(messageId);
|
database.markAsSentFailed(messageId);
|
||||||
notifyMediaMessageDeliveryFailed(context, messageId);
|
notifyMediaMessageDeliveryFailed(context, messageId);
|
||||||
@ -247,9 +215,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onShouldRetry(@NonNull Exception exception) {
|
public boolean onShouldRetry(@NonNull Exception exception) {
|
||||||
if (exception instanceof IOException) return true;
|
if (exception instanceof IOException) return true;
|
||||||
|
|
||||||
// Loki - Disable since we have our own retrying
|
// Loki - Disable since we have our own retrying
|
||||||
// if (exception instanceof RetryLaterException) return true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,17 +226,18 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
|
|
||||||
private List<SendMessageResult> deliver(OutgoingMediaMessage message, @NonNull List<Address> destinations)
|
private List<SendMessageResult> deliver(OutgoingMediaMessage message, @NonNull List<Address> destinations)
|
||||||
throws IOException, UntrustedIdentityException, UndeliverableMessageException {
|
throws IOException, UntrustedIdentityException, UndeliverableMessageException {
|
||||||
// rotateSenderCertificateIfNecessary();
|
|
||||||
|
|
||||||
// Messages shouldn't be able to be sent to RSS Feeds
|
// Loki - The user shouldn't be able to message RSS feeds
|
||||||
Address groupAddress = message.getRecipient().getAddress();
|
Address address = message.getRecipient().getAddress();
|
||||||
if (groupAddress.isRSSFeed()) {
|
if (address.isRSSFeed()) {
|
||||||
List<SendMessageResult> results = new ArrayList<>();
|
List<SendMessageResult> results = new ArrayList<>();
|
||||||
for (Address destination : destinations) results.add(SendMessageResult.networkFailure(new SignalServiceAddress(destination.toPhoneString())));
|
for (Address destination : destinations) {
|
||||||
|
results.add(SendMessageResult.networkFailure(new SignalServiceAddress(destination.toPhoneString())));
|
||||||
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
String groupId = groupAddress.toGroupString();
|
String groupId = address.toGroupString();
|
||||||
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
||||||
Optional<Quote> quote = getQuoteFor(message);
|
Optional<Quote> quote = getQuoteFor(message);
|
||||||
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
|
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
|
||||||
@ -281,18 +248,15 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
List<SignalServiceAttachment> attachmentPointers = getAttachmentPointersFor(attachments);
|
List<SignalServiceAttachment> attachmentPointers = getAttachmentPointersFor(attachments);
|
||||||
|
|
||||||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(addresses)
|
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(addresses)
|
||||||
.map(address -> Address.fromSerialized(address.getNumber()))
|
.map(a -> Address.fromSerialized(a.getNumber()))
|
||||||
.map(address -> Recipient.from(context, address, false))
|
.map(a -> Recipient.from(context, a, false))
|
||||||
.map(recipient -> UnidentifiedAccessUtil.getAccessFor(context, recipient))
|
.map(recipient -> UnidentifiedAccessUtil.getAccessFor(context, recipient))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
SignalServiceGroup.GroupType groupType = SignalServiceGroup.GroupType.SIGNAL;
|
SignalServiceGroup.GroupType groupType = address.isOpenGroup() ? SignalServiceGroup.GroupType.PUBLIC_CHAT : SignalServiceGroup.GroupType.SIGNAL;
|
||||||
if (groupAddress.isPublicChat()) {
|
|
||||||
groupType = SignalServiceGroup.GroupType.PUBLIC_CHAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.isGroup() && groupAddress.isSignalGroup()) {
|
if (message.isGroup() && address.isClosedGroup()) {
|
||||||
// Loki - Only send GroupUpdate or GroupQuit to signal groups
|
// Loki - Only send GroupUpdate or GroupQuit messages to closed groups
|
||||||
OutgoingGroupMediaMessage groupMessage = (OutgoingGroupMediaMessage) message;
|
OutgoingGroupMediaMessage groupMessage = (OutgoingGroupMediaMessage) message;
|
||||||
GroupContext groupContext = groupMessage.getGroupContext();
|
GroupContext groupContext = groupMessage.getGroupContext();
|
||||||
SignalServiceAttachment avatar = attachmentPointers.isEmpty() ? null : attachmentPointers.get(0);
|
SignalServiceAttachment avatar = attachmentPointers.isEmpty() ? null : attachmentPointers.get(0);
|
||||||
@ -301,7 +265,6 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
SignalServiceDataMessage groupDataMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage groupDataMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withTimestamp(message.getSentTimeMillis())
|
.withTimestamp(message.getSentTimeMillis())
|
||||||
.withExpiration(message.getRecipient().getExpireMessages())
|
.withExpiration(message.getRecipient().getExpireMessages())
|
||||||
.withBody(message.getBody())
|
|
||||||
.asGroupMessage(group)
|
.asGroupMessage(group)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -326,65 +289,6 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull List<Address> getGroupMessageRecipients(String groupId, long messageId) {
|
|
||||||
if (GroupUtil.isRssFeed(groupId)) { return new ArrayList<>(); }
|
|
||||||
|
|
||||||
// Loki - All public chat group messages should be directed to their respective servers
|
|
||||||
if (GroupUtil.isPublicChat(groupId)) {
|
|
||||||
ArrayList<Address> result = new ArrayList<>();
|
|
||||||
long threadID = GroupManager.getThreadIdFromGroupId(groupId, context);
|
|
||||||
LokiPublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID);
|
|
||||||
if (publicChat != null) {
|
|
||||||
result.add(Address.fromSerialized(groupId));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
Our biggest assumption here is that group members will only consist of primary devices.
|
|
||||||
No secondary device should be able to be added to a group.
|
|
||||||
*/
|
|
||||||
List<GroupReceiptInfo> destinations = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageId);
|
|
||||||
|
|
||||||
Set<Address> memberSet = new HashSet<>();
|
|
||||||
if (destinations.isEmpty()) {
|
|
||||||
List<Recipient> groupMembers = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
|
|
||||||
memberSet.addAll(Stream.of(groupMembers).map(Recipient::getAddress).toList());
|
|
||||||
} else {
|
|
||||||
memberSet.addAll(Stream.of(destinations).map(GroupReceiptInfo::getAddress).toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace primary device public key with ours so message syncing works correctly
|
|
||||||
String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
|
||||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
|
||||||
if (masterHexEncodedPublicKey != null && memberSet.contains(Address.fromSerialized(masterHexEncodedPublicKey))) {
|
|
||||||
memberSet.remove(Address.fromSerialized(masterHexEncodedPublicKey));
|
|
||||||
memberSet.add(Address.fromSerialized(localNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add secondary devices to the list. We shouldn't add our secondary devices
|
|
||||||
try {
|
|
||||||
Set<Address> originalMemberSet = new HashSet<>(memberSet);
|
|
||||||
for (Address member : originalMemberSet) {
|
|
||||||
if (!member.isPhone() || member.serialize().equalsIgnoreCase(localNumber)) { continue; }
|
|
||||||
|
|
||||||
try {
|
|
||||||
Set<String> secondaryDevices = PromiseUtil.timeout(LokiDeviceLinkUtilities.INSTANCE.getSlaveHexEncodedPublicKeys(member.serialize()), 5000).get();
|
|
||||||
memberSet.addAll(Stream.of(secondaryDevices).map(string -> {
|
|
||||||
// Loki - Calling .map(Address::fromSerialized) is causing errors, thus we use the long method :(
|
|
||||||
return Address.fromSerialized(string);
|
|
||||||
}).toList());
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Timed out, go to the next member
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("PushGroupSend", "Error occurred while adding secondary devices: " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new LinkedList<>(memberSet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Factory implements Job.Factory<PushGroupSendJob> {
|
public static class Factory implements Job.Factory<PushGroupSendJob> {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull PushGroupSendJob create(@NonNull Parameters parameters, @NonNull org.thoughtcrime.securesms.jobmanager.Data data) {
|
public @NonNull PushGroupSendJob create(@NonNull Parameters parameters, @NonNull org.thoughtcrime.securesms.jobmanager.Data data) {
|
||||||
|
@ -123,7 +123,6 @@ public class PushGroupUpdateJob extends BaseJob implements InjectableType {
|
|||||||
.withExpiration(groupRecipient.getExpireMessages())
|
.withExpiration(groupRecipient.getExpireMessages())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// TODO: Message ID
|
|
||||||
messageSender.sendMessage(0, new SignalServiceAddress(source),
|
messageSender.sendMessage(0, new SignalServiceAddress(source),
|
||||||
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(source), false)),
|
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(source), false)),
|
||||||
message);
|
message);
|
||||||
|
@ -22,7 +22,7 @@ import org.thoughtcrime.securesms.jobmanager.Data;
|
|||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
@ -45,9 +45,7 @@ import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
|||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
||||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol;
|
||||||
import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage;
|
|
||||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -66,9 +64,8 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
private static final String KEY_TEMPLATE_MESSAGE_ID = "template_message_id";
|
private static final String KEY_TEMPLATE_MESSAGE_ID = "template_message_id";
|
||||||
private static final String KEY_MESSAGE_ID = "message_id";
|
private static final String KEY_MESSAGE_ID = "message_id";
|
||||||
private static final String KEY_DESTINATION = "destination";
|
private static final String KEY_DESTINATION = "destination";
|
||||||
private static final String KEY_IS_FRIEND_REQUEST = "is_friend_request";
|
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";
|
private static final String KEY_CUSTOM_FR_MESSAGE = "custom_friend_request_message";
|
||||||
private static final String KEY_SHOULD_SEND_SYNC_MESSAGE = "should_send_sync_message";
|
|
||||||
|
|
||||||
@Inject SignalServiceMessageSender messageSender;
|
@Inject SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
@ -76,33 +73,37 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
private long templateMessageId; // The message ID of the message to template this send job from
|
private long templateMessageId; // The message ID of the message to template this send job from
|
||||||
|
|
||||||
// Loki - Multi device
|
// Loki - Multi device
|
||||||
private Address destination; // Destination to check whether this is another device we're sending to
|
private Address destination; // Used to check whether this is another device we're sending to
|
||||||
private boolean isFriendRequest; // Whether this is a friend request message
|
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 String customFriendRequestMessage; // If this isn't set then we use the message body
|
||||||
private boolean shouldSendSyncMessage;
|
|
||||||
|
|
||||||
public PushMediaSendJob(long messageId, Address destination) { this(messageId, messageId, destination); }
|
public PushMediaSendJob(long messageId, Address destination) {
|
||||||
public PushMediaSendJob(long templateMessageId, long messageId, Address destination) { this(templateMessageId, messageId, destination, false, null, false); }
|
this(messageId, messageId, destination);
|
||||||
public PushMediaSendJob(long templateMessageId, long messageId, Address destination, boolean isFriendRequest, String customFriendRequestMessage, boolean shouldSendSyncMessage) {
|
|
||||||
this(constructParameters(destination), templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage, shouldSendSyncMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PushMediaSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isFriendRequest, String customFriendRequestMessage, boolean shouldSendSyncMessage) {
|
public PushMediaSendJob(long templateMessageId, long messageId, Address destination) {
|
||||||
|
this(templateMessageId, messageId, destination, false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
this.templateMessageId = templateMessageId;
|
this.templateMessageId = templateMessageId;
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
this.destination = destination;
|
this.destination = destination;
|
||||||
this.isFriendRequest = isFriendRequest;
|
this.isLokiPreKeyBundleMessage = isLokiPreKeyBundleMessage;
|
||||||
this.customFriendRequestMessage = customFriendRequestMessage;
|
this.customFriendRequestMessage = customFriendRequestMessage;
|
||||||
this.shouldSendSyncMessage = shouldSendSyncMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Address destination, boolean shouldSendSyncMessage) {
|
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Address destination) {
|
||||||
enqueue(context, jobManager, messageId, messageId, destination, false, null, shouldSendSyncMessage);
|
enqueue(context, jobManager, messageId, messageId, destination, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long templateMessageId, long messageId, @NonNull Address destination, Boolean isFriendRequest, @Nullable String customFriendRequestMessage, boolean shouldSendSyncMessage) {
|
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, shouldSendSyncMessage)));
|
enqueue(context, jobManager, Collections.singletonList(new PushMediaSendJob(templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
@ -147,8 +148,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
|
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
|
||||||
.putLong(KEY_MESSAGE_ID, messageId)
|
.putLong(KEY_MESSAGE_ID, messageId)
|
||||||
.putString(KEY_DESTINATION, destination.serialize())
|
.putString(KEY_DESTINATION, destination.serialize())
|
||||||
.putBoolean(KEY_IS_FRIEND_REQUEST, isFriendRequest)
|
.putBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE, isLokiPreKeyBundleMessage);
|
||||||
.putBoolean(KEY_SHOULD_SEND_SYNC_MESSAGE, shouldSendSyncMessage);
|
|
||||||
|
|
||||||
if (customFriendRequestMessage != null) { builder.putString(KEY_CUSTOM_FR_MESSAGE, customFriendRequestMessage); }
|
if (customFriendRequestMessage != null) { builder.putString(KEY_CUSTOM_FR_MESSAGE, customFriendRequestMessage); }
|
||||||
return builder.build();
|
return builder.build();
|
||||||
@ -233,15 +233,17 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
}
|
}
|
||||||
} catch (LokiAPI.Error e) {
|
} catch (LokiAPI.Error e) {
|
||||||
Log.d("Loki", "Couldn't send message due to error: " + e.getDescription());
|
Log.d("Loki", "Couldn't send message due to error: " + e.getDescription());
|
||||||
if (messageId < 0) { return; }
|
if (messageId >= 0) {
|
||||||
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
||||||
lokiMessageDatabase.setErrorMessage(messageId, e.getDescription());
|
lokiMessageDatabase.setErrorMessage(messageId, e.getDescription());
|
||||||
database.markAsSentFailed(messageId);
|
database.markAsSentFailed(messageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onShouldRetry(@NonNull Exception exception) {
|
public boolean onShouldRetry(@NonNull Exception exception) {
|
||||||
|
// Loki - Disable since we have our own retrying
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,9 +270,15 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
||||||
List<Preview> previews = getPreviewsFor(message);
|
List<Preview> previews = getPreviewsFor(message);
|
||||||
|
|
||||||
// Loki - Include a pre key bundle if the message is a friend request or an end session message
|
// Loki - Include a pre key bundle if needed
|
||||||
PreKeyBundle preKeyBundle = isFriendRequest ? DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.getNumber()) : null;
|
PreKeyBundle preKeyBundle;
|
||||||
String body = (isFriendRequest && customFriendRequestMessage != null) ? customFriendRequestMessage : message.getBody();
|
if (isLokiPreKeyBundleMessage) {
|
||||||
|
preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.getNumber());
|
||||||
|
} else {
|
||||||
|
preKeyBundle = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String body = (isLokiPreKeyBundleMessage && customFriendRequestMessage != null) ? customFriendRequestMessage : message.getBody();
|
||||||
SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withBody(body)
|
.withBody(body)
|
||||||
.withAttachments(serviceAttachments)
|
.withAttachments(serviceAttachments)
|
||||||
@ -283,25 +291,18 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
.withPreviews(previews)
|
.withPreviews(previews)
|
||||||
.asExpirationUpdate(message.isExpirationUpdate())
|
.asExpirationUpdate(message.isExpirationUpdate())
|
||||||
.withPreKeyBundle(preKeyBundle)
|
.withPreKeyBundle(preKeyBundle)
|
||||||
.asFriendRequest(isFriendRequest)
|
.asFriendRequest(isLokiPreKeyBundleMessage)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
if (address.getNumber().equals(TextSecurePreferences.getLocalNumber(context))) {
|
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) {
|
||||||
|
// Loki - Device link messages don't go through here
|
||||||
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
|
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
|
||||||
SignalServiceSyncMessage syncMessage = buildSelfSendSyncMessage(context, mediaMessage, syncAccess);
|
SignalServiceSyncMessage syncMessage = buildSelfSendSyncMessage(context, mediaMessage, syncAccess);
|
||||||
|
|
||||||
messageSender.sendMessage(templateMessageId, syncMessage, syncAccess);
|
messageSender.sendMessage(syncMessage, syncAccess);
|
||||||
return syncAccess.isPresent();
|
return syncAccess.isPresent();
|
||||||
} else {
|
} else {
|
||||||
LokiSyncMessage syncMessage = null;
|
SendMessageResult result = messageSender.sendMessage(messageId, address, UnidentifiedAccessUtil.getAccessFor(context, recipient), mediaMessage);
|
||||||
if (shouldSendSyncMessage) {
|
|
||||||
// Set the sync message destination to the master device, this way it will show that we sent a message to the master device and not the slave device
|
|
||||||
String masterDevice = PromiseUtil.get(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(address.getNumber()), null);
|
|
||||||
SignalServiceAddress masterAddress = masterDevice == null ? address : new SignalServiceAddress(masterDevice);
|
|
||||||
// We also need to use the original message ID and not -1
|
|
||||||
syncMessage = new LokiSyncMessage(masterAddress, templateMessageId);
|
|
||||||
}
|
|
||||||
SendMessageResult result = messageSender.sendMessage(messageId, address, UnidentifiedAccessUtil.getAccessFor(context, recipient), mediaMessage, Optional.fromNullable(syncMessage));
|
|
||||||
if (result.getLokiAPIError() != null) {
|
if (result.getLokiAPIError() != null) {
|
||||||
throw result.getLokiAPIError();
|
throw result.getLokiAPIError();
|
||||||
} else {
|
} else {
|
||||||
@ -326,10 +327,9 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
long templateMessageID = data.getLong(KEY_TEMPLATE_MESSAGE_ID);
|
long templateMessageID = data.getLong(KEY_TEMPLATE_MESSAGE_ID);
|
||||||
long messageID = data.getLong(KEY_MESSAGE_ID);
|
long messageID = data.getLong(KEY_MESSAGE_ID);
|
||||||
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
|
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
|
||||||
boolean isFriendRequest = data.getBoolean(KEY_IS_FRIEND_REQUEST);
|
boolean isLokiPreKeyBundleMessage = data.getBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE);
|
||||||
boolean shouldSendSyncMessage = data.getBoolean(KEY_SHOULD_SEND_SYNC_MESSAGE);
|
String customFRMessage = data.hasString(KEY_CUSTOM_FR_MESSAGE) ? data.getString(KEY_CUSTOM_FR_MESSAGE) : null;
|
||||||
String frMessage = 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, isFriendRequest, frMessage, shouldSendSyncMessage);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user