Merge branch 'dev'

This commit is contained in:
nielsandriesse 2020-05-26 16:05:45 +10:00
commit 4001714705
245 changed files with 3483 additions and 4334 deletions

1
.gitignore vendored
View File

@ -26,3 +26,4 @@ jni/libspeex/.deps/
pkcs11.password
fabric.properties
play
google-services.json

View File

@ -16,12 +16,6 @@
<uses-feature
android:name="android.hardware.bluetooth"
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
android:name="android.hardware.microphone"
android:required="false" />
@ -56,8 +50,6 @@
<!-- For conversation 'shortcuts' on the desktop -->
<uses-permission android:name="android.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.DISABLE_KEYGUARD" />
@ -96,62 +88,62 @@
<!-- Session -->
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.LandingActivity"
android:name="org.thoughtcrime.securesms.loki.activities.LandingActivity"
android:screenOrientation="portrait" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.RegisterActivity"
android:name="org.thoughtcrime.securesms.loki.activities.RegisterActivity"
android:screenOrientation="portrait" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.RestoreActivity"
android:name="org.thoughtcrime.securesms.loki.activities.RestoreActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.LinkDeviceActivity"
android:name="org.thoughtcrime.securesms.loki.activities.LinkDeviceActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.DisplayNameActivity"
android:name="org.thoughtcrime.securesms.loki.activities.DisplayNameActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.PNModeActivity"
android:name="org.thoughtcrime.securesms.loki.activities.PNModeActivity"
android:screenOrientation="portrait" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity"
android:name="org.thoughtcrime.securesms.loki.activities.HomeActivity"
android:screenOrientation="portrait"
android:launchMode="singleTask"
android:theme="@style/Session.DarkTheme.NoActionBar" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.SettingsActivity"
android:name="org.thoughtcrime.securesms.loki.activities.SettingsActivity"
android:screenOrientation="portrait"
android:theme="@style/Session.DarkTheme.NoActionBar" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.QRCodeActivity"
android:name="org.thoughtcrime.securesms.loki.activities.QRCodeActivity"
android:screenOrientation="portrait" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.CreatePrivateChatActivity"
android:name="org.thoughtcrime.securesms.loki.activities.CreatePrivateChatActivity"
android:screenOrientation="portrait" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.CreateClosedGroupActivity"
android:name="org.thoughtcrime.securesms.loki.activities.CreateClosedGroupActivity"
android:screenOrientation="portrait" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.JoinPublicChatActivity"
android:name="org.thoughtcrime.securesms.loki.activities.JoinPublicChatActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.SeedActivity"
android:name="org.thoughtcrime.securesms.loki.activities.SeedActivity"
android:screenOrientation="portrait" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.PrivacySettingsActivity"
android:name="org.thoughtcrime.securesms.loki.activities.PrivacySettingsActivity"
android:screenOrientation="portrait" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.NotificationSettingsActivity"
android:name="org.thoughtcrime.securesms.loki.activities.NotificationSettingsActivity"
android:screenOrientation="portrait" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.ChatSettingsActivity"
android:name="org.thoughtcrime.securesms.loki.activities.ChatSettingsActivity"
android:screenOrientation="portrait" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.LinkedDevicesActivity"
android:name="org.thoughtcrime.securesms.loki.activities.LinkedDevicesActivity"
android:screenOrientation="portrait" />
<!-- Session -->
<activity
@ -166,7 +158,7 @@
<activity
android:name="org.thoughtcrime.securesms.InviteActivity"
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:windowSoftInputMode="stateHidden">
<meta-data
@ -225,7 +217,7 @@
<activity-alias
android:name=".RoutingActivity"
android:exported="true"
android:targetActivity="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity">
android:targetActivity="org.thoughtcrime.securesms.loki.activities.HomeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -264,7 +256,7 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:label="@string/AndroidManifest_archived_conversations"
android:launchMode="singleTask"
android:parentActivityName="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity">
android:parentActivityName="org.thoughtcrime.securesms.loki.activities.HomeActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="PsiClass:HomeActivity" />
@ -275,7 +267,7 @@
android:launchMode="singleTask"
android:screenOrientation="portrait"
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">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
@ -514,7 +506,7 @@
android:exported="true"
android:theme="@style/TextSecure.LightNoActionBar" />
<service
android:name="org.thoughtcrime.securesms.service.PushNotificationService"
android:name="org.thoughtcrime.securesms.loki.api.PushNotificationService"
android:enabled="true"
android:exported="true">
<intent-filter>
@ -673,12 +665,12 @@
</intent-filter>
</receiver>
<!-- Session -->
<receiver android:name="org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPollWorker">
<receiver android:name="org.thoughtcrime.securesms.loki.api.BackgroundPollWorker">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name="org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundOpenGroupPollWorker">
<receiver android:name="org.thoughtcrime.securesms.loki.api.BackgroundOpenGroupPollWorker">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>

View File

@ -190,8 +190,8 @@ dependencies {
implementation "com.github.ybq:Android-SpinKit:1.4.0"
}
def canonicalVersionCode = 49
def canonicalVersionName = "1.1.0"
def canonicalVersionCode = 50
def canonicalVersionName = "1.2.0"
def postFixSize = 10
def abiPostFix = ['armeabi-v7a' : 1,

View File

@ -21,7 +21,7 @@
android:textColor="@color/text"
android:text="Your Session begins here..." />
<org.thoughtcrime.securesms.loki.redesign.views.FakeChatView
<org.thoughtcrime.securesms.loki.views.FakeChatView
android:id="@+id/fakeChatView"
android:layout_width="match_parent"
android:layout_height="@dimen/fake_chat_view_height"

View File

@ -7,7 +7,7 @@
android:gravity="center_horizontal"
android:orientation="vertical">
<org.thoughtcrime.securesms.loki.redesign.views.SeedReminderView
<org.thoughtcrime.securesms.loki.views.SeedReminderView
android:id="@+id/seedReminderView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View File

@ -30,7 +30,7 @@
android:textAlignment="center"
android:text="Users can share their Session ID by going into their account settings and tapping &quot;Share Session ID&quot;, or by sharing their QR code." />
<org.thoughtcrime.securesms.loki.redesign.views.LabeledSeparatorView
<org.thoughtcrime.securesms.loki.views.LabeledSeparatorView
android:id="@+id/separatorView"
android:layout_width="match_parent"
android:layout_height="32dp"

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

View File

@ -25,7 +25,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="6dp"
android:layout_marginTop="4dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/small_font_size"
android:textColor="@color/text"
@ -37,7 +37,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="12dp"
android:layout_marginTop="10dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:hint="Enter a display name" />

View File

@ -21,11 +21,11 @@
android:layout_width="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:layout_width="@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_centerVertical="true" />
@ -44,7 +44,7 @@
</android.support.v7.widget.Toolbar>
<org.thoughtcrime.securesms.loki.redesign.views.SeedReminderView
<org.thoughtcrime.securesms.loki.views.SeedReminderView
android:id="@+id/seedReminderView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
@ -66,13 +66,39 @@
android:layout_height="match_parent"
android:background="@drawable/home_activity_gradient" />
<org.thoughtcrime.securesms.loki.redesign.views.NewConversationButtonSetView
<org.thoughtcrime.securesms.loki.views.NewConversationButtonSetView
android:id="@+id/newConversationButtonSet"
android:layout_width="252dp"
android:layout_height="212dp"
android:layout_centerHorizontal="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>
</LinearLayout>

View File

@ -21,7 +21,7 @@
android:textColor="@color/text"
android:text="Your Session begins here..." />
<org.thoughtcrime.securesms.loki.redesign.views.FakeChatView
<org.thoughtcrime.securesms.loki.views.FakeChatView
android:id="@+id/fakeChatView"
android:layout_width="match_parent"
android:layout_height="@dimen/fake_chat_view_height"

View File

@ -31,7 +31,7 @@
android:layout_width="196dp"
android:layout_height="@dimen/medium_button_height"
android:layout_marginTop="@dimen/medium_spacing"
android:text="Link a Device" />
android:text="Link a Device (Beta)" />
</LinearLayout>

View File

@ -25,7 +25,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="6dp"
android:layout_marginTop="4dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/small_font_size"
android:textColor="@color/text"
@ -38,7 +38,7 @@
android:layout_height="wrap_content"
android:textSize="18dp"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="12dp"
android:layout_marginTop="10dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />

View File

@ -25,7 +25,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="6dp"
android:layout_marginTop="4dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/small_font_size"
android:textColor="@color/text"
@ -37,7 +37,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="12dp"
android:layout_marginTop="10dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:hint="Enter your recovery phrase" />

View File

@ -7,7 +7,7 @@
android:gravity="center_horizontal"
android:orientation="vertical">
<org.thoughtcrime.securesms.loki.redesign.views.SeedReminderView
<org.thoughtcrime.securesms.loki.views.SeedReminderView
android:id="@+id/seedReminderView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
@ -22,7 +22,7 @@
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/large_font_size"
android:textSize="19sp"
android:textStyle="bold"
android:textColor="@color/text"
android:text="Meet your recovery phrase" />
@ -31,9 +31,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="10dp"
android:layout_marginTop="4dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/medium_font_size"
android:textSize="14sp"
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 dont 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_height="wrap_content"
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:gravity="center"
android:textSize="@dimen/medium_font_size"
@ -54,9 +54,9 @@
android:id="@+id/revealButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginTop="6dp"
android:textAlignment="center"
android:textSize="@dimen/medium_font_size"
android:textSize="14sp"
android:textColor="@color/text"
android:alpha="0.6"
android:text="Hold to reveal" />

View File

@ -70,7 +70,7 @@
</android.support.v7.widget.Toolbar>
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
android:id="@+id/profilePictureView"
android:layout_width="@dimen/large_profile_picture_size"
android:layout_height="@dimen/large_profile_picture_size"
@ -107,7 +107,7 @@
</RelativeLayout>
<org.thoughtcrime.securesms.loki.redesign.views.LabeledSeparatorView
<org.thoughtcrime.securesms.loki.views.LabeledSeparatorView
android:id="@+id/separatorView"
android:layout_width="match_parent"
android:layout_height="32dp"

View File

@ -19,6 +19,6 @@
<fragment android:id="@+id/contact_selection_list_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="org.thoughtcrime.securesms.ContactSelectionListFragment" />
android:name="org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment" />
</LinearLayout>

View File

@ -1,92 +1,53 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="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.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:scrollbars="vertical" />
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|center_vertical"
android:layout_marginTop="15dp"
android:text="@string/contact_selection_group_activity__finding_contacts"
android:textSize="20sp" />
</android.support.v4.widget.SwipeRefreshLayout>
<org.thoughtcrime.securesms.components.RecyclerViewFastScroller
android:id="@+id/fast_scroller"
android:layout_width="wrap_content"
<LinearLayout
android:id="@+id/emptyStateContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:layout_gravity="end"/>
android:gravity="center"
android:orientation="vertical">
<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">
<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" />
<FrameLayout
</LinearLayout>
<LinearLayout
android:id="@+id/mainContentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="match_parent"
android:clipToPadding="false"
android:scrollbars="vertical" />
<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"
/>
<TextView
android:id="@+id/loadingTextView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/text"
android:text="@string/contact_selection_group_activity__finding_contacts"
android:textSize="@dimen/large_font_size" />
<ImageView android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/no_contacts"/>
</android.support.v4.widget.SwipeRefreshLayout>
</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>
</FrameLayout>

View File

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

View File

@ -104,7 +104,7 @@
android:indeterminate="false"
android:progress="0" />
<org.thoughtcrime.securesms.loki.redesign.views.SessionRestoreBannerView
<org.thoughtcrime.securesms.loki.views.SessionRestoreBannerView
android:id="@+id/sessionRestoreBannerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View File

@ -28,7 +28,7 @@
android:layout_height="42dp"
android:layout_alignParentStart="true">
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
android:id="@+id/profilePictureView"
android:layout_marginTop="2dp"
android:layout_width="@dimen/small_profile_picture_size"
@ -208,7 +208,7 @@
</LinearLayout>
<org.thoughtcrime.securesms.loki.redesign.views.FriendRequestView
<org.thoughtcrime.securesms.loki.views.FriendRequestView
android:id="@+id/friend_request_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -18,7 +18,7 @@
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/large_spacing"
android:layout_marginEnd="12dp"
android:clipToPadding="false"
android:clipChildren="false">
@ -161,7 +161,7 @@
</LinearLayout>
<org.thoughtcrime.securesms.loki.redesign.views.FriendRequestView
<org.thoughtcrime.securesms.loki.views.FriendRequestView
android:id="@+id/friend_request_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -4,7 +4,7 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/large_spacing"
android:paddingStart="12dp"
android:paddingEnd="8dp"
android:paddingBottom="@dimen/small_spacing"
android:gravity="center_vertical">

View File

@ -3,6 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/default_dialog_background_inset"
android:gravity="center_horizontal"
android:orientation="vertical"
@ -12,6 +13,7 @@
android:paddingBottom="@dimen/medium_spacing">
<RelativeLayout
android:id="@+id/qrCodeImageViewContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/small_spacing"
@ -24,6 +26,15 @@
</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
android:id="@+id/titleTextView"
android:layout_width="wrap_content"
@ -56,6 +67,7 @@
android:visibility="gone" />
<LinearLayout
android:id="@+id/buttonContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/large_spacing"

View File

@ -18,7 +18,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_centerInParent="true"
app:SpinKit_Color="@color/text" />
<TextView

View File

@ -30,7 +30,7 @@
android:textAlignment="center"
android:text="Users can share their Session ID by going into their account settings and tapping &quot;Share Session ID&quot;, or by sharing their QR code." />
<org.thoughtcrime.securesms.loki.redesign.views.LabeledSeparatorView
<org.thoughtcrime.securesms.loki.views.LabeledSeparatorView
android:id="@+id/separatorView"
android:layout_width="match_parent"
android:layout_height="32dp"

View File

@ -26,7 +26,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/large_spacing"
android:layout_marginTop="6dp"
android:layout_marginTop="4dp"
android:layout_marginRight="@dimen/large_spacing"
android:textSize="14sp"
android:textColor="@color/text"
@ -38,7 +38,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/large_spacing"
android:layout_marginTop="12dp"
android:layout_marginTop="10dp"
android:layout_marginRight="@dimen/large_spacing"
android:hint="Enter your session ID" />

View File

@ -94,7 +94,7 @@
android:layout_width="match_parent"
android:layout_height="0dp"
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"/>
<LinearLayout android:layout_width="match_parent"

View File

@ -49,7 +49,7 @@
android:layout_below="@id/toolbar"
android:layout_width="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
android:id="@+id/search_toolbar"

View File

@ -13,7 +13,7 @@
android:layout_height="match_parent"
android:background="@color/accent" />
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
android:id="@+id/profilePictureView"
android:layout_width="@dimen/medium_profile_picture_size"
android:layout_height="@dimen/medium_profile_picture_size"

View File

@ -1,5 +1,5 @@
<?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"
android:layout_width="match_parent"
android:layout_height="44dp"
@ -13,7 +13,7 @@
android:layout_width="26dp"
android:layout_height="32dp">
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
android:id="@+id/profilePictureView"
android:layout_width="@dimen/very_small_profile_picture_size"
android:layout_height="@dimen/very_small_profile_picture_size"
@ -39,4 +39,4 @@
android:maxLines="1"
android:ellipsize="end" />
</org.thoughtcrime.securesms.loki.redesign.views.MentionCandidateView>
</org.thoughtcrime.securesms.loki.views.MentionCandidateView>

View File

@ -1,5 +1,5 @@
<?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"
android:id="@+id/userSelectionView"
android:layout_width="match_parent"

View File

@ -1,5 +1,6 @@
<?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_height="wrap_content"
android:background="@color/cell_background"
@ -39,11 +40,12 @@
<TextView
android:id="@+id/subtitleTextView"
android:layout_width="wrap_content"
android:layout_width="224dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/text"
android:textSize="@dimen/very_small_font_size"
android:lines="2"
android:alpha="0.6"
android:text="Secure your account by saving your recovery phrase" />
@ -52,14 +54,15 @@
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
android:layout_weight="1"
android:layout_marginLeft="4dp" />
<Button
style="@style/MediumProminentOutlineButton"
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="27dp"
android:layout_marginLeft="@dimen/small_spacing"
android:layout_height="28dp"
android:layout_marginLeft="4dp"
android:textStyle="normal"
android:text="Continue" />

View File

@ -14,7 +14,7 @@
android:gravity="center_vertical"
android:padding="@dimen/medium_spacing">
<org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
android:id="@+id/profilePictureView"
android:layout_width="@dimen/medium_profile_picture_size"
android:layout_height="@dimen/medium_profile_picture_size" />

View File

@ -1663,13 +1663,14 @@
<string name="session_restore_banner_dismiss_button_title">Dismiss</string>
<string name="session_restore_banner_restore_button_title">Restore</string>
<!-- Loki -->
<!-- Session -->
<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_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="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_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>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<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.seed2.loki.network</domain>
<domain includeSubdomains="true">public.loki.foundation</domain>

View File

@ -19,10 +19,8 @@ package org.thoughtcrime.securesms;
import android.arch.lifecycle.DefaultLifecycleObserver;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.ProcessLifecycleOwner;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.os.AsyncTask;
import android.os.Build;
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.ProfileKeyUtil;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseContentProviders;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.jobmanager.DependencyInjector;
import org.thoughtcrime.securesms.jobmanager.JobManager;
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.PersistentLogger;
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
import org.thoughtcrime.securesms.loki.LokiPublicChatManager;
import org.thoughtcrime.securesms.loki.LokiPushNotificationManager;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundOpenGroupPollWorker;
import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPollWorker;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiRSSFeedPoller;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.redesign.utilities.Broadcaster;
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
import org.thoughtcrime.securesms.loki.api.BackgroundOpenGroupPollWorker;
import org.thoughtcrime.securesms.loki.api.BackgroundPollWorker;
import org.thoughtcrime.securesms.loki.api.LokiPublicChatManager;
import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager;
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.protocol.EphemeralMessage;
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation;
import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob;
import org.thoughtcrime.securesms.loki.utilities.Broadcaster;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
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.UpdateApkRefreshListener;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
import org.webrtc.PeerConnectionFactory;
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.internal.push.SignalServiceProtos;
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.LokiPushNotificationAcknowledgement;
import org.whispersystems.signalservice.loki.api.LokiSwarmAPI;
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI;
import org.whispersystems.signalservice.loki.api.rssfeeds.LokiRSSFeed;
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI;
import org.whispersystems.signalservice.loki.api.p2p.LokiP2PAPI;
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.FileInputStream;
import java.security.SecureRandom;
import java.security.Security;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import dagger.ObjectGraph;
@ -132,7 +135,7 @@ import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant;
*
* @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 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;
// Loki
private LokiPoller lokiPoller = null;
private LokiRSSFeedPoller lokiNewsFeedPoller = null;
private LokiRSSFeedPoller lokiMessengerUpdatesFeedPoller = null;
private LokiPublicChatManager lokiPublicChatManager = null;
public LokiPoller lokiPoller = null;
public LokiPublicChatManager lokiPublicChatManager = null;
private LokiPublicChatAPI lokiPublicChatAPI = null;
public Broadcaster broadcaster = null;
public SignalCommunicationModule communicationModule;
@ -164,13 +165,42 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate()");
broadcaster = new Broadcaster(this);
checkNeedsDatabaseReset();
startKovenant();
initializeSecurityProvider();
initializeLogging();
initializeCrashHandling();
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();
initializeMessageRetrieval();
initializeExpiringMessageManager();
@ -182,30 +212,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
initializePendingMessages();
initializeUnidentifiedDeliveryAbilityRefresh();
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
@ -214,9 +220,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
Log.i(TAG, "App is now visible.");
executePendingContactSync();
KeyCachingService.onAppForegrounded(this);
// Loki - Start polling if needed
// Loki
startPollingIfNeeded();
// Loki - Start open group polling if needed
lokiPublicChatManager.startPollersIfNeeded();
}
@ -226,14 +231,14 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
Log.i(TAG, "App is no longer visible.");
KeyCachingService.onAppBackgrounded(this);
MessageNotifier.setVisibleThread(-1);
// Loki - Stop polling if needed
// Loki
if (lokiPoller != null) { lokiPoller.stopIfNeeded(); }
if (lokiPublicChatManager != null) { lokiPublicChatManager.stopPollers(); }
}
@Override
public void onTerminate() {
stopKovenant();
stopKovenant(); // Loki
super.onTerminate();
}
@ -268,20 +273,15 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
return persistentLogger;
}
public LokiPublicChatManager getLokiPublicChatManager() {
return lokiPublicChatManager;
}
// Loki
public @Nullable LokiPublicChatAPI getLokiPublicChatAPI() {
if (lokiPublicChatAPI == null && IdentityKeyUtil.hasIdentityKey(this)) {
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userHexEncodedPublicKey != null) {
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
LokiAPIDatabase apiDatabase = DatabaseFactory.getLokiAPIDatabase(this);
LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(this);
lokiPublicChatAPI = new LokiPublicChatAPI(userHexEncodedPublicKey, userPrivateKey, apiDatabase, userDatabase);
}
}
if (lokiPublicChatAPI != null || !IdentityKeyUtil.hasIdentityKey(this)) { return lokiPublicChatAPI; }
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userPublicKey== null) { return lokiPublicChatAPI; }
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
lokiPublicChatAPI = new LokiPublicChatAPI(userPublicKey, userPrivateKey, apiDB, userDB);
return lokiPublicChatAPI;
}
@ -363,8 +363,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
RotateSignedPreKeyListener.schedule(this);
LocalBackupListener.schedule(this);
RotateSenderCertificateListener.schedule(this);
BackgroundPollWorker.schedule(this); // Session
BackgroundOpenGroupPollWorker.schedule(this); // Session
BackgroundPollWorker.schedule(this); // Loki
BackgroundOpenGroupPollWorker.schedule(this); // Loki
if (BuildConfig.PLAY_STORE_DISABLED) {
UpdateApkRefreshListener.schedule(this);
@ -442,18 +442,16 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
// region Loki
public boolean setUpStorageAPIIfNeeded() {
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userHexEncodedPublicKey != null && IdentityKeyUtil.hasIdentityKey(this)) {
boolean isDebugMode = BuildConfig.DEBUG;
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
LokiAPIDatabaseProtocol database = DatabaseFactory.getLokiAPIDatabase(this);
LokiFileServerAPI.Companion.configure(isDebugMode, userHexEncodedPublicKey, userPrivateKey, database);
return true;
}
return false;
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userPublicKey == null || !IdentityKeyUtil.hasIdentityKey(this)) { return false; }
boolean isDebugMode = BuildConfig.DEBUG;
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
LokiAPIDatabaseProtocol apiDB = DatabaseFactory.getLokiAPIDatabase(this);
LokiFileServerAPI.Companion.configure(isDebugMode, userPublicKey, userPrivateKey, apiDB);
return true;
}
public void setUpP2PAPI() {
public void setUpP2PAPIIfNeeded() {
String hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
if (hexEncodedPublicKey == null) { return; }
LokiP2PAPI.Companion.configure(hexEncodedPublicKey, (isOnline, contactPublicKey) -> {
@ -470,10 +468,10 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
return;
}
String token = task.getResult().getToken();
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context);
if (userHexEncodedPublicKey == null) return;
String userPublicKey = TextSecurePreferences.getLocalNumber(context);
if (userPublicKey == null) return;
if (TextSecurePreferences.isUsingFCM(this)) {
LokiPushNotificationManager.register(token, userHexEncodedPublicKey, context, force);
LokiPushNotificationManager.register(token, userPublicKey, context, force);
} else {
LokiPushNotificationManager.unregister(token, context);
}
@ -487,15 +485,15 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
private void setUpPollingIfNeeded() {
if (lokiPoller != null) return;
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userHexEncodedPublicKey == null) return;
LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(this);
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userPublicKey == null) return;
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
Context context = this;
LokiSwarmAPI.Companion.configureIfNeeded(lokiAPIDatabase);
LokiAPI.Companion.configureIfNeeded(userHexEncodedPublicKey, lokiAPIDatabase, broadcaster);
lokiPoller = new LokiPoller(userHexEncodedPublicKey, lokiAPIDatabase, protos -> {
LokiSwarmAPI.Companion.configureIfNeeded(apiDB);
LokiAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster);
lokiPoller = new LokiPoller(userPublicKey, apiDB, protos -> {
for (SignalServiceProtos.Envelope proto : protos) {
new PushContentReceiveJob(context).processEnvelope(new SignalServiceEnvelope(proto));
new PushContentReceiveJob(context).processEnvelope(new SignalServiceEnvelope(proto), false);
}
return Unit.INSTANCE;
});
@ -506,94 +504,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
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() {
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userHexEncodedPublicKey == null) return;
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userPublicKey == null) return;
long now = new Date().getTime();
long lastProfilePictureUpload = TextSecurePreferences.getLastProfilePictureUpload(this);
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);
byte[] profileKey = ProfileKeyUtil.getProfileKeyFromEncodedString(encodedProfileKey);
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());
LokiFileServerAPI.shared.uploadProfilePicture(LokiFileServerAPI.shared.getServer(), profileKey, stream, () -> {
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(() -> {
LokiPublicChatAPI publicChatAPI = null;
try {
@ -623,48 +536,46 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
} catch (Exception e) {
// Do nothing
}
if (publicChatAPI != null) {
byte[] profileKey = ProfileKeyUtil.getProfileKey(this);
String url = TextSecurePreferences.getProfileAvatarUrl(this);
String ourMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(this);
if (ourMasterDevice != null) {
Recipient masterDevice = Recipient.from(this, Address.fromSerialized(ourMasterDevice), false).resolve();
profileKey = masterDevice.getProfileKey();
url = masterDevice.getProfileAvatar();
}
Set<String> servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers();
for (String server : servers) {
if (profileKey != null) {
publicChatAPI.setProfilePicture(server, profileKey, url);
}
if (publicChatAPI == null) { return; }
byte[] profileKey = ProfileKeyUtil.getProfileKey(this);
String url = TextSecurePreferences.getProfilePictureURL(this);
String userMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(this);
if (userMasterDevice != null) {
Recipient userMasterDeviceAsRecipient = Recipient.from(this, Address.fromSerialized(userMasterDevice), false).resolve();
profileKey = userMasterDeviceAsRecipient.getProfileKey();
url = userMasterDeviceAsRecipient.getProfileAvatar();
}
Set<String> servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers();
for (String server : servers) {
if (profileKey != null) {
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() {
TextSecurePreferences.setResetDatabase(this, true);
new Handler().postDelayed(this::restartApplication, 200);
boolean wasUnlinked = TextSecurePreferences.getWasUnlinked(this);
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() {
Intent intent = new Intent(this, HomeActivity.class);
ComponentName componentName = intent.getComponent();
Intent mainIntent = Intent.makeRestartActivityTask(componentName);
this.startActivity(mainIntent);
startActivity(Intent.makeRestartActivityTask(intent.getComponent()));
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
}

View File

@ -41,7 +41,7 @@ import android.util.Log;
import android.widget.Toast;
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.ChatsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
@ -345,16 +345,16 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
}
String seed = new MnemonicCodec(languageFileDirectory).encode(hexEncodedSeed, MnemonicCodec.Language.Configuration.Companion.getEnglish());
new AlertDialog.Builder(getContext())
.setTitle(R.string.activity_settings_seed_dialog_title)
.setMessage(seed)
.setPositiveButton(R.string.activity_settings_seed_dialog_copy_button_title, (DialogInterface.OnClickListener) (dialog, which) -> {
ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("seed", seed);
clipboard.setPrimaryClip(clip);
Toast.makeText(getContext(), R.string.activity_settings_seed_copied_message, Toast.LENGTH_SHORT).show();
})
.setNeutralButton(R.string.activity_settings_seed_dialog_ok_button_title, null)
.show();
.setTitle(R.string.activity_settings_seed_dialog_title)
.setMessage(seed)
.setPositiveButton(R.string.activity_settings_seed_dialog_copy_button_title, (DialogInterface.OnClickListener) (dialog, which) -> {
ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("seed", seed);
clipboard.setPrimaryClip(clip);
Toast.makeText(getContext(), R.string.activity_settings_seed_copied_message, Toast.LENGTH_SHORT).show();
})
.setNeutralButton(R.string.activity_settings_seed_dialog_ok_button_title, null)
.show();
} catch (Exception e) {
Log.d("Loki", e.getMessage());
}

View File

@ -20,11 +20,11 @@ import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
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.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import network.loki.messenger.R;
@ -36,8 +36,8 @@ import network.loki.messenger.R;
*
*/
public abstract class ContactSelectionActivity extends PassphraseRequiredActionBarActivity
implements SwipeRefreshLayout.OnRefreshListener,
ContactSelectionListFragment.OnContactSelectedListener
implements SwipeRefreshLayout.OnRefreshListener,
ContactSelectionListFragment.OnContactSelectedListener
{
private static final String TAG = ContactSelectionActivity.class.getSimpleName();
@ -57,9 +57,7 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
@Override
protected void onCreate(Bundle icicle, boolean ready) {
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
int displayMode = TextSecurePreferences.isSmsEnabled(this) ? DisplayMode.FLAG_ALL
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_GROUPS;
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_ALL);
}
setContentView(R.layout.contact_selection_activity);

View File

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

View File

@ -49,8 +49,8 @@ import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
import org.thoughtcrime.securesms.loki.RecipientAvatarModifiedEvent;
import org.thoughtcrime.securesms.loki.redesign.activities.JoinPublicChatActivity;
import org.thoughtcrime.securesms.loki.utilities.ProfilePictureModifiedEvent;
import org.thoughtcrime.securesms.loki.activities.JoinPublicChatActivity;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
@ -86,13 +86,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
protected void onPreCreate() {
dynamicTheme.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
@ -330,9 +323,9 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onAvatarModified(RecipientAvatarModifiedEvent event) {
public void onAvatarModified(ProfilePictureModifiedEvent event) {
Recipient recipient = event.getRecipient();
if (recipient.isLocalNumber() || recipient.isOurMasterDevice()) {
if (recipient.isLocalNumber() || recipient.isUserMasterDevice()) {
initializeProfileIcon(recipient);
}
}

View File

@ -74,7 +74,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
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.notifications.MarkReadReceiver;
import org.thoughtcrime.securesms.notifications.MessageNotifier;

View File

@ -37,8 +37,8 @@ import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.components.ThumbnailView;
import org.thoughtcrime.securesms.components.TypingIndicatorView;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities;
import org.thoughtcrime.securesms.loki.redesign.utilities.MentionUtilities;
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
import org.thoughtcrime.securesms.loki.utilities.MentionUtilities;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
@ -272,7 +272,7 @@ public class ConversationListItem extends RelativeLayout
}
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());
return snippet.length() <= MAX_SNIPPET_LENGTH ? snippet : snippet.subSequence(0, MAX_SNIPPET_LENGTH);
}

View File

@ -59,7 +59,7 @@ import org.whispersystems.signalservice.api.crypto.ProfileCipher;
import org.whispersystems.signalservice.api.util.StreamDetails;
import org.whispersystems.signalservice.loki.api.LokiDotNetAPI;
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.File;
@ -406,7 +406,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
String newProfileKey = ProfileKeyUtil.generateEncodedProfileKey(context);
byte[] profileKey = ProfileKeyUtil.getProfileKeyFromEncodedString(newProfileKey);
//Loki - Upload the profile photo here
// Loki - Upload the profile photo here
if (avatar != null) {
Log.d("Loki", "Start uploading profile photo");
LokiFileServerAPI storageAPI = LokiFileServerAPI.shared;
@ -415,9 +415,9 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
return Unit.INSTANCE;
});
Log.d("Loki", "Profile photo uploaded, the url is " + result.getUrl());
TextSecurePreferences.setProfileAvatarUrl(context, result.getUrl());
TextSecurePreferences.setProfilePictureURL(context, result.getUrl());
} else {
TextSecurePreferences.setProfileAvatarUrl(context, null);
TextSecurePreferences.setProfilePictureURL(context, null);
}
AvatarHelper.setAvatar(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), avatarBytes);
@ -427,7 +427,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
ProfileKeyUtil.setEncodedProfileKey(context, newProfileKey);
// Update profile key on the public chat server
ApplicationContext.getInstance(context).updatePublicChatProfilePictureIfNeeded();
ApplicationContext.getInstance(context).updateOpenGroupProfilePicturesIfNeeded();
} catch (Exception e) {
Log.d("Loki", "Failed to upload profile photo: " + e);
return false;

View File

@ -18,7 +18,7 @@ import android.widget.ProgressBar;
import android.widget.TextView;
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.ImportState;

View File

@ -25,8 +25,8 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.loaders.DeviceListLoader;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.devicelist.Device;
import org.thoughtcrime.securesms.loki.redesign.dialogs.DeviceEditingOptionsBottomSheet;
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities;
import org.thoughtcrime.securesms.loki.dialogs.DeviceEditingOptionsBottomSheet;
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.whispersystems.libsignal.util.guava.Function;
@ -39,7 +39,7 @@ import kotlin.Pair;
import kotlin.Unit;
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
implements LoaderManager.LoaderCallbacks<List<Device>>,

View File

@ -19,7 +19,7 @@ import com.nineoldandroids.animation.ArgbEvaluator;
import org.thoughtcrime.securesms.IntroPagerAdapter.IntroPage;
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.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;

View File

@ -43,7 +43,6 @@ import com.bumptech.glide.request.transition.Transition;
import org.thoughtcrime.securesms.avatar.AvatarSelection;
import org.thoughtcrime.securesms.components.PushRecipientsPanel;
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.avatars.ContactColors;
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.GroupActionResult;
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.recipients.Recipient;
import org.thoughtcrime.securesms.util.BitmapUtil;
@ -321,11 +322,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
@Override
public void onClick(View v) {
Intent intent = new Intent(GroupCreateActivity.this, PushContactSelectionActivity.class);
if (groupToUpdate.isPresent()) {
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_PUSH);
} else {
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_PUSH | DisplayMode.FLAG_SMS);
}
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_FRIENDS);
startActivityForResult(intent, PICK_CONTACT);
}
}

View File

@ -26,9 +26,10 @@ import android.widget.Toast;
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
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.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.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
@ -40,7 +41,7 @@ import java.util.concurrent.ExecutionException;
import network.loki.messenger.R;
public class InviteActivity extends PassphraseRequiredActionBarActivity implements ContactSelectionListFragment.OnContactSelectedListener {
public class InviteActivity extends PassphraseRequiredActionBarActivity {
private ContactSelectionListFragment contactsFragment;
private EditText inviteText;
@ -52,7 +53,7 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
@Override
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.REFRESHABLE, false);
@ -84,7 +85,6 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
heart.getViewTreeObserver().addOnPreDrawListener(new HeartPreDrawListener());
}
contactsFragment.setOnContactSelectedListener(this);
shareButton.setOnClickListener(new ShareClickListener());
smsButton.setOnClickListener(new SmsClickListener());
smsCancelButton.setOnClickListener(new SmsCancelClickListener());
@ -99,12 +99,10 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
return animation;
}
@Override
public void onContactSelected(String number) {
updateSmsButtonText();
}
@Override
public void onContactDeselected(String number) {
updateSmsButtonText();
}
@ -132,7 +130,6 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
}
private void cancelSmsSelection() {
contactsFragment.reset();
updateSmsButtonText();
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>() {
@Override
public void onSuccess(Boolean result) {
contactsFragment.reset();
}
@Override

View File

@ -47,7 +47,7 @@ import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.loaders.MessageDetailsLoader;
import org.thoughtcrime.securesms.database.model.MessageRecord;
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.GlideRequests;
import org.thoughtcrime.securesms.notifications.MessageNotifier;

View File

@ -13,9 +13,9 @@ import android.support.v4.app.Fragment;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
import org.thoughtcrime.securesms.loki.redesign.activities.LandingActivity;
import org.thoughtcrime.securesms.loki.redesign.activities.SeedActivity;
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
import org.thoughtcrime.securesms.loki.activities.LandingActivity;
import org.thoughtcrime.securesms.loki.activities.SeedActivity;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.TextSecurePreferences;

View File

@ -19,6 +19,8 @@ package org.thoughtcrime.securesms;
import android.content.Intent;
import android.os.Bundle;
import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment;
import java.util.ArrayList;
import java.util.List;

View File

@ -618,7 +618,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
unidentifiedAccessKey, universalUnidentifiedAccess);
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);
accountManager.setPreKeys(identityKey.getPublicKey(), signedPreKey, records);

View File

@ -29,19 +29,19 @@ import android.os.Process;
import android.provider.OpenableColumns;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import org.thoughtcrime.securesms.components.SearchToolbar;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
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.mms.PartAuthority;
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.FileUtils;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.io.FileInputStream;
@ -68,7 +67,7 @@ import network.loki.messenger.R;
* @author Jake McGinty
*/
public class ShareActivity extends PassphraseRequiredActionBarActivity
implements ContactSelectionListFragment.OnContactSelectedListener, SwipeRefreshLayout.OnRefreshListener
implements ContactSelectionListFragment.OnContactSelectedListener
{
private static final String TAG = ShareActivity.class.getSimpleName();
@ -96,14 +95,10 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
@Override
protected void onCreate(Bundle icicle, boolean ready) {
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE,
TextSecurePreferences.isSmsEnabled(this)
? DisplayMode.FLAG_ALL
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_GROUPS);
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_ALL);
}
getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false);
getIntent().putExtra(ContactSelectionListFragment.RECENTS, true);
setContentView(R.layout.share_activity);
@ -170,7 +165,6 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
searchAction = findViewById(R.id.search_action);
contactsFragment = (ContactSelectionListFragment) getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment);
contactsFragment.setOnContactSelectedListener(this);
contactsFragment.setOnRefreshListener(this);
}
private void initializeSearch() {
@ -281,12 +275,6 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
@Override
public void onContactDeselected(String number) {
}
@Override
public void onRefresh() {
}
@SuppressLint("StaticFieldLeak")

View File

@ -11,7 +11,7 @@ import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
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.util.CommunicationActions;

View File

@ -80,7 +80,7 @@ public class AvatarImageView extends AppCompatImageView {
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setOval(0, 0, view.getWidth(), view.getHeight());
outline.setOval(0, 0, view.getWidth(), view.getHeight());
}
});
setClipToOutline(true);
@ -132,11 +132,11 @@ public class AvatarImageView extends AppCompatImageView {
if (photo.contactPhoto != null) {
requestManager.load(photo.contactPhoto)
.fallback(fallbackContactPhotoDrawable)
.error(fallbackContactPhotoDrawable)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.circleCrop()
.into(this);
.fallback(fallbackContactPhotoDrawable)
.error(fallbackContactPhotoDrawable)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.circleCrop()
.into(this);
} else {
setImageDrawable(fallbackContactPhotoDrawable);
}
@ -184,9 +184,9 @@ public class AvatarImageView extends AppCompatImageView {
if (other == null) return false;
return other.recipient.equals(recipient) &&
other.recipient.getColor().equals(recipient.getColor()) &&
other.ready == ready &&
Objects.equals(other.contactPhoto, contactPhoto);
other.recipient.getColor().equals(recipient.getColor()) &&
other.ready == ready &&
Objects.equals(other.contactPhoto, contactPhoto);
}
}
}

View File

@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.conversation.ConversationStickerSuggestionAdap
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
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.GlideRequests;
import org.thoughtcrime.securesms.mms.QuoteModel;

View File

@ -75,7 +75,6 @@ public class LinkPreviewView extends FrameLayout {
container.setBackgroundColor(Color.TRANSPARENT);
container.setPadding(0, 0, 0, 0);
divider.setVisibility(VISIBLE);
// closeButton.setVisibility(VISIBLE);
closeButton.setOnClickListener(v -> {
if (closeClickedListener != null) {

View File

@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
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;

View File

@ -108,11 +108,7 @@ public class SendButton extends AppCompatImageButton
@Override
public boolean onLongClick(View v) {
// if (isEnabled() && transportOptions.getEnabledTransports().size() > 1) {
// getTransportOptionsPopup().display(transportOptions.getEnabledTransports());
// return true;
// }
// Loki - Do nothing
return false;
}
}

View File

@ -200,7 +200,6 @@ public class TransferControlView extends FrameLayout {
if (view != null) {
view.setVisibility(VISIBLE);
// setVisibility(VISIBLE);
} else {
setVisibility(GONE);
}

View File

@ -9,17 +9,16 @@ import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.jobs.TypingSendJob;
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import kotlin.Unit;
@SuppressLint("UseSparseArrays")
public class TypingStatusSender {
@ -82,24 +81,17 @@ public class TypingStatusSender {
}
private void sendTyping(long threadId, boolean typingStarted) {
LokiFileServerAPI storageAPI = LokiFileServerAPI.Companion.getShared();
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
Recipient recipient = threadDatabase.getRecipientForThreadId(threadId);
if (recipient == null) {
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(threadId, typingStarted));
return;
// Loki - Check whether we want to send a typing indicator to this user
if (!SessionMetaProtocol.shouldSendTypingIndicator(recipient, context)) { return; }
// Loki - Take into account multi device
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.getAddress().serialize());
for (String device : linkedDevices) {
Recipient deviceAsRecipient = Recipient.from(context, Address.fromSerialized(device), false);
long deviceThreadID = threadDatabase.getThreadIdFor(deviceAsRecipient);
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(deviceThreadID, typingStarted));
}
LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(recipient.getAddress().serialize()).success(devices -> {
for (String device : devices) {
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));
}
}
return Unit.INSTANCE;
});
}
private class StartRunnable implements Runnable {

View File

@ -8,9 +8,9 @@ import android.provider.Telephony;
import android.view.View;
import android.view.View.OnClickListener;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import network.loki.messenger.R;
public class DefaultSmsReminder extends Reminder {
@ -40,14 +40,5 @@ public class DefaultSmsReminder extends Reminder {
public static boolean isEligible(Context context) {
return false;
// Loki - Original code
// ========
// final boolean isDefault = Util.isDefaultSmsProvider(context);
// if (isDefault) {
// TextSecurePreferences.setPromptedDefaultSmsProvider(context, false);
// }
//
// return !isDefault && !TextSecurePreferences.hasPromptedDefaultSmsProvider(context);
// ========
}
}

View File

@ -4,9 +4,9 @@ import android.content.Context;
import android.content.Intent;
import android.view.View.OnClickListener;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.RegistrationActivity;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import network.loki.messenger.R;
public class PushRegistrationReminder extends Reminder {
@ -30,9 +30,5 @@ public class PushRegistrationReminder extends Reminder {
public static boolean isEligible(Context context) {
return false;
// Loki - Original code
// ========
// return !TextSecurePreferences.isPushRegistered(context);
// ========
}
}

View File

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

View File

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

View File

@ -139,7 +139,6 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.MmsSmsColumns.Types;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.identity.IdentityRecordList;
import org.thoughtcrime.securesms.database.model.MessageRecord;
@ -155,16 +154,17 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.LokiThreadDatabaseDelegate;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.redesign.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.loki.redesign.views.MentionCandidateSelectionView;
import org.thoughtcrime.securesms.loki.redesign.views.SessionRestoreBannerView;
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabaseDelegate;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol;
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView;
import org.thoughtcrime.securesms.loki.views.SessionRestoreBannerView;
import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
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.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.ExpirationUtil;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.MediaUtil;
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.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLink;
import org.whispersystems.signalservice.loki.api.LokiAPI;
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus;
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus;
import org.whispersystems.signalservice.loki.messaging.Mention;
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat;
import org.whispersystems.signalservice.loki.protocol.mentions.Mention;
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager;
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol;
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus;
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
import java.io.IOException;
@ -242,7 +240,6 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@ -326,7 +323,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private MenuItem searchViewItem;
private ProgressBar messageStatusProgressBar;
private ImageView muteIndicatorImageView;
private TextView subtitleTextView;
private TextView subtitleTextView;
private AttachmentTypeSelector attachmentTypeSelector;
private AttachmentManager attachmentManager;
@ -357,7 +354,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private final DynamicNoActionBarTheme dynamicTheme = new DynamicNoActionBarTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
// Message Status Bar
// Message status bar
private ArrayList<BroadcastReceiver> broadcastReceivers = new ArrayList<>();
private String messageStatus = null;
@ -368,9 +365,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private ArrayList<Mention> mentions = new ArrayList<>();
private String oldText = "";
// Multi Device
private boolean isFriendsWithAnyDevice = false;
// Restoration
protected SessionRestoreBannerView sessionRestoreBannerView;
@ -458,7 +452,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
});
sessionRestoreBannerView.setOnRestore(() -> {
this.restoreSession();
SessionManagementProtocol.startSessionReset(this, recipient, threadId);
updateSessionRestoreBanner();
return Unit.INSTANCE;
});
sessionRestoreBannerView.setOnDismiss(() -> {
@ -468,7 +463,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
return Unit.INSTANCE;
});
LokiAPIUtilities.INSTANCE.populateUserHexEncodedPublicKeyCacheIfNeeded(threadId, this);
MentionManagerUtilities.INSTANCE.populateUserHexEncodedPublicKeyCacheIfNeeded(threadId, this);
LokiPublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
if (publicChat != null) {
@ -559,6 +554,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
markThreadAsRead();
DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this);
updateInputPanel();
updateSessionRestoreBanner();
@ -665,9 +661,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
*/
case PICK_GIF:
setMedia(data.getData(),
MediaType.GIF,
data.getIntExtra(GiphyActivity.EXTRA_WIDTH, 0),
data.getIntExtra(GiphyActivity.EXTRA_HEIGHT, 0));
MediaType.GIF,
data.getIntExtra(GiphyActivity.EXTRA_WIDTH, 0),
data.getIntExtra(GiphyActivity.EXTRA_HEIGHT, 0));
break;
case SMS_DEFAULT:
initializeSecurity(isSecureText, isDefaultSms);
@ -747,7 +743,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
MenuInflater inflater = this.getMenuInflater();
menu.clear();
boolean isOpenGroupOrRSSFeed = recipient.getAddress().isPublicChat() || recipient.getAddress().isRSSFeed();
boolean isOpenGroupOrRSSFeed = recipient.getAddress().isOpenGroup() || recipient.getAddress().isRSSFeed();
if (isSecureText && !isOpenGroupOrRSSFeed) {
if (recipient.getExpireMessages() > 0) {
@ -887,7 +883,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
case R.id.menu_invite: handleInviteLink(); return true;
case R.id.menu_mute_notifications: handleMuteNotifications(); return true;
case R.id.menu_unmute_notifications: handleUnmuteNotifications(); return true;
// case R.id.menu_conversation_settings: handleConversationSettings(); return true;
// case R.id.menu_conversation_settings: handleConversationSettings(); return true;
case R.id.menu_expiring_messages_off:
case R.id.menu_expiring_messages: handleSelectMessageExpiration(); return true;
case android.R.id.home: handleReturnToConversationList(); return true;
@ -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.setPositiveButton(R.string.yes, (dialog, which) -> {
Recipient groupRecipient = getRecipient();
if (GroupUtil.leaveGroup(this, groupRecipient)) {
if (ClosedGroupsProtocol.leaveGroup(this, groupRecipient)) {
initializeEnabledCheck();
} else {
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() {
return !recipient.getAddress().isGroup();
// if (recipient.getContactUri() != null) {
// ContactsContract.QuickContact.showQuickContact(ConversationActivity.this, titleView, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
// } else {
// handleAddToContacts();
// }
/*
if (recipient.getContactUri() != null) {
ContactsContract.QuickContact.showQuickContact(ConversationActivity.this, titleView, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
} else {
handleAddToContacts();
}
*/
}
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);
if (devices.size() > 0) {
sessionRestoreBannerView.update(recipient);
@ -1617,30 +1615,30 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void initializeViews() {
titleTextView = findViewById(R.id.titleTextView);
buttonToggle = ViewUtil.findById(this, R.id.button_toggle);
sendButton = ViewUtil.findById(this, R.id.send_button);
attachButton = ViewUtil.findById(this, R.id.attach_button);
composeText = ViewUtil.findById(this, R.id.embedded_text_editor);
charactersLeft = ViewUtil.findById(this, R.id.space_left);
emojiDrawerStub = ViewUtil.findStubById(this, R.id.emoji_drawer_stub);
unblockButton = ViewUtil.findById(this, R.id.unblock_button);
makeDefaultSmsButton = ViewUtil.findById(this, R.id.make_default_sms_button);
registerButton = ViewUtil.findById(this, R.id.register_button);
container = ViewUtil.findById(this, R.id.layout_container);
reminderView = ViewUtil.findStubById(this, R.id.reminder_stub);
unverifiedBannerView = ViewUtil.findStubById(this, R.id.unverified_banner_stub);
groupShareProfileView = ViewUtil.findStubById(this, R.id.group_share_profile_view_stub);
quickAttachmentToggle = ViewUtil.findById(this, R.id.quick_attachment_toggle);
inlineAttachmentToggle = ViewUtil.findById(this, R.id.inline_attachment_container);
inputPanel = ViewUtil.findById(this, R.id.bottom_panel);
searchNav = ViewUtil.findById(this, R.id.conversation_search_nav);
titleTextView = findViewById(R.id.titleTextView);
buttonToggle = ViewUtil.findById(this, R.id.button_toggle);
sendButton = ViewUtil.findById(this, R.id.send_button);
attachButton = ViewUtil.findById(this, R.id.attach_button);
composeText = ViewUtil.findById(this, R.id.embedded_text_editor);
charactersLeft = ViewUtil.findById(this, R.id.space_left);
emojiDrawerStub = ViewUtil.findStubById(this, R.id.emoji_drawer_stub);
unblockButton = ViewUtil.findById(this, R.id.unblock_button);
makeDefaultSmsButton = ViewUtil.findById(this, R.id.make_default_sms_button);
registerButton = ViewUtil.findById(this, R.id.register_button);
container = ViewUtil.findById(this, R.id.layout_container);
reminderView = ViewUtil.findStubById(this, R.id.reminder_stub);
unverifiedBannerView = ViewUtil.findStubById(this, R.id.unverified_banner_stub);
groupShareProfileView = ViewUtil.findStubById(this, R.id.group_share_profile_view_stub);
quickAttachmentToggle = ViewUtil.findById(this, R.id.quick_attachment_toggle);
inlineAttachmentToggle = ViewUtil.findById(this, R.id.inline_attachment_container);
inputPanel = ViewUtil.findById(this, R.id.bottom_panel);
searchNav = ViewUtil.findById(this, R.id.conversation_search_nav);
mentionCandidateSelectionViewContainer = ViewUtil.findById(this, R.id.mentionCandidateSelectionViewContainer);
mentionCandidateSelectionView = ViewUtil.findById(this, R.id.userSelectionView);
sessionRestoreBannerView = ViewUtil.findById(this, R.id.sessionRestoreBannerView);
messageStatusProgressBar = ViewUtil.findById(this, R.id.messageStatusProgressBar);
muteIndicatorImageView = ViewUtil.findById(this, R.id.muteIndicatorImageView);
subtitleTextView = ViewUtil.findById(this, R.id.subtitleTextView);
mentionCandidateSelectionView = ViewUtil.findById(this, R.id.userSelectionView);
sessionRestoreBannerView = ViewUtil.findById(this, R.id.sessionRestoreBannerView);
messageStatusProgressBar = ViewUtil.findById(this, R.id.messageStatusProgressBar);
muteIndicatorImageView = ViewUtil.findById(this, R.id.muteIndicatorImageView);
subtitleTextView = ViewUtil.findById(this, R.id.subtitleTextView);
ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle);
ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button);
@ -1897,15 +1895,21 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
case AttachmentTypeSelector.TAKE_PHOTO:
attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
case AttachmentTypeSelector.ADD_GIF:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Search GIFs?");
builder.setMessage("You will not have full metadata protection when sending GIFs.");
builder.setPositiveButton("OK", (dialog, which) -> {
boolean hasSeenGIFMetaDataWarning = TextSecurePreferences.hasSeenGIFMetaDataWarning(this);
if (!hasSeenGIFMetaDataWarning) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Search GIFs?");
builder.setMessage("You will not have full metadata protection when sending GIFs.");
builder.setPositiveButton("OK", (dialog, which) -> {
AttachmentManager.selectGif(this, PICK_GIF, !isSecureText);
dialog.dismiss();
});
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss());
builder.create().show();
TextSecurePreferences.setHasSeenGIFMetaDataWarning(this);
} else {
AttachmentManager.selectGif(this, PICK_GIF, !isSecureText);
dialog.dismiss();
});
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss() );
builder.create().show();
}
break;
}
}
@ -2073,7 +2077,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
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().setVisibility(View.GONE); // Loki - Always hide for now
} else if (groupShareProfileView.resolved()) {
@ -2249,72 +2253,39 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
public void handleThreadFriendRequestStatusChanged(long threadID) {
if (threadID != this.threadId) {
Recipient threadRecipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID);
if (threadRecipient != null && !threadRecipient.isGroupRecipient()) {
LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(threadRecipient.getAddress().serialize()).success(devices -> {
// We should update our input if this thread is a part of the other threads device
if (devices.contains(recipient.getAddress().serialize())) {
this.updateInputPanel();
}
return Unit.INSTANCE;
});
}
return;
if (recipient.isGroupRecipient()) { return; }
boolean isUpdateNeeded = false;
if (threadID == this.threadId) {
isUpdateNeeded = true;
} else {
String thisThreadPublicKey = recipient.getAddress().serialize();
Set<String> thisThreadAssociatedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(thisThreadPublicKey);
Recipient changedThreadRecipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID);
String changedThreadPublicKey = changedThreadRecipient.getAddress().serialize();
for (String device : thisThreadAssociatedDevices) {
if (device.equals(changedThreadPublicKey)) { isUpdateNeeded = true; }
}
this.updateInputPanel();
}
if (isUpdateNeeded) {
updateInputPanel();
}
}
@Override
public void handleSessionRestoreDevicesChanged(long threadId) {
if (threadId == this.threadId) {
public void handleSessionRestoreDevicesChanged(long threadID) {
if (threadID == this.threadId) {
runOnUiThread(this::updateSessionRestoreBanner);
}
}
private void updateInputPanel() {
/*
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) {
boolean shouldInputPanelBeEnabled = FriendRequestProtocol.shouldInputPanelBeEnabled(this, recipient);
Util.runOnMain(() -> {
updateToggleButtonState();
String hint = enabled ? "Message" : "Pending session request";
String hint = shouldInputPanelBeEnabled ? "Message" : "Pending session request";
inputPanel.setHint(hint);
inputPanel.setEnabled(enabled);
if (enabled && inputPanel.getVisibility() == View.VISIBLE) {
inputPanel.setEnabled(shouldInputPanelBeEnabled);
if (shouldInputPanelBeEnabled && inputPanel.getVisibility() == View.VISIBLE) {
inputPanel.composeText.requestFocus();
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.showSoftInput(inputPanel.composeText, 0);
@ -2370,7 +2341,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
Log.w(TAG, ex);
}
if (messageStatus == null && !isGroupConversation()) {
if (messageStatus == null && !isGroupConversation() && !SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize())) {
messageStatus = "calculatingPoW";
updateSubtitleTextView();
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
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) {
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
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("");
final long id = fragment.stageOutgoingMessage(message);
@ -2508,8 +2481,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void updateToggleButtonState() {
// Don't allow attachments if we're not friends with any of the user's devices
if (!isNoteToSelf() && !recipient.isGroupRecipient() && !isFriendsWithAnyDevice) {
if (!FriendRequestProtocol.shouldAttachmentButtonBeEnabled(this, recipient)) {
buttonToggle.display(sendButton);
quickAttachmentToggle.hide();
inlineAttachmentToggle.hide();
@ -2745,7 +2717,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private void silentlySetComposeText(String text) {
typingTextWatcher.setEnabled(false);
composeText.setText(text);
if (text.isEmpty()) resetMentions();
if (text.isEmpty()) { resetMentions(); }
typingTextWatcher.setEnabled(true);
}
@ -2905,7 +2877,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
LokiThreadDatabase threadDatabase = DatabaseFactory.getLokiThreadDatabase(ConversationActivity.this);
LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(ConversationActivity.this);
if (lastCharacter == '@' && Character.isWhitespace(secondToLastCharacter)) {
List<Mention> mentionCandidates = LokiAPI.Companion.getMentionCandidates("", threadId, userHexEncodedPublicKey, threadDatabase, userDatabase);
List<Mention> mentionCandidates = MentionsManager.shared.getMentionCandidates("", threadId);
currentMentionStartIndex = lastCharacterIndex;
mentionCandidateSelectionViewContainer.setVisibility(View.VISIBLE);
mentionCandidateSelectionView.show(mentionCandidates, threadId);
@ -2916,7 +2888,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} else {
if (currentMentionStartIndex != -1) {
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);
mentionCandidateSelectionView.show(mentionCandidates, threadId);
}
@ -2960,12 +2932,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
inputPanel.setQuote(GlideApp.with(this),
messageRecord.getDateSent(),
author,
body,
slideDeck,
recipient,
threadId);
messageRecord.getDateSent(),
author,
body,
slideDeck,
recipient,
threadId);
} else if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) {
LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0);
@ -2976,20 +2948,20 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
inputPanel.setQuote(GlideApp.with(this),
messageRecord.getDateSent(),
author,
messageRecord.getBody(),
slideDeck,
recipient,
threadId);
messageRecord.getDateSent(),
author,
messageRecord.getBody(),
slideDeck,
recipient,
threadId);
} else {
inputPanel.setQuote(GlideApp.with(this),
messageRecord.getDateSent(),
author,
messageRecord.getBody(),
messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(),
recipient,
threadId);
messageRecord.getDateSent(),
author,
messageRecord.getBody(),
messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(),
recipient,
threadId);
}
}
@ -3106,17 +3078,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
// region Loki
private void updateTitleTextView(Recipient recipient) {
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
Set<DeviceLink> deviceLinks = DatabaseFactory.getLokiAPIDatabase(this).getDeviceLinks(userHexEncodedPublicKey);
HashSet<String> userLinkedDeviceHexEncodedPublicKeys = new HashSet<>();
for (DeviceLink deviceLink : deviceLinks) {
userLinkedDeviceHexEncodedPublicKeys.add(deviceLink.getMasterHexEncodedPublicKey().toLowerCase());
userLinkedDeviceHexEncodedPublicKeys.add(deviceLink.getSlaveHexEncodedPublicKey().toLowerCase());
}
userLinkedDeviceHexEncodedPublicKeys.add(userHexEncodedPublicKey.toLowerCase());
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
Set<String> allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey);
if (recipient == null) {
titleTextView.setText("Compose");
} else if (userLinkedDeviceHexEncodedPublicKeys.contains(recipient.getAddress().toString().toLowerCase())) {
} else if (allUserDevices.contains(recipient.getAddress().toString().toLowerCase())) {
titleTextView.setText("Note to Self");
} else {
boolean hasName = (recipient.getName() != null && !recipient.getName().isEmpty());
@ -3192,7 +3158,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void handleMessageStatusChanged(String newMessageStatus, long timestamp) {
if (timestamp == 0) { return; }
if (timestamp == 0 || SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize()) ) { return; }
updateForNewMessageStatusIfNeeded(newMessageStatus, timestamp);
if (newMessageStatus.equals("messageFailed") || newMessageStatus.equals("messageSent")) {
new Handler().postDelayed(() -> clearMessageStatusIfNeeded(timestamp), 1000);
@ -3232,48 +3198,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
public void acceptFriendRequest(@NotNull MessageRecord friendRequest) {
// Send the accept to the original friend request thread ID
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(this);
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);
if (recipient.isGroupRecipient()) { return; }
FriendRequestProtocol.acceptFriendRequest(this, recipient);
updateInputPanel();
}
@Override
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; }
LokiThreadDatabase lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(this);
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(this);
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();
FriendRequestProtocol.rejectFriendRequest(this, recipient);
updateInputPanel();
}
// endregion
}

View File

@ -40,7 +40,7 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.redesign.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;

View File

@ -79,7 +79,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.redesign.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mms.GlideApp;
@ -101,8 +101,8 @@ import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI;
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI;
import java.io.IOException;
import java.io.InputStream;
@ -375,9 +375,9 @@ public class ConversationFragment extends Fragment
}
if (messageRecords.size() > 1) {
// menu.findItem(R.id.menu_context_forward).setVisible(false);
// menu.findItem(R.id.menu_context_forward).setVisible(false);
menu.findItem(R.id.menu_context_reply).setVisible(false);
// menu.findItem(R.id.menu_context_details).setVisible(false);
// menu.findItem(R.id.menu_context_details).setVisible(false);
menu.findItem(R.id.menu_context_save_attachment).setVisible(false);
menu.findItem(R.id.menu_context_resend).setVisible(false);
} else {
@ -726,7 +726,7 @@ public class ConversationFragment extends Fragment
}
if (!loader.hasSent() && !recipient.isSystemContact() && !recipient.isGroupRecipient() && recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
// adapter.setHeaderView(unknownSenderView);
// adapter.setHeaderView(unknownSenderView);
} else {
clearHeaderIfNotTyping(adapter);
}

View File

@ -86,11 +86,11 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.redesign.utilities.MentionUtilities;
import org.thoughtcrime.securesms.loki.redesign.views.FriendRequestView;
import org.thoughtcrime.securesms.loki.redesign.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView;
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.utilities.MentionUtilities;
import org.thoughtcrime.securesms.loki.views.FriendRequestView;
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.loki.views.ProfilePictureView;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.ImageSlide;
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.views.Stub;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI;
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI;
import java.util.Collections;
import java.util.HashSet;

View File

@ -49,8 +49,6 @@ public class ConversationPopupActivity extends ConversationActivity {
else getWindow().setLayout((int) (width * .7), (int) (height * .75));
super.onCreate(bundle, ready);
// titleView.setOnClickListener(null);
}
@Override

View File

@ -105,16 +105,16 @@ public class ConversationUpdateItem extends LinearLayout
this.sender.addListener(this);
if (messageRecord.isGroupAction()) setGroupRecord(messageRecord);
else if (messageRecord.isCallLog()) setCallRecord(messageRecord);
else if (messageRecord.isJoined()) setJoinedRecord(messageRecord);
else if (messageRecord.isExpirationTimerUpdate()) setTimerRecord(messageRecord);
else if (messageRecord.isEndSession()) setEndSessionRecord(messageRecord);
else if (messageRecord.isIdentityUpdate()) setIdentityRecord(messageRecord);
if (messageRecord.isGroupAction()) setGroupRecord(messageRecord);
else if (messageRecord.isCallLog()) setCallRecord(messageRecord);
else if (messageRecord.isJoined()) setJoinedRecord(messageRecord);
else if (messageRecord.isExpirationTimerUpdate()) setTimerRecord(messageRecord);
else if (messageRecord.isEndSession()) setEndSessionRecord(messageRecord);
else if (messageRecord.isIdentityUpdate()) setIdentityRecord(messageRecord);
else if (messageRecord.isIdentityVerified() ||
messageRecord.isIdentityDefault()) setIdentityVerifyUpdate(messageRecord);
messageRecord.isIdentityDefault()) setIdentityVerifyUpdate(messageRecord);
else if (messageRecord.isLokiSessionRestoreSent()) setTextMessageRecord(messageRecord);
else throw new AssertionError("Neither group nor log nor joined.");
else throw new AssertionError("Neither group nor log nor joined.");
if (batchSelected.contains(messageRecord)) setSelected(true);
else setSelected(false);

View File

@ -43,7 +43,7 @@ public class PreKeyUtil {
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);
List<PreKeyRecord> records = new LinkedList<>();
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<>();
int preKeyIDOffset = TextSecurePreferences.getNextPreKeyId(context);
for (int i = 0; i < amount; i++) {

View File

@ -9,22 +9,15 @@ import android.support.annotation.WorkerThread;
import org.signal.libsignal.metadata.SignalProtos;
import org.signal.libsignal.metadata.certificate.CertificateValidator;
import org.signal.libsignal.metadata.certificate.InvalidCertificateException;
import network.loki.messenger.BuildConfig;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
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.signalservice.api.crypto.UnidentifiedAccess;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import java.io.IOException;
public class UnidentifiedAccessUtil {
private static final String TAG = UnidentifiedAccessUtil.class.getSimpleName();
@ -116,9 +109,9 @@ public class UnidentifiedAccessUtil {
String ourNumber = TextSecurePreferences.getLocalNumber(context);
if (ourNumber != null) {
SignalProtos.SenderCertificate certificate = SignalProtos.SenderCertificate.newBuilder()
.setSender(ourNumber)
.setSenderDevice(SignalServiceAddress.DEFAULT_DEVICE_ID)
.build();
.setSender(ourNumber)
.setSenderDevice(SignalServiceAddress.DEFAULT_DEVICE_ID)
.build();
return certificate.toByteArray();
}

View File

@ -105,11 +105,11 @@ public class Address implements Parcelable, Comparable<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); }
@ -127,7 +127,7 @@ public class Address implements Parcelable, Comparable<Address> {
}
public @NonNull String toPhoneString() {
if (!isPhone() && !isPublicChat()) {
if (!isPhone() && !isOpenGroup()) {
if (isEmail()) throw new AssertionError("Not e164, is email");
if (isGroup()) throw new AssertionError("Not e164, is group");
throw new AssertionError("Not e164, unknown");

View File

@ -31,11 +31,12 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.helpers.ClassicOpenHelper;
import org.thoughtcrime.securesms.database.helpers.SQLCipherMigrationHelper;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.loki.*;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyBundleDatabase;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyRecordDatabase;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.database.LokiPreKeyBundleDatabase;
import org.thoughtcrime.securesms.loki.database.LokiPreKeyRecordDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
public class DatabaseFactory {

View File

@ -160,14 +160,15 @@ public class GroupDatabase extends Database {
return recipients;
}
public boolean signalGroupsHaveMember(String hexEncodedPublicKey) {
public boolean isClosedGroupMember(String hexEncodedPublicKey) {
try {
Address address = Address.fromSerialized(hexEncodedPublicKey);
Reader reader = DatabaseFactory.getGroupDatabase(context).getGroups();
GroupRecord record;
while ((record = reader.getNext()) != null) {
if (record.isSignalGroup() && record.members.contains(address)) {
return true;
if (record.isClosedGroup() && record.members.contains(address)) {
return true;
}
}
@ -292,8 +293,7 @@ public class GroupDatabase extends Database {
contents.put(ADMINS, Address.toSerializedList(admins, ','));
contents.put(ACTIVE, 1);
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
new String[] {groupId});
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", new String[] {groupId});
}
public void remove(String groupId, Address source) {
@ -489,11 +489,11 @@ public class GroupDatabase extends Database {
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 isSignalGroup() { return Address.fromSerialized(id).isSignalGroup(); }
public boolean isClosedGroup() { return Address.fromSerialized(id).isClosedGroup(); }
public String getUrl() { return url; }

View File

@ -47,7 +47,6 @@ import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@ -252,7 +251,7 @@ public class SmsDatabase extends MessagingDatabase {
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);
}
@ -342,12 +341,12 @@ public class SmsDatabase extends MessagingDatabase {
try {
cursor = database.query(TABLE_NAME, new String[] { ID, THREAD_ID, ADDRESS, TYPE },
DATE_SENT + " = ?", new String[] { String.valueOf(timestamp) },
null, null, null, null);
DATE_SENT + " = ?", new String[] { String.valueOf(timestamp) },
null, null, null, null);
while (cursor.moveToNext()) {
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(TYPE)))) {
isOutgoing = true;
isOutgoing = true;
}
}
} finally {

View File

@ -537,7 +537,7 @@ public class ThreadDatabase extends Database {
}
public @Nullable Recipient getRecipientForThreadId(long threadId) {
// Loki - Cache the address.
// Loki - Cache the address
if (addressCache.containsKey(threadId) && addressCache.get(threadId) != null) {
return Recipient.from(context, addressCache.get(threadId), false);
}

View File

@ -35,17 +35,17 @@ import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyBundleDatabase;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyRecordDatabase;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.database.LokiPreKeyBundleDatabase;
import org.thoughtcrime.securesms.loki.database.LokiPreKeyRecordDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.GroupUtil;
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;
@ -81,8 +81,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int lokiV5 = 26;
private static final int lokiV6 = 27;
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 final Context context;
@ -138,6 +139,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL(LokiAPIDatabase.getCreateLastDeletionServerIDTableCommand());
db.execSQL(LokiAPIDatabase.getCreateDeviceLinkTableCommand());
db.execSQL(LokiAPIDatabase.getCreateUserCountTableCommand());
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampTableCommand());
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
db.execSQL(LokiMessageDatabase.getCreateMessageFriendRequestTableCommand());
@ -181,8 +183,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
@Override
public void onConfigure(SQLiteDatabase db) {
super.onConfigure(db);
// Loki: Enable Write Ahead Logging Mode, increase the cache size
// This should be disabled if we ever run into serious race condition bugs
// Loki - Enable write ahead logging mode and increase the cache size.
// This should be disabled if we ever run into serious race condition bugs.
db.enableWriteAheadLogging();
db.execSQL("PRAGMA cache_size = 10000");
}
@ -544,7 +546,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
if (publicChat != null) {
byte[] groupId = publicChat.getId().getBytes();
String oldId = GroupUtil.getEncodedId(groupId, false);
String newId = GroupUtil.getEncodedPublicChatId(groupId);
String newId = GroupUtil.getEncodedOpenGroupId(groupId);
ContentValues threadUpdate = new ContentValues();
threadUpdate.put("recipient_ids", newId);
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" };
for (String groupId : rssFeedIds) {
String oldId = GroupUtil.getEncodedId(groupId.getBytes(), false);
@ -576,6 +578,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand());
}
if (oldVersion < lokiV8) {
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampTableCommand());
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();

View File

@ -8,11 +8,11 @@ import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.devicelist.Device;
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.TextSecurePreferences;
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec;
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
import java.io.File;
import java.util.Collections;
@ -33,9 +33,9 @@ public class DeviceListLoader extends AsyncLoader<List<Device>> {
@Override
public List<Device> loadInBackground() {
try {
String ourPublicKey = TextSecurePreferences.getLocalNumber(getContext());
Set<String> secondaryDevicePublicKeys = LokiDeviceLinkUtilities.INSTANCE.getSlaveHexEncodedPublicKeys(ourPublicKey).get();
List<Device> devices = Stream.of(secondaryDevicePublicKeys).map(this::mapToDevice).toList();
String userPublicKey = TextSecurePreferences.getLocalNumber(getContext());
Set<String> slaveDevicePublicKeys = MultiDeviceProtocol.shared.getSlaveDevices(userPublicKey);
List<Device> devices = Stream.of(slaveDevicePublicKeys).map(this::mapToDevice).toList();
Collections.sort(devices, new DeviceComparator());
return devices;
} catch (Exception e) {

View File

@ -21,7 +21,6 @@ import android.content.Context;
import android.support.annotation.NonNull;
import android.text.SpannableString;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.database.MmsSmsColumns;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
@ -30,6 +29,8 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.LinkedList;
import java.util.List;
import network.loki.messenger.R;
/**
* The message record model which represents standard SMS messages.
*
@ -67,9 +68,9 @@ public class SmsMessageRecord extends MessageRecord {
int readReceiptCount, boolean unidentified, boolean isFriendRequest)
{
super(id, body, recipient, individualRecipient, recipientDeviceId,
dateSent, dateReceived, threadId, status, deliveryReceiptCount, type,
mismatches, new LinkedList<>(), subscriptionId,
expiresIn, expireStarted, readReceiptCount, unidentified);
dateSent, dateReceived, threadId, status, deliveryReceiptCount, type,
mismatches, new LinkedList<>(), subscriptionId,
expiresIn, expireStarted, readReceiptCount, unidentified);
this.isFriendRequest = isFriendRequest;
}

View File

@ -45,9 +45,8 @@ import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
import org.thoughtcrime.securesms.jobs.TypingSendJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.LokiSessionResetImplementation;
import org.thoughtcrime.securesms.loki.MultiDeviceOpenGroupUpdateJob;
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation;
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceOpenGroupUpdateJob;
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
import org.thoughtcrime.securesms.push.MessageSenderEventListener;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
@ -112,7 +111,6 @@ import network.loki.messenger.BuildConfig;
MultiDeviceStickerPackOperationJob.class,
MultiDeviceStickerPackSyncJob.class,
LinkPreviewRepository.class,
PushMessageSyncSendJob.class,
MultiDeviceOpenGroupUpdateJob.class})
public class SignalCommunicationModule {
@ -154,6 +152,7 @@ public class SignalCommunicationModule {
Optional.fromNullable(IncomingMessageObserver.getUnidentifiedPipe()),
Optional.of(new MessageSenderEventListener(context)),
TextSecurePreferences.getLocalNumber(context),
TextSecurePreferences.getMasterHexEncodedPublicKey(context),
DatabaseFactory.getLokiAPIDatabase(context),
DatabaseFactory.getLokiThreadDatabase(context),
DatabaseFactory.getLokiMessageDatabase(context),

View File

@ -36,18 +36,18 @@ import java.util.Set;
public class GroupManager {
public static long getPublicChatThreadId(String id, @NonNull Context context) {
final String groupId = GroupUtil.getEncodedPublicChatId(id.getBytes());
return getThreadIdFromGroupId(groupId, context);
public static long getOpenGroupThreadID(String id, @NonNull Context context) {
final String groupID = GroupUtil.getEncodedOpenGroupId(id.getBytes());
return getThreadIDFromGroupID(groupID, context);
}
public static long getRSSFeedThreadId(String id, @NonNull Context context) {
final String groupId = GroupUtil.getEncodedRSSFeedId(id.getBytes());
return getThreadIdFromGroupId(groupId, context);
public static long getRSSFeedThreadID(String id, @NonNull Context context) {
final String groupID = GroupUtil.getEncodedRSSFeedId(id.getBytes());
return getThreadIDFromGroupID(groupID, context);
}
public static long getThreadIdFromGroupId(String groupId, @NonNull Context context) {
final Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupId), false);
public static long getThreadIDFromGroupID(String groupID, @NonNull Context context) {
final Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupID), false);
return DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(groupRecipient);
}
@ -78,10 +78,10 @@ public class GroupManager {
final Set<Address> memberAddresses = getMemberAddresses(members);
final Set<Address> adminAddresses = getMemberAddresses(admins);
String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
String ourNumber = masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : TextSecurePreferences.getLocalNumber(context);
String masterPublicKeyOrNull = TextSecurePreferences.getMasterHexEncodedPublicKey(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));
if (!mms) {
@ -94,28 +94,28 @@ public class GroupManager {
}
}
public static @NonNull GroupActionResult createPublicChatGroup(@NonNull String id,
@NonNull Context context,
@Nullable Bitmap avatar,
@Nullable String name)
public static @NonNull GroupActionResult createOpenGroup(@NonNull String id,
@NonNull Context context,
@Nullable Bitmap avatar,
@Nullable String name)
{
final String groupId = GroupUtil.getEncodedPublicChatId(id.getBytes());
return createLokiGroup(groupId, context, avatar, name);
final String groupID = GroupUtil.getEncodedOpenGroupId(id.getBytes());
return createLokiGroup(groupID, context, avatar, name);
}
public static @NonNull GroupActionResult createRSSFeedGroup(@NonNull String id,
@NonNull Context context,
@Nullable Bitmap avatar,
@Nullable String name)
public static @NonNull GroupActionResult createRSSFeed(@NonNull String id,
@NonNull Context context,
@Nullable Bitmap avatar,
@Nullable String name)
{
final String groupId = GroupUtil.getEncodedRSSFeedId(id.getBytes());
return createLokiGroup(groupId, context, avatar, name);
final String groupID = GroupUtil.getEncodedRSSFeedId(id.getBytes());
return createLokiGroup(groupID, context, avatar, name);
}
private static @NonNull GroupActionResult createLokiGroup(@NonNull String groupId,
@NonNull Context context,
@Nullable Bitmap avatar,
@Nullable String name)
private static @NonNull GroupActionResult createLokiGroup(@NonNull String groupId,
@NonNull Context context,
@Nullable Bitmap avatar,
@Nullable String name)
{
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
@ -127,8 +127,8 @@ public class GroupManager {
groupDatabase.updateAvatar(groupId, avatarBytes);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
return new GroupActionResult(groupRecipient, threadId);
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
return new GroupActionResult(groupRecipient, threadID);
}
public static GroupActionResult updateGroup(@NonNull Context context,

View File

@ -8,7 +8,6 @@ import android.support.annotation.Nullable;
import com.google.protobuf.ByteString;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
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.PushGroupUpdateJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.Base64;
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.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
import java.util.Collections;
import java.util.HashSet;
@ -45,8 +41,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import kotlin.Unit;
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.GroupContext;
@ -95,7 +89,7 @@ public class GroupMessageProcessor {
builder.setType(GroupContext.Type.UPDATE);
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;
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
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, TextSecurePreferences.getLocalNumber(context));
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.");
// Loki - Ignore message if needed
if (ClosedGroupsProtocol.shouldIgnoreGroupCreatedMessage(context, group)) {
return null;
}
// Loki - Parse admins
if (group.getAdmins().isPresent()) {
for (String admin : group.getAdmins().get()) {
admins.add(Address.fromExternal(context, admin));
@ -121,7 +114,7 @@ public class GroupMessageProcessor {
avatar != null && avatar.isPointer() ? avatar.asPointer() : null, null, admins);
if (group.getMembers().isPresent()) {
establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
ClosedGroupsProtocol.establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
}
return storeMessage(context, content, group, builder.build(), outgoing);
@ -137,21 +130,21 @@ public class GroupMessageProcessor {
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
String id = GroupUtil.getEncodedId(group);
String ourHexEncodedPublicKey = getMasterHexEncodedPublicKey(context, TextSecurePreferences.getLocalNumber(context));
String userMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
if (group.getGroupType() == SignalServiceGroup.GroupType.SIGNAL) {
// Only update group if the group admin sent the message
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender());
if (!groupRecord.getAdmins().contains(Address.fromSerialized(hexEncodedPublicKey))) {
Log.d("Loki - Group Message", "Received a group update message from a non-admin user for " + id +". Ignoring.");
// Loki - Only update the group if the group admin sent the message
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
if (!groupRecord.getAdmins().contains(Address.fromSerialized(masterDevice))) {
Log.d("Loki", "Received a group update message from a non-admin user for: " + id +"; ignoring.");
return null;
}
// We should only process update messages if we're in the group
Address ourAddress = Address.fromSerialized(ourHexEncodedPublicKey);
if (!groupRecord.getMembers().contains(ourAddress) &&
!group.getMembers().or(Collections.emptyList()).contains(ourHexEncodedPublicKey)) {
Log.d("Loki - Group Message", "Received a group update message from a group we are not a member of: " + id + "; ignoring.");
// Loki - Only process update messages if we're part of the group
Address userMasterDeviceAddress = Address.fromSerialized(userMasterDevice);
if (!groupRecord.getMembers().contains(userMasterDeviceAddress) &&
!group.getMembers().or(Collections.emptyList()).contains(userMasterDevice)) {
Log.d("Loki", "Received a group update message from a group we're not a member of: " + id + "; ignoring.");
database.setActive(id, false);
return null;
}
@ -180,8 +173,8 @@ public class GroupMessageProcessor {
database.updateMembers(id, new LinkedList<>(newMembers));
}
// We 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
// 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.
for (Address addedMember : addedMembers) {
builder.addNewMembers(addedMember.serialize());
}
@ -200,13 +193,13 @@ public class GroupMessageProcessor {
}
// 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);
} else {
if (!groupRecord.isActive()) database.setActive(id, true);
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 GroupRecord record)
{
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender());
if (record.getMembers().contains(Address.fromSerialized(hexEncodedPublicKey))) {
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
if (record.getMembers().contains(Address.fromSerialized(masterDevice))) {
ApplicationContext.getInstance(context)
.getJobManager()
.add(new PushGroupUpdateJob(content.getSender(), group.getGroupId()));
@ -240,9 +233,9 @@ public class GroupMessageProcessor {
GroupContext.Builder builder = createGroupContext(group);
builder.setType(GroupContext.Type.QUIT);
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender());
if (members.contains(Address.fromExternal(context, hexEncodedPublicKey))) {
database.remove(id, Address.fromExternal(context, hexEncodedPublicKey));
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
if (members.contains(Address.fromExternal(context, masterDevice))) {
database.remove(id, Address.fromExternal(context, masterDevice));
if (outgoing) database.setActive(id, false);
return storeMessage(context, content, group, builder.build(), outgoing);
@ -322,32 +315,4 @@ public class GroupMessageProcessor {
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;
});
}
}
}

View File

@ -196,14 +196,17 @@ public class AttachmentDownloadJob extends BaseJob implements InjectableType {
try {
long id = Long.parseLong(attachment.getLocation());
if (isPublicAttachment) {
return new SignalServiceAttachmentPointer(id, null, new byte[0],
Optional.of(Util.toIntExact(attachment.getSize())),
Optional.absent(),
0, 0,
Optional.fromNullable(attachment.getDigest()),
Optional.fromNullable(attachment.getFileName()),
attachment.isVoiceNote(),
Optional.absent(), attachment.getUrl());
return new SignalServiceAttachmentPointer(id,
null,
new byte[0],
Optional.of(Util.toIntExact(attachment.getSize())),
Optional.absent(),
0,
0,
Optional.fromNullable(attachment.getDigest()),
Optional.fromNullable(attachment.getFileName()),
attachment.isVoiceNote(),
Optional.absent(), attachment.getUrl());
}
byte[] key = Base64.decode(attachment.getKey());

View File

@ -40,7 +40,7 @@ public class CleanPreKeysJob extends BaseJob implements InjectableType {
public CleanPreKeysJob() {
this(new Job.Parameters.Builder()
.setQueue("CleanPreKeysJob")
.setMaxAttempts(5)
.setMaxAttempts(3)
.build());
}

View File

@ -13,9 +13,8 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver;
import org.thoughtcrime.securesms.loki.MultiDeviceOpenGroupUpdateJob;
import org.thoughtcrime.securesms.loki.PushBackgroundMessageSendJob;
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceOpenGroupUpdateJob;
import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob;
import java.util.Arrays;
import java.util.HashMap;
@ -71,8 +70,7 @@ public final class JobManagerFactories {
put(TrimThreadJob.KEY, new TrimThreadJob.Factory());
put(TypingSendJob.KEY, new TypingSendJob.Factory());
put(UpdateApkJob.KEY, new UpdateApkJob.Factory());
put(PushMessageSyncSendJob.KEY, new PushMessageSyncSendJob.Factory());
put(PushBackgroundMessageSendJob.KEY, new PushBackgroundMessageSendJob.Factory());
put(PushEphemeralMessageSendJob.KEY, new PushEphemeralMessageSendJob.Factory());
put(MultiDeviceOpenGroupUpdateJob.KEY, new MultiDeviceOpenGroupUpdateJob.Factory());
}};
}

View File

@ -3,11 +3,6 @@ package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.support.annotation.NonNull;
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 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.NoSuchMessageException;
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.MediaConstraints;
import org.thoughtcrime.securesms.mms.MmsException;
@ -64,7 +63,7 @@ public class MmsSendJob extends SendJob {
this(new Job.Parameters.Builder()
.setQueue("mms-operation")
.addConstraint(NetworkConstraint.KEY)
.setMaxAttempts(15)
.setMaxAttempts(25)
.build(),
messageId);
}

View File

@ -84,8 +84,7 @@ public class MultiDeviceBlockedUpdateJob extends BaseJob implements InjectableTy
}
}
// TODO: Message ID
messageSender.sendMessage(0, SignalServiceSyncMessage.forBlocked(new BlockedListMessage(blockedIndividuals, blockedGroups)),
messageSender.sendMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(blockedIndividuals, blockedGroups)),
UnidentifiedAccessUtil.getAccessForSync(context));
}
}

View File

@ -91,8 +91,7 @@ public class MultiDeviceConfigurationUpdateJob extends BaseJob implements Inject
return;
}
// TODO: Message ID
messageSender.sendMessage(0, SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(readReceiptsEnabled),
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(readReceiptsEnabled),
Optional.of(unidentifiedDeliveryIndicatorsEnabled),
Optional.of(typingIndicatorsEnabled),
Optional.of(linkPreviewsEnabled))),

View File

@ -1,21 +1,16 @@
package org.thoughtcrime.securesms.jobs;
import android.Manifest;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.contacts.ContactAccessor;
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.Database;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.IdentityDatabase;
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.impl.NetworkConstraint;
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.util.TextSecurePreferences;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.util.guava.Optional;
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.UntrustedIdentityException;
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.SignalServiceSyncMessage;
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.loki.messaging.LokiThreadFriendRequestStatus;
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
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 String KEY_ADDRESS = "address";
private static final String KEY_RECIPIENT = "recipient";
private static final String KEY_FORCE_SYNC = "force_sync";
@Inject SignalServiceMessageSender messageSender;
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;
/**
* 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) {
this(context, false);
}
public MultiDeviceContactUpdateJob(@NonNull Context context, boolean forceSync) { this(context, null, forceSync); }
/**
* Create a full contact sync job which only gets sent to `recipient`
*/
public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address recipient, boolean forceSync) {
this(context, recipient, null, forceSync);
public MultiDeviceContactUpdateJob(@NonNull Context context, boolean forceSync) {
this(context, 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) {
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()
.addConstraint(NetworkConstraint.KEY)
.setQueue("MultiDeviceContactUpdateJob")
.setLifespan(TimeUnit.DAYS.toMillis(1))
.setMaxAttempts(1)
.build(),
recipient,
address,
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);
this.forceSync = forceSync;
this.recipient = (recipient != null) ? recipient.serialize() : null;
if (address != null) this.address = address.serialize();
else this.address = null;
@ -125,7 +104,6 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
public @NonNull Data serialize() {
return new Data.Builder().putString(KEY_ADDRESS, address)
.putBoolean(KEY_FORCE_SYNC, forceSync)
.putString(KEY_RECIPIENT, recipient)
.build();
}
@ -144,14 +122,14 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
}
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)
throws IOException, UntrustedIdentityException, NetworkException
{
// Loki - Only sync regular contacts
if (!address.isPhone()) { return; }
if (!PublicKeyValidation.isValid(address.serialize())) { return; }
File contactDataFile = createTempFile("multidevice-contact-update");
@ -162,17 +140,15 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
Optional<VerifiedMessage> verifiedMessage = getVerifiedMessage(recipient, identityRecord);
// Loki - Only sync contacts we are friends with
if (getFriendRequestStatus(recipient) == LokiThreadFriendRequestStatus.FRIENDS) {
if (SyncMessagesProtocol.shouldSyncContact(context, address)) {
out.write(new DeviceContact(address.toPhoneString(),
Optional.fromNullable(recipient.getName()),
getAvatar(recipient.getContactUri()),
Optional.fromNullable(recipient.getColor().serialize()),
verifiedMessage,
Optional.fromNullable(recipient.getProfileKey()),
recipient.isBlocked(),
recipient.getExpireMessages() > 0 ?
Optional.of(recipient.getExpireMessages()) :
Optional.absent()));
Optional.fromNullable(recipient.getName()),
getAvatar(recipient.getContactUri()),
Optional.fromNullable(recipient.getColor().serialize()),
verifiedMessage,
Optional.fromNullable(recipient.getProfileKey()),
recipient.isBlocked(),
recipient.getExpireMessages() > 0 ? Optional.of(recipient.getExpireMessages()) : Optional.absent()));
}
out.close();
@ -206,7 +182,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
try {
DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile));
List<ContactData> contacts = getAllContacts();
List<ContactData> contacts = SyncMessagesProtocol.getContactsToSync(context);
for (ContactData contactData : contacts) {
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactData.id));
@ -220,10 +196,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
boolean blocked = recipient.isBlocked();
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)) {
@ -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
public boolean onShouldRetry(@NonNull Exception exception) {
// Loki - Disabled because we have our own retrying
// if (exception instanceof PushNetworkException) return true;
// Loki - Disabled since we have our own retrying
return false;
}
@ -286,13 +239,10 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
.withLength(contactsFile.length())
.build();
SignalServiceAddress messageRecipient = recipient != null ? new SignalServiceAddress(recipient) : null;
Address address = recipient != null ? Address.fromSerialized(recipient) : null;
Optional<UnidentifiedAccessPair> unidentifiedAccess = address != null ? UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, address, false)) : Optional.absent();
Optional<UnidentifiedAccessPair> unidentifiedAccess = address != null ? UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(address), false)) : Optional.absent();
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) {
throw new NetworkException(ioe);
}
@ -302,7 +252,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
private Optional<SignalServiceAttachmentStream> getAvatar(@Nullable Uri uri) throws IOException {
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) {
return Optional.absent();
}
@ -397,10 +347,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
String serialized = data.getString(KEY_ADDRESS);
Address address = serialized != null ? Address.fromSerialized(serialized) : null;
String recipientSerialized = data.getString(KEY_RECIPIENT);
Address recipient = recipientSerialized != null ? Address.fromSerialized(recipientSerialized) : null;
return new MultiDeviceContactUpdateJob(parameters, recipient, address, data.getBoolean(KEY_FORCE_SYNC));
return new MultiDeviceContactUpdateJob(parameters, address, data.getBoolean(KEY_FORCE_SYNC));
}
}
}

View File

@ -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.DeviceGroupsOutputStream;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import java.io.ByteArrayInputStream;
import java.io.File;
@ -85,7 +84,7 @@ public class MultiDeviceGroupUpdateJob extends BaseJob implements InjectableType
reader = DatabaseFactory.getGroupDatabase(context).getGroups();
while ((record = reader.getNext()) != null) {
if (record.isSignalGroup()) {
if (record.isClosedGroup()) {
List<String> members = new LinkedList<>();
List<String> admins = new LinkedList<>();
@ -125,8 +124,7 @@ public class MultiDeviceGroupUpdateJob extends BaseJob implements InjectableType
@Override
public boolean onShouldRetry(@NonNull Exception exception) {
// Loki - Disabled because we have our own retrying
// if (exception instanceof PushNetworkException) return true;
// Loki - Disabled since we have our own retrying
return false;
}
@ -145,7 +143,7 @@ public class MultiDeviceGroupUpdateJob extends BaseJob implements InjectableType
.withLength(contactsFile.length())
.build();
messageSender.sendMessage(0, SignalServiceSyncMessage.forGroups(attachmentStream),
messageSender.sendMessage(SignalServiceSyncMessage.forGroups(attachmentStream),
UnidentifiedAccessUtil.getAccessForSync(context));
}

View File

@ -87,10 +87,9 @@ public class MultiDeviceProfileKeyUpdateJob extends BaseJob implements Injectabl
.withLength(baos.toByteArray().length)
.build();
SignalServiceSyncMessage syncMessage = SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, false));
SignalServiceSyncMessage syncMessage = SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, false));
// TODO: Message ID
messageSender.sendMessage(0, syncMessage, UnidentifiedAccessUtil.getAccessForSync(context));
messageSender.sendMessage(syncMessage, UnidentifiedAccessUtil.getAccessForSync(context));
}
@Override

View File

@ -94,8 +94,7 @@ public class MultiDeviceReadUpdateJob extends BaseJob implements InjectableType
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
}
// TODO: Message ID
messageSender.sendMessage(0, SignalServiceSyncMessage.forRead(readMessages), UnidentifiedAccessUtil.getAccessForSync(context));
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages), UnidentifiedAccessUtil.getAccessForSync(context));
}
@Override

View File

@ -2,20 +2,14 @@ package org.thoughtcrime.securesms.jobs;
import android.support.annotation.NonNull;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
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.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.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
@ -76,6 +70,7 @@ public class MultiDeviceStickerPackOperationJob extends BaseJob implements Injec
@Override
protected void onRun() throws Exception {
/*
if (!TextSecurePreferences.isMultiDevice(context)) {
Log.i(TAG, "Not multi device, aborting...");
return;
@ -94,8 +89,9 @@ public class MultiDeviceStickerPackOperationJob extends BaseJob implements Injec
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));
*/
}
@Override

View File

@ -2,24 +2,14 @@ package org.thoughtcrime.securesms.jobs;
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.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.util.Hex;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
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 java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
@ -59,6 +49,8 @@ public class MultiDeviceStickerPackSyncJob extends BaseJob implements Injectable
@Override
protected void onRun() throws Exception {
return;
/*
if (!TextSecurePreferences.isMultiDevice(context)) {
Log.i(TAG, "Not multi device, aborting...");
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));
*/
}
@Override

View File

@ -3,23 +3,16 @@ package org.thoughtcrime.securesms.jobs;
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.IdentityDatabase.VerifiedStatus;
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.recipients.Recipient;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
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.push.exceptions.PushNetworkException;
@ -89,6 +82,7 @@ public class MultiDeviceVerifiedUpdateJob extends BaseJob implements InjectableT
@Override
public void onRun() throws IOException, UntrustedIdentityException {
/*
try {
if (!TextSecurePreferences.isMultiDevice(context)) {
Log.i(TAG, "Not multi device...");
@ -104,12 +98,12 @@ public class MultiDeviceVerifiedUpdateJob extends BaseJob implements InjectableT
VerifiedMessage.VerifiedState verifiedState = getVerifiedState(verifiedStatus);
VerifiedMessage verifiedMessage = new VerifiedMessage(canonicalDestination.toPhoneString(), new IdentityKey(identityKey, 0), verifiedState, timestamp);
// TODO: Message ID
messageSender.sendMessage(0, SignalServiceSyncMessage.forVerified(verifiedMessage),
messageSender.sendMessage(SignalServiceSyncMessage.forVerified(verifiedMessage),
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(destination), false)));
} catch (InvalidKeyException e) {
throw new IOException(e);
}
*/
}
private VerifiedMessage.VerifiedState getVerifiedState(VerifiedStatus status) {

File diff suppressed because it is too large Load Diff

View File

@ -12,31 +12,26 @@ import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
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.signalservice.api.SignalServiceMessageSender;
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.push.SignalServiceAddress;
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.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@ -159,36 +150,13 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
try {
log(TAG, "Sending message: " + messageId);
List<Address> target;
List<Address> targets;
if (filterAddress != null) target = Collections.singletonList(Address.fromSerialized(filterAddress));
else if (!existingNetworkFailures.isEmpty()) target = Stream.of(existingNetworkFailures).map(NetworkFailure::getAddress).toList();
else target = getGroupMessageRecipients(message.getRecipient().getAddress().toGroupString(), messageId);
if (filterAddress != null) targets = Collections.singletonList(Address.fromSerialized(filterAddress));
else if (!existingNetworkFailures.isEmpty()) targets = Stream.of(existingNetworkFailures).map(NetworkFailure::getAddress).toList();
else targets = ClosedGroupsProtocol.getDestinations(message.getRecipient().getAddress().toGroupString(), context).get();
String localNumber = TextSecurePreferences.getLocalNumber(context);
// 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<SendMessageResult> results = deliver(message, targets);
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();
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);
notifyMediaMessageDeliveryFailed(context, messageId);
}
} catch (UntrustedIdentityException | UndeliverableMessageException e) {
} catch (Exception e) {
warn(TAG, e);
database.markAsSentFailed(messageId);
notifyMediaMessageDeliveryFailed(context, messageId);
@ -246,10 +214,8 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
@Override
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
// if (exception instanceof RetryLaterException) return true;
return false;
}
@ -260,17 +226,18 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
private List<SendMessageResult> deliver(OutgoingMediaMessage message, @NonNull List<Address> destinations)
throws IOException, UntrustedIdentityException, UndeliverableMessageException {
// rotateSenderCertificateIfNecessary();
// Messages shouldn't be able to be sent to RSS Feeds
Address groupAddress = message.getRecipient().getAddress();
if (groupAddress.isRSSFeed()) {
// Loki - The user shouldn't be able to message RSS feeds
Address address = message.getRecipient().getAddress();
if (address.isRSSFeed()) {
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;
}
String groupId = groupAddress.toGroupString();
String groupId = address.toGroupString();
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
Optional<Quote> quote = getQuoteFor(message);
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
@ -281,18 +248,15 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
List<SignalServiceAttachment> attachmentPointers = getAttachmentPointersFor(attachments);
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(addresses)
.map(address -> Address.fromSerialized(address.getNumber()))
.map(address -> Recipient.from(context, address, false))
.map(a -> Address.fromSerialized(a.getNumber()))
.map(a -> Recipient.from(context, a, false))
.map(recipient -> UnidentifiedAccessUtil.getAccessFor(context, recipient))
.toList();
SignalServiceGroup.GroupType groupType = SignalServiceGroup.GroupType.SIGNAL;
if (groupAddress.isPublicChat()) {
groupType = SignalServiceGroup.GroupType.PUBLIC_CHAT;
}
SignalServiceGroup.GroupType groupType = address.isOpenGroup() ? SignalServiceGroup.GroupType.PUBLIC_CHAT : SignalServiceGroup.GroupType.SIGNAL;
if (message.isGroup() && groupAddress.isSignalGroup()) {
// Loki - Only send GroupUpdate or GroupQuit to signal groups
if (message.isGroup() && address.isClosedGroup()) {
// Loki - Only send GroupUpdate or GroupQuit messages to closed groups
OutgoingGroupMediaMessage groupMessage = (OutgoingGroupMediaMessage) message;
GroupContext groupContext = groupMessage.getGroupContext();
SignalServiceAttachment avatar = attachmentPointers.isEmpty() ? null : attachmentPointers.get(0);
@ -301,7 +265,6 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
SignalServiceDataMessage groupDataMessage = SignalServiceDataMessage.newBuilder()
.withTimestamp(message.getSentTimeMillis())
.withExpiration(message.getRecipient().getExpireMessages())
.withBody(message.getBody())
.asGroupMessage(group)
.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> {
@Override
public @NonNull PushGroupSendJob create(@NonNull Parameters parameters, @NonNull org.thoughtcrime.securesms.jobmanager.Data data) {

Some files were not shown because too many files have changed in this diff Show More