mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-22 07:57:30 +00:00
Merge branch 'dev'
This commit is contained in:
commit
18b95c7f8a
11
.github/ISSUE_TEMPLATE.md
vendored
11
.github/ISSUE_TEMPLATE.md
vendored
@ -23,9 +23,13 @@ Describe here the issue that you are experiencing.
|
||||
- list the steps
|
||||
- that reproduce the bug
|
||||
|
||||
**Actual result:** Describe here what happens after you run the steps above (i.e. the buggy behaviour)
|
||||
**Actual result:**
|
||||
|
||||
**Expected result:** Describe here what should happen after you run the steps above (i.e. what would be the correct behaviour)
|
||||
Describe here what happens after you run the steps above (i.e. the buggy behaviour)
|
||||
|
||||
**Expected result:**
|
||||
|
||||
Describe here what should happen after you run the steps above (i.e. what would be the correct behaviour)
|
||||
|
||||
### Screenshots
|
||||
<!-- you can drag and drop images below -->
|
||||
@ -33,10 +37,11 @@ Describe here the issue that you are experiencing.
|
||||
|
||||
### Device info
|
||||
<!-- replace the examples with your info -->
|
||||
|
||||
**Device:** Manufacturer Model XVI
|
||||
|
||||
**Android version:** 0.0.0
|
||||
|
||||
**Session version:** 0.0.0
|
||||
|
||||
|
||||
### Link to debug log
|
||||
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -23,7 +23,7 @@ If applicable, add screenshots or logs to help explain your problem.
|
||||
|
||||
- Device: [e.g. Samsung Galaxy S8]
|
||||
- OS: [e.g. Android Pie]
|
||||
- Version of Loki Messenger or latest commit hash
|
||||
- Version of Session or latest commit hash
|
||||
|
||||
**Additional context**
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
@ -112,6 +113,9 @@
|
||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.DisplayNameActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.PNModeActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity"
|
||||
android:screenOrientation="portrait"
|
||||
@ -509,6 +513,14 @@
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:exported="true"
|
||||
android:theme="@style/TextSecure.LightNoActionBar" />
|
||||
<service
|
||||
android:name="org.thoughtcrime.securesms.service.PushNotificationService"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name="org.thoughtcrime.securesms.service.WebRtcCallService"
|
||||
android:enabled="true" />
|
||||
|
66
BUILDING.md
Normal file
66
BUILDING.md
Normal file
@ -0,0 +1,66 @@
|
||||
Building Session
|
||||
===============
|
||||
|
||||
Basics
|
||||
------
|
||||
|
||||
Session uses [Gradle](http://gradle.org) to build the project and to maintain
|
||||
dependencies. However, you needn't install it yourself; the
|
||||
"gradle wrapper" `gradlew`, mentioned below, will do that for you.
|
||||
|
||||
Building Session
|
||||
---------------
|
||||
|
||||
The following steps should help you (re)build Session from the command line.
|
||||
|
||||
1. Checkout the session-android project source with the command:
|
||||
|
||||
git clone https://github.com/loki-project/session-android.git
|
||||
|
||||
2. Make sure you have the [Android SDK](https://developer.android.com/sdk/index.html) installed.
|
||||
3. Ensure that the following packages are installed from the Android SDK manager:
|
||||
* Android SDK Build Tools (see buildToolsVersion in build.gradle)
|
||||
* SDK Platform (All API levels)
|
||||
* Android Support Repository
|
||||
* Google Repository
|
||||
4. Create a local.properties file at the root of your source checkout and add an sdk.dir entry to it. For example:
|
||||
|
||||
sdk.dir=/Application/android-sdk-macosx
|
||||
|
||||
5. Using Java 8
|
||||
|
||||
6. Execute Gradle:
|
||||
|
||||
./gradlew build
|
||||
|
||||
Visual assets
|
||||
----------------------
|
||||
|
||||
Source assets tend to be large binary blobs, which are best stored outside of git repositories. Some source files are SVGs that can be auto-colored and sized using a tool like [android-res-utils](https://github.com/sebkur/android-res-utils).
|
||||
|
||||
Sample command for generating our audio placeholder image:
|
||||
|
||||
```bash
|
||||
pngs_from_svg.py ic_audio.svg /path/to/Session/res/ 150 --color #000 --opacity 0.54 --suffix _light
|
||||
pngs_from_svg.py ic_audio.svg /path/to/Session/res/ 150 --color #fff --opacity 1.00 --suffix _light
|
||||
```
|
||||
|
||||
Setting up a development environment
|
||||
------------------------------------
|
||||
|
||||
[Android Studio](https://developer.android.com/sdk/installing/studio.html) is the recommended development environment.
|
||||
|
||||
1. Install Android Studio.
|
||||
2. Open Android Studio. On a new installation, the Quickstart panel will appear. If you have open projects, close them using "File > Close Project" to see the Quickstart panel.
|
||||
3. From the Quickstart panel, choose "Configure" then "SDK Manager".
|
||||
4. In the SDK Tools tab of the SDK Manager, make sure that the "Android Support Repository" is installed, and that the latest "Android SDK build-tools" are installed. Click "OK" to return to the Quickstart panel.
|
||||
5. From the Quickstart panel, choose "Checkout from Version Control" then "git".
|
||||
6. Paste the URL for the session-android project when prompted (https://github.com/loki-project/session-android.git).
|
||||
7. Android studio should detect the presence of a project file and ask you whether to open it. Click "yes".
|
||||
9. Default config options should be good enough.
|
||||
9. Project initialisation and build should proceed.
|
||||
|
||||
Contributing code
|
||||
-----------------
|
||||
|
||||
Code contributions should be sent via github as pull requests, from feature branches [as explained here](https://help.github.com/articles/using-pull-requests).
|
@ -6,13 +6,13 @@
|
||||
|
||||
## Summary
|
||||
|
||||
Session integrates directly with [Loki Service Nodes](https://lokidocs.com/ServiceNodes/SNOverview/), which are a set of distributed, decentralized and Sybil resistant nodes. Service Nodes act as servers which store messages offline, and a set of nodes which allow for onion routing functionality obfuscating users IP addresses. For a full understanding of how Session works, read the [Session Whitepaper](https://getsession.org/whitepaper).
|
||||
Session integrates directly with [Loki Service Nodes](https://lokidocs.com/ServiceNodes/SNOverview/), which are a set of distributed, decentralized and Sybil resistant nodes. Service Nodes act as servers which store messages offline, and a set of nodes which allow for onion routing functionality obfuscating users' IP addresses. For a full understanding of how Session works, read the [Session Whitepaper](https://getsession.org/whitepaper).
|
||||
|
||||
![AndroidSession](https://i.imgur.com/0YC9TyI.png)
|
||||
|
||||
## Want to Contribute? Found a Bug or Have a feature request?
|
||||
|
||||
Please search for any [existing issues](https://github.com/loki-project/session-android/issues) that describe your bugs in order to avoid duplicate submissions. Submissions can be made by making a pull request to our development branch. If you don't know where to start contributing , try reading the Github issues page for ideas.
|
||||
Please search for any [existing issues](https://github.com/loki-project/session-android/issues) that describe your bugs in order to avoid duplicate submissions. Submissions can be made by making a pull request to our development branch. If you don't know where to start contributing, try reading the Github issues page for ideas.
|
||||
|
||||
## Build instruction
|
||||
|
||||
|
10
build.gradle
10
build.gradle
@ -6,6 +6,8 @@ buildscript {
|
||||
ext.kovenant_version = "3.3.0"
|
||||
ext.identicon_version = "v11"
|
||||
ext.rss_parser_version = "2.0.4"
|
||||
ext.google_services_version = "4.3.3"
|
||||
ext.firebase_messaging_version = "18.0.0"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
@ -16,6 +18,7 @@ buildscript {
|
||||
classpath "com.android.tools.build:gradle:$gradle_version"
|
||||
classpath files('libs/gradle-witness.jar')
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "com.google.gms:google-services:$google_services_version"
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +27,7 @@ apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'witness'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
@ -87,6 +91,8 @@ dependencies {
|
||||
implementation 'android.arch.lifecycle:extensions:1.1.1'
|
||||
implementation 'android.arch.lifecycle:common-java8:1.1.1'
|
||||
|
||||
implementation "com.google.firebase:firebase-messaging:$firebase_messaging_version"
|
||||
|
||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.1'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-ui:2.9.1'
|
||||
|
||||
@ -184,8 +190,8 @@ dependencies {
|
||||
implementation "com.github.ybq:Android-SpinKit:1.4.0"
|
||||
}
|
||||
|
||||
def canonicalVersionCode = 48
|
||||
def canonicalVersionName = "1.0.11"
|
||||
def canonicalVersionCode = 49
|
||||
def canonicalVersionName = "1.1.0"
|
||||
|
||||
def postFixSize = 10
|
||||
def abiPostFix = ['armeabi-v7a' : 1,
|
||||
|
15
res/drawable/pn_option_background.xml
Normal file
15
res/drawable/pn_option_background.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
|
||||
<solid
|
||||
android:color="@color/pn_option_background" />
|
||||
|
||||
<stroke
|
||||
android:color="@color/pn_option_border"
|
||||
android:width="@dimen/border_thickness" />
|
||||
|
||||
<corners android:radius="@dimen/pn_option_corner_radius" />
|
||||
|
||||
</shape>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<transition xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/pn_option_background_selected" />
|
||||
<item android:drawable="@drawable/pn_option_background" />
|
||||
</transition>
|
5
res/drawable/pn_option_background_select_transition.xml
Normal file
5
res/drawable/pn_option_background_select_transition.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<transition xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/pn_option_background" />
|
||||
<item android:drawable="@drawable/pn_option_background_selected" />
|
||||
</transition>
|
15
res/drawable/pn_option_background_selected.xml
Normal file
15
res/drawable/pn_option_background_selected.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
|
||||
<solid
|
||||
android:color="@color/pn_option_background" />
|
||||
|
||||
<stroke
|
||||
android:color="@color/accent"
|
||||
android:width="@dimen/border_thickness" />
|
||||
|
||||
<corners android:radius="@dimen/pn_option_corner_radius" />
|
||||
|
||||
</shape>
|
116
res/layout-sw400dp/activity_pn_mode.xml
Normal file
116
res/layout-sw400dp/activity_pn_mode.xml
Normal file
@ -0,0 +1,116 @@
|
||||
<?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="match_parent"
|
||||
android:background="@drawable/default_session_background"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:textSize="@dimen/very_large_font_size"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/activity_pn_mode_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/activity_pn_mode_explanation" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/fcmOptionView"
|
||||
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_marginRight="@dimen/very_large_spacing"
|
||||
android:padding="12dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/pn_option_background">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/activity_pn_mode_fcm_option_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/activity_pn_mode_fcm_option_explanation" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/accent"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/activity_pn_mode_recommended_option_tag" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/backgroundPollingOptionView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="@dimen/small_spacing"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:padding="12dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/pn_option_background">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/activity_pn_mode_background_polling_option_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/activity_pn_mode_background_polling_option_explanation" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<Button
|
||||
style="@style/MediumProminentFilledButton"
|
||||
android:id="@+id/registerButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginLeft="@dimen/massive_spacing"
|
||||
android:layout_marginRight="@dimen/massive_spacing"
|
||||
android:layout_marginBottom="@dimen/medium_spacing"
|
||||
android:text="Continue" />
|
||||
|
||||
</LinearLayout>
|
@ -41,6 +41,6 @@
|
||||
android:textColor="@color/text"
|
||||
android:alpha="0.6"
|
||||
android:textAlignment="center"
|
||||
android:text="Open groups can be joined by anyone and do not provide full metadata protection" />
|
||||
android:text="Open groups can be joined by anyone and do not provide full privacy protection" />
|
||||
|
||||
</LinearLayout>
|
118
res/layout-sw400dp/fragment_pn_mode_bottom_sheet.xml
Normal file
118
res/layout-sw400dp/fragment_pn_mode_bottom_sheet.xml
Normal file
@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
app:behavior_hideable="true"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
|
||||
android:background="@drawable/default_bottom_sheet_background_inset">
|
||||
|
||||
<TextView
|
||||
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_marginRight="@dimen/very_large_spacing"
|
||||
android:textSize="@dimen/very_large_font_size"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/sheet_pn_mode_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/sheet_pn_mode_explanation" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/fcmOptionView"
|
||||
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_marginRight="@dimen/very_large_spacing"
|
||||
android:padding="12dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/pn_option_background">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/sheet_pn_mode_fcm_option_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/sheet_pn_mode_fcm_option_explanation" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/accent"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/sheet_pn_mode_recommended_option_tag" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/backgroundPollingOptionView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="@dimen/small_spacing"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:padding="12dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/pn_option_background">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/sheet_pn_mode_background_polling_option_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/sheet_pn_mode_background_polling_option_explanation" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
style="@style/MediumProminentOutlineButton"
|
||||
android:id="@+id/confirmButton"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:text="@string/sheet_pn_mode_confirm_button_title" />
|
||||
|
||||
<Button
|
||||
style="@style/MediumUnimportantOutlineButton"
|
||||
android:id="@+id/skipButton"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="@dimen/small_spacing"
|
||||
android:layout_marginBottom="@dimen/medium_spacing"
|
||||
android:text="@string/sheet_pn_mode_skip_button_title" />
|
||||
|
||||
</LinearLayout>
|
@ -32,7 +32,7 @@
|
||||
android:textColor="@color/text"
|
||||
android:alpha="0.6"
|
||||
android:textAlignment="center"
|
||||
android:text="Closed groups are end-to-end encrypted group chats for up to 10 members. They provide the same privacy protections as one-on-one sessions." />
|
||||
android:text="Closed groups support up to 10 members and provide the same privacy protections as one-on-one sessions." />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
|
116
res/layout/activity_pn_mode.xml
Normal file
116
res/layout/activity_pn_mode.xml
Normal file
@ -0,0 +1,116 @@
|
||||
<?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="match_parent"
|
||||
android:background="@drawable/default_session_background"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
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:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/activity_pn_mode_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/activity_pn_mode_explanation" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/fcmOptionView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="@dimen/small_spacing"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:padding="12dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/pn_option_background">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/activity_pn_mode_fcm_option_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/activity_pn_mode_fcm_option_explanation" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/accent"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/activity_pn_mode_recommended_option_tag" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/backgroundPollingOptionView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="@dimen/small_spacing"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:padding="12dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/pn_option_background">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/activity_pn_mode_background_polling_option_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/activity_pn_mode_background_polling_option_explanation" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<Button
|
||||
style="@style/MediumProminentFilledButton"
|
||||
android:id="@+id/registerButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginLeft="@dimen/massive_spacing"
|
||||
android:layout_marginRight="@dimen/massive_spacing"
|
||||
android:layout_marginBottom="@dimen/medium_spacing"
|
||||
android:text="Continue" />
|
||||
|
||||
</LinearLayout>
|
@ -41,6 +41,6 @@
|
||||
android:textColor="@color/text"
|
||||
android:alpha="0.6"
|
||||
android:textAlignment="center"
|
||||
android:text="Open groups can be joined by anyone and do not provide full metadata protection" />
|
||||
android:text="Open groups can be joined by anyone and do not provide full privacy protection" />
|
||||
|
||||
</LinearLayout>
|
@ -58,6 +58,6 @@
|
||||
android:textColor="@color/text"
|
||||
android:alpha="0.6"
|
||||
android:textAlignment="center"
|
||||
android:text="Open groups can be joined by anyone and do not provide full metadata protection" />
|
||||
android:text="Open groups can be joined by anyone and do not provide full privacy protection" />
|
||||
|
||||
</LinearLayout>
|
||||
|
118
res/layout/fragment_pn_mode_bottom_sheet.xml
Normal file
118
res/layout/fragment_pn_mode_bottom_sheet.xml
Normal file
@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
app:behavior_hideable="true"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
|
||||
android:background="@drawable/default_bottom_sheet_background_inset">
|
||||
|
||||
<TextView
|
||||
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_marginRight="@dimen/very_large_spacing"
|
||||
android:textSize="@dimen/large_font_size"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/sheet_pn_mode_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/sheet_pn_mode_explanation" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/fcmOptionView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="@dimen/small_spacing"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:padding="12dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/pn_option_background">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/sheet_pn_mode_fcm_option_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/sheet_pn_mode_fcm_option_explanation" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/accent"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/sheet_pn_mode_recommended_option_tag" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/backgroundPollingOptionView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="@dimen/small_spacing"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:padding="12dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/pn_option_background">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/sheet_pn_mode_background_polling_option_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/sheet_pn_mode_background_polling_option_explanation" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
style="@style/MediumProminentOutlineButton"
|
||||
android:id="@+id/confirmButton"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/sheet_pn_mode_confirm_button_title" />
|
||||
|
||||
<Button
|
||||
style="@style/MediumUnimportantOutlineButton"
|
||||
android:id="@+id/skipButton"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="@dimen/small_spacing"
|
||||
android:layout_marginBottom="@dimen/medium_spacing"
|
||||
android:text="@string/sheet_pn_mode_skip_button_title" />
|
||||
|
||||
</LinearLayout>
|
@ -26,6 +26,8 @@
|
||||
<color name="sent_message_background">#3F4146</color>
|
||||
<color name="quote_not_found_background">#99FFFFFF</color>
|
||||
<color name="new_conversation_button_collapsed_background">#1F1F1F</color>
|
||||
<color name="pn_option_background">#1B1B1B</color>
|
||||
<color name="pn_option_border">#212121</color>
|
||||
<!-- Session -->
|
||||
|
||||
<!-- Loki -->
|
||||
|
@ -32,6 +32,7 @@
|
||||
<dimen name="setting_button_height">56dp</dimen>
|
||||
<dimen name="dialog_corner_radius">8dp</dimen>
|
||||
<dimen name="dialog_button_corner_radius">4dp</dimen>
|
||||
<dimen name="pn_option_corner_radius">8dp</dimen>
|
||||
|
||||
<!-- Distances -->
|
||||
<dimen name="small_spacing">8dp</dimen>
|
||||
|
@ -1670,5 +1670,26 @@
|
||||
<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="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>
|
||||
<string name="activity_pn_mode_fcm_option_explanation">Session will use the Firebase Cloud Messaging service to receive push notifications. You’ll be notified of new messages reliably and immediately. Using FCM means that this device will communicate directly with Google’s servers to retrieve push notifications, which will expose your IP address to Google. Your messages will still be onion-routed and end-to-end encrypted, so the contents of your messages will remain completely private.</string>
|
||||
<string name="activity_pn_mode_background_polling_option_title">Background Polling</string>
|
||||
<string name="activity_pn_mode_background_polling_option_explanation">Session will occasionally check for new messages in the background. This guarantees full privacy protection, but message notifications may be significantly delayed.</string>
|
||||
<string name="activity_pn_mode_recommended_option_tag">Recommended</string>
|
||||
<string name="activity_pn_mode_no_option_picked_dialog_title">Please Pick an Option</string>
|
||||
<string name="sheet_pn_mode_title">Push Notifications</string>
|
||||
<string name="sheet_pn_mode_explanation">Session now features two ways to handle push notifications. Make sure to read the descriptions carefully before you choose.</string>
|
||||
<string name="sheet_pn_mode_fcm_option_title">Firebase Cloud Messaging</string>
|
||||
<string name="sheet_pn_mode_fcm_option_explanation">Session will use the Firebase Cloud Messaging service to receive push notifications. You’ll be notified of new messages reliably and immediately. Using FCM means that this device will communicate directly with Google’s servers to retrieve push notifications, which will expose your IP address to Google. Your messages will still be onion-routed and end-to-end encrypted, so the contents of your messages will remain completely private.</string>
|
||||
<string name="sheet_pn_mode_background_polling_option_title">Background Polling</string>
|
||||
<string name="sheet_pn_mode_background_polling_option_explanation">Session will occasionally check for new messages in the background. This guarantees full privacy protection, but message notifications may be significantly delayed.</string>
|
||||
<string name="sheet_pn_mode_recommended_option_tag">Recommended</string>
|
||||
<string name="sheet_pn_mode_no_option_picked_dialog_title">Please Pick an Option</string>
|
||||
<string name="sheet_pn_mode_confirm_button_title">Confirm</string>
|
||||
<string name="sheet_pn_mode_skip_button_title">Skip</string>
|
||||
<string name="preferences_notifications_strategy_category_title">Notification Strategy</string>
|
||||
<string name="preferences_notifications_use_fcm_option_title">Use FCM</string>
|
||||
<string name="preferences_notifications_use_fcm_option_explanation">Using Firebase Cloud Messaging allows for more reliable push notifications, but exposes your IP to Google.</string>
|
||||
|
||||
</resources>
|
||||
|
@ -1,11 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">imaginary.stream</domain>
|
||||
<domain includeSubdomains="true">chat.getsession.org</domain>
|
||||
<domain includeSubdomains="true">149.56.148.124</domain>
|
||||
<domain includeSubdomains="true">storage.seed1.loki.network</domain>
|
||||
<domain includeSubdomains="true">storage.seed2.loki.network</domain>
|
||||
<domain includeSubdomains="true">public.loki.foundation:22023</domain>
|
||||
<domain includeSubdomains="true">public.loki.foundation</domain>
|
||||
<domain includeSubdomains="true">file-dev.lokinet.org</domain>
|
||||
<domain includeSubdomains="true">127.0.0.1</domain>
|
||||
</domain-config>
|
||||
|
@ -21,6 +21,19 @@
|
||||
|
||||
<PreferenceCategory android:layout="@layout/preference_divider" />
|
||||
|
||||
<PreferenceCategory android:title="@string/preferences_notifications_strategy_category_title">
|
||||
|
||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
android:dependency="pref_key_enable_notifications"
|
||||
android:key="pref_key_use_fcm"
|
||||
android:title="@string/preferences_notifications_use_fcm_option_title"
|
||||
android:summary="@string/preferences_notifications_use_fcm_option_explanation"
|
||||
android:defaultValue="false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:layout="@layout/preference_divider" />
|
||||
|
||||
<PreferenceCategory android:title="@string/activity_notification_settings_style_section_title">
|
||||
|
||||
<org.thoughtcrime.securesms.preferences.widgets.SignalPreference
|
||||
|
@ -30,6 +30,8 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.multidex.MultiDexApplication;
|
||||
|
||||
import com.google.firebase.iid.FirebaseInstanceId;
|
||||
|
||||
import org.conscrypt.Conscrypt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.signal.aesgcmprovider.AesGcmProvider;
|
||||
@ -61,6 +63,7 @@ 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;
|
||||
@ -92,14 +95,17 @@ import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider;
|
||||
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.LokiFileServerAPI;
|
||||
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.LokiPublicChat;
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
|
||||
import org.whispersystems.signalservice.loki.api.LokiRSSFeed;
|
||||
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 java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -180,6 +186,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
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);
|
||||
@ -197,6 +205,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
// Loki - Set up public chat manager
|
||||
lokiPublicChatManager = new LokiPublicChatManager(this);
|
||||
updatePublicChatProfilePictureIfNeeded();
|
||||
registerForFCMIfNeeded(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -453,6 +462,24 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
}, this);
|
||||
}
|
||||
|
||||
public void registerForFCMIfNeeded(Boolean force) {
|
||||
Context context = this;
|
||||
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(task -> {
|
||||
if (!task.isSuccessful()) {
|
||||
Log.w(TAG, "getInstanceId failed", task.getException());
|
||||
return;
|
||||
}
|
||||
String token = task.getResult().getToken();
|
||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
if (userHexEncodedPublicKey == null) return;
|
||||
if (TextSecurePreferences.isUsingFCM(this)) {
|
||||
LokiPushNotificationManager.register(token, userHexEncodedPublicKey, context, force);
|
||||
} else {
|
||||
LokiPushNotificationManager.unregister(token, context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ping(@NotNull String s) {
|
||||
// TODO: Implement
|
||||
@ -464,7 +491,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
if (userHexEncodedPublicKey == null) return;
|
||||
LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(this);
|
||||
Context context = this;
|
||||
lokiPoller = new LokiPoller(userHexEncodedPublicKey, lokiAPIDatabase, broadcaster, protos -> {
|
||||
LokiSwarmAPI.Companion.configureIfNeeded(lokiAPIDatabase);
|
||||
LokiAPI.Companion.configureIfNeeded(userHexEncodedPublicKey, lokiAPIDatabase, broadcaster);
|
||||
lokiPoller = new LokiPoller(userHexEncodedPublicKey, lokiAPIDatabase, protos -> {
|
||||
for (SignalServiceProtos.Envelope proto : protos) {
|
||||
new PushContentReceiveJob(context).processEnvelope(new SignalServiceEnvelope(proto));
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec;
|
||||
import org.whispersystems.signalservice.loki.utilities.SerializationKt;
|
||||
import org.whispersystems.signalservice.loki.utilities.HexEncodingKt;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@ -341,7 +341,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
try {
|
||||
String hexEncodedSeed = IdentityKeyUtil.retrieve(getContext(), IdentityKeyUtil.lokiSeedKey);
|
||||
if (hexEncodedSeed == null) {
|
||||
hexEncodedSeed = SerializationKt.getHexEncodedPrivateKey(IdentityKeyUtil.getIdentityKeyPair(getContext())); // Legacy account
|
||||
hexEncodedSeed = HexEncodingKt.getHexEncodedPrivateKey(IdentityKeyUtil.getIdentityKeyPair(getContext())); // Legacy account
|
||||
}
|
||||
String seed = new MnemonicCodec(languageFileDirectory).encode(hexEncodedSeed, MnemonicCodec.Language.Configuration.Companion.getEnglish());
|
||||
new AlertDialog.Builder(getContext())
|
||||
|
@ -58,8 +58,8 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
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.LokiFileServerAPI;
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
|
||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.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.LokiPublicChat;
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -11,8 +11,8 @@ import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI;
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -228,10 +228,10 @@ 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.DeviceLink;
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLink;
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
||||
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChat;
|
||||
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;
|
||||
@ -317,7 +317,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private Button makeDefaultSmsButton;
|
||||
private Button registerButton;
|
||||
private InputAwareLayout container;
|
||||
private View composePanel;
|
||||
protected Stub<ReminderView> reminderView;
|
||||
private Stub<UnverifiedBannerView> unverifiedBannerView;
|
||||
private Stub<GroupShareProfileView> groupShareProfileView;
|
||||
@ -552,7 +551,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
updateTitleTextView(recipient);
|
||||
updateSubtitleTextView();
|
||||
setActionBarColor(recipient.getColor());
|
||||
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
||||
updateInputUI(recipient, isSecureText, isDefaultSms);
|
||||
setGroupShareProfileReminder(recipient);
|
||||
calculateCharactersRemaining();
|
||||
|
||||
@ -645,7 +644,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
updateTitleTextView(recipient);
|
||||
updateSubtitleTextView();
|
||||
NotificationChannels.updateContactChannelName(this, recipient);
|
||||
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
||||
updateInputUI(recipient, isSecureText, isDefaultSms);
|
||||
supportInvalidateOptionsMenu();
|
||||
break;
|
||||
case TAKE_PHOTO:
|
||||
@ -858,6 +857,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
searchViewModel.onSearchClosed();
|
||||
searchNav.setVisibility(View.GONE);
|
||||
inputPanel.setVisibility(View.VISIBLE);
|
||||
updateInputUI(recipient, isSecureText, isDefaultSms);
|
||||
fragment.onSearchQueryUpdated(null);
|
||||
invalidateOptionsMenu();
|
||||
return true;
|
||||
@ -1343,7 +1343,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
calculateCharactersRemaining();
|
||||
supportInvalidateOptionsMenu();
|
||||
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
||||
updateInputUI(recipient, isSecureText, isDefaultSms);
|
||||
}
|
||||
|
||||
///// Initializers
|
||||
@ -1627,7 +1627,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
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);
|
||||
composePanel = ViewUtil.findById(this, R.id.bottom_panel);
|
||||
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);
|
||||
@ -1835,7 +1834,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
updateTitleTextView(recipient);
|
||||
updateSubtitleTextView();
|
||||
// titleView.setVerified(identityRecords.isVerified());
|
||||
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
||||
updateInputUI(recipient, isSecureText, isDefaultSms);
|
||||
setActionBarColor(recipient.getColor());
|
||||
setGroupShareProfileReminder(recipient);
|
||||
updateReminders(recipient.hasSeenInviteReminder());
|
||||
@ -2043,29 +2042,30 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
setStatusBarColor(getResources().getColor(R.color.action_bar_background));
|
||||
}
|
||||
|
||||
private void setBlockedUserState(Recipient recipient, boolean isSecureText, boolean isDefaultSms) {
|
||||
if (recipient.isGroupRecipient() && recipient.getAddress().isRSSFeed()) {
|
||||
// FIXME: This name is confusing because we also have updateInputPanel and setInputPanelEnabled
|
||||
private void updateInputUI(Recipient recipient, boolean isSecureText, boolean isDefaultSms) {
|
||||
if (recipient.isGroupRecipient() && !isActiveGroup()) {
|
||||
unblockButton.setVisibility(View.GONE);
|
||||
composePanel.setVisibility(View.GONE);
|
||||
inputPanel.setVisibility(View.GONE);
|
||||
makeDefaultSmsButton.setVisibility(View.GONE);
|
||||
registerButton.setVisibility(View.GONE);
|
||||
} else if (recipient.isBlocked()) {
|
||||
unblockButton.setVisibility(View.VISIBLE);
|
||||
composePanel.setVisibility(View.GONE);
|
||||
inputPanel.setVisibility(View.GONE);
|
||||
makeDefaultSmsButton.setVisibility(View.GONE);
|
||||
registerButton.setVisibility(View.GONE);
|
||||
} else if (!isSecureText && isPushGroupConversation()) {
|
||||
unblockButton.setVisibility(View.GONE);
|
||||
composePanel.setVisibility(View.GONE);
|
||||
inputPanel.setVisibility(View.GONE);
|
||||
makeDefaultSmsButton.setVisibility(View.GONE);
|
||||
registerButton.setVisibility(View.VISIBLE);
|
||||
} else if (!isSecureText && !isDefaultSms) {
|
||||
unblockButton.setVisibility(View.GONE);
|
||||
composePanel.setVisibility(View.GONE);
|
||||
inputPanel.setVisibility(View.GONE);
|
||||
makeDefaultSmsButton.setVisibility(View.VISIBLE);
|
||||
registerButton.setVisibility(View.GONE);
|
||||
} else {
|
||||
composePanel.setVisibility(View.VISIBLE);
|
||||
inputPanel.setVisibility(View.VISIBLE);
|
||||
unblockButton.setVisibility(View.GONE);
|
||||
makeDefaultSmsButton.setVisibility(View.GONE);
|
||||
registerButton.setVisibility(View.GONE);
|
||||
@ -2125,7 +2125,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
private boolean isActiveGroup() {
|
||||
if (!isGroupConversation()) return false;
|
||||
if (!isGroupConversation() || recipient.getAddress().isRSSFeed()) return false;
|
||||
|
||||
Optional<GroupRecord> record = DatabaseFactory.getGroupDatabase(this).getGroup(getRecipient().getAddress().toGroupString());
|
||||
return record.isPresent() && record.get().isActive();
|
||||
@ -2314,7 +2314,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
String hint = enabled ? "Message" : "Pending session request";
|
||||
inputPanel.setHint(hint);
|
||||
inputPanel.setEnabled(enabled);
|
||||
if (enabled) {
|
||||
if (enabled && inputPanel.getVisibility() == View.VISIBLE) {
|
||||
inputPanel.composeText.requestFocus();
|
||||
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
||||
inputMethodManager.showSoftInput(inputPanel.composeText, 0);
|
||||
@ -2939,6 +2939,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
@Override
|
||||
public void handleReplyMessage(MessageRecord messageRecord) {
|
||||
if (recipient.isGroupRecipient() && !isActiveGroup()) { return; }
|
||||
|
||||
Recipient author;
|
||||
|
||||
if (messageRecord.isOutgoing()) {
|
||||
@ -3152,7 +3154,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
subtitleTextView.setVisibility(View.GONE);
|
||||
}
|
||||
} else if (PublicKeyValidation.isValid(recipient.getAddress().toString())) {
|
||||
subtitleTextView.setText(recipient.getAddress().toString());
|
||||
String ourMasterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(this);
|
||||
String hexEncodedPublicKey = (recipient.isLocalNumber() && ourMasterHexEncodedPublicKey != null) ? ourMasterHexEncodedPublicKey : recipient.getAddress().toPhoneString();
|
||||
subtitleTextView.setText(hexEncodedPublicKey);
|
||||
} else {
|
||||
subtitleTextView.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -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.LokiPublicChat;
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -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.LokiPublicChat;
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
@ -45,7 +45,7 @@ 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.LokiPublicChat;
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -11,7 +11,7 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities;
|
||||
import org.thoughtcrime.securesms.util.AsyncLoader;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -36,7 +36,7 @@ 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.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
@ -137,49 +137,57 @@ public class GroupMessageProcessor {
|
||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||
String id = GroupUtil.getEncodedId(group);
|
||||
|
||||
// Only update group if admin sent the message
|
||||
String ourHexEncodedPublicKey = getMasterHexEncodedPublicKey(context, TextSecurePreferences.getLocalNumber(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.");
|
||||
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.");
|
||||
database.setActive(id, false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Set<Address> recordMembers = new HashSet<>(groupRecord.getMembers());
|
||||
Set<Address> messageMembers = new HashSet<>();
|
||||
Set<Address> currentMembers = new HashSet<>(groupRecord.getMembers());
|
||||
Set<Address> newMembers = new HashSet<>();
|
||||
|
||||
for (String messageMember : group.getMembers().get()) {
|
||||
messageMembers.add(Address.fromExternal(context, messageMember));
|
||||
newMembers.add(Address.fromExternal(context, messageMember));
|
||||
}
|
||||
|
||||
Set<Address> addedMembers = new HashSet<>(messageMembers);
|
||||
addedMembers.removeAll(recordMembers);
|
||||
// Added members are the members who are present in newMembers but not in currentMembers
|
||||
Set<Address> addedMembers = new HashSet<>(newMembers);
|
||||
addedMembers.removeAll(currentMembers);
|
||||
|
||||
Set<Address> missingMembers = new HashSet<>(recordMembers);
|
||||
missingMembers.removeAll(messageMembers);
|
||||
// Kicked members are members who are present in currentMembers but not in newMembers
|
||||
Set<Address> removedMembers = new HashSet<>(currentMembers);
|
||||
removedMembers.removeAll(newMembers);
|
||||
|
||||
GroupContext.Builder builder = createGroupContext(group);
|
||||
builder.setType(GroupContext.Type.UPDATE);
|
||||
|
||||
if (addedMembers.size() > 0) {
|
||||
Set<Address> unionMembers = new HashSet<>(recordMembers);
|
||||
unionMembers.addAll(messageMembers);
|
||||
database.updateMembers(id, new LinkedList<>(unionMembers));
|
||||
|
||||
builder.clearMembers();
|
||||
|
||||
for (Address addedMember : addedMembers) {
|
||||
builder.addMembers(addedMember.serialize());
|
||||
}
|
||||
} else {
|
||||
builder.clearMembers();
|
||||
// Update our group members if they're different
|
||||
if (!currentMembers.equals(newMembers)) {
|
||||
database.updateMembers(id, new LinkedList<>(newMembers));
|
||||
}
|
||||
|
||||
if (missingMembers.size() > 0) {
|
||||
for (Address removedMember : missingMembers) {
|
||||
builder.addMembers(removedMember.serialize());
|
||||
}
|
||||
// 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
|
||||
for (Address addedMember : addedMembers) {
|
||||
builder.addNewMembers(addedMember.serialize());
|
||||
}
|
||||
|
||||
for (Address removedMember : removedMembers) {
|
||||
builder.addRemovedMembers(removedMember.serialize());
|
||||
}
|
||||
|
||||
if (group.getName().isPresent() || group.getAvatar().isPresent()) {
|
||||
@ -191,10 +199,15 @@ public class GroupMessageProcessor {
|
||||
builder.clearName();
|
||||
}
|
||||
|
||||
if (!groupRecord.isActive()) database.setActive(id, true);
|
||||
// If we were removed then we need to disable the chat
|
||||
if (removedMembers.contains(Address.fromSerialized(ourHexEncodedPublicKey))) {
|
||||
database.setActive(id, false);
|
||||
} else {
|
||||
if (!groupRecord.isActive()) database.setActive(id, true);
|
||||
|
||||
if (group.getMembers().isPresent()) {
|
||||
establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
|
||||
if (group.getMembers().isPresent()) {
|
||||
establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
|
||||
}
|
||||
}
|
||||
|
||||
return storeMessage(context, content, group, builder.build(), outgoing);
|
||||
|
@ -27,7 +27,7 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI;
|
||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -137,12 +137,12 @@ import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOper
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLink;
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLinkingSession;
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLink;
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLinkingSession;
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
||||
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI;
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChat;
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat;
|
||||
import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiServiceMessage;
|
||||
@ -1895,7 +1895,28 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
boolean isGroupActive = groupId.isPresent() && groupDatabase.isActive(groupId.get());
|
||||
boolean isLeaveMessage = message.getGroupInfo().isPresent() && message.getGroupInfo().get().getType() == SignalServiceGroup.Type.QUIT;
|
||||
|
||||
return (isContentMessage && !isGroupActive) || (sender.isBlocked() && !isLeaveMessage);
|
||||
boolean isClosedGroup = conversation.getAddress().isSignalGroup();
|
||||
boolean isGroupMember = true;
|
||||
|
||||
// Only allow messages from group members
|
||||
if (isClosedGroup) {
|
||||
String senderHexEncodedPublicKey = content.getSender();
|
||||
|
||||
try {
|
||||
String masterHexEncodedPublicKey = PromiseUtil.timeout(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(content.getSender()), 5000).get();
|
||||
if (masterHexEncodedPublicKey != null) {
|
||||
senderHexEncodedPublicKey = masterHexEncodedPublicKey;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Recipient senderMasterAddress = Recipient.from(context, Address.fromSerialized(senderHexEncodedPublicKey), false);
|
||||
|
||||
isGroupMember = groupId.isPresent() && groupDatabase.getGroupMembers(groupId.get(), true).contains(senderMasterAddress);
|
||||
}
|
||||
|
||||
return (isContentMessage && !isGroupActive) || (sender.isBlocked() && !isLeaveMessage) || (isContentMessage && !isGroupMember);
|
||||
} else {
|
||||
return sender.isBlocked();
|
||||
}
|
||||
|
@ -50,8 +50,8 @@ 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.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChat;
|
||||
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;
|
||||
|
@ -45,7 +45,7 @@ import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
||||
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage;
|
||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
||||
|
||||
|
@ -33,7 +33,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSy
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
||||
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage;
|
||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
||||
|
||||
|
@ -13,7 +13,7 @@ import org.thoughtcrime.securesms.groups.GroupManager
|
||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPublicChatPoller
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChat
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat
|
||||
|
||||
class LokiPublicChatManager(private val context: Context) {
|
||||
private var chats = mutableMapOf<Long, LokiPublicChat>()
|
||||
|
@ -0,0 +1,82 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Context
|
||||
import okhttp3.*
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.libsignal.logging.Log
|
||||
import org.whispersystems.signalservice.internal.util.JsonUtil
|
||||
import org.whispersystems.signalservice.loki.api.LokiPushNotificationAcknowledgement
|
||||
import java.io.IOException
|
||||
|
||||
object LokiPushNotificationManager {
|
||||
private val connection = OkHttpClient()
|
||||
|
||||
private val server by lazy {
|
||||
LokiPushNotificationAcknowledgement.shared.server
|
||||
}
|
||||
|
||||
private const val tokenExpirationInterval = 2 * 24 * 60 * 60 * 1000
|
||||
|
||||
@JvmStatic
|
||||
fun unregister(token: String, context: Context?) {
|
||||
val parameters = mapOf( "token" to token )
|
||||
val url = "${server}/register"
|
||||
val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters))
|
||||
val request = Request.Builder().url(url).post(body).build()
|
||||
connection.newCall(request).enqueue(object : Callback {
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
when (response.code()) {
|
||||
200 -> {
|
||||
val bodyAsString = response.body()!!.string()
|
||||
val json = JsonUtil.fromJson(bodyAsString, Map::class.java)
|
||||
val code = json?.get("code") as? Int
|
||||
if (code != null && code != 0) {
|
||||
TextSecurePreferences.setIsUsingFCM(context, false)
|
||||
} else {
|
||||
Log.d("Loki", "Couldn't disable FCM due to error: ${json?.get("message") as? String ?: "null"}.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call, exception: IOException) {
|
||||
Log.d("Loki", "Couldn't disable FCM.")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun register(token: String, hexEncodedPublicKey: String, context: Context?, force: Boolean) {
|
||||
val oldToken = TextSecurePreferences.getFCMToken(context)
|
||||
val lastUploadDate = TextSecurePreferences.getLastFCMUploadTime(context)
|
||||
if (!force && token == oldToken && System.currentTimeMillis() - lastUploadDate < tokenExpirationInterval) { return }
|
||||
val parameters = mapOf( "token" to token, "pubKey" to hexEncodedPublicKey )
|
||||
val url = "${server}/register"
|
||||
val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters))
|
||||
val request = Request.Builder().url(url).post(body).build()
|
||||
connection.newCall(request).enqueue(object : Callback {
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
when (response.code()) {
|
||||
200 -> {
|
||||
val bodyAsString = response.body()!!.string()
|
||||
val json = JsonUtil.fromJson(bodyAsString, Map::class.java)
|
||||
val code = json?.get("code") as? Int
|
||||
if (code != null && code != 0) {
|
||||
TextSecurePreferences.setIsUsingFCM(context, true)
|
||||
TextSecurePreferences.setFCMToken(context, token)
|
||||
TextSecurePreferences.setLastFCMUploadTime(context, System.currentTimeMillis())
|
||||
} else {
|
||||
Log.d("Loki", "Couldn't register for FCM due to error: ${json?.get("message") as? String ?: "null"}.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call, exception: IOException) {
|
||||
Log.d("Loki", "Couldn't register for FCM.")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.libsignal.loki.LokiSessionResetStatus
|
||||
import org.whispersystems.signalservice.internal.util.JsonUtil
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChat
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadDatabaseProtocol
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
|
||||
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
|
||||
|
@ -12,7 +12,7 @@ import org.thoughtcrime.securesms.logging.Log
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChat
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -18,9 +18,9 @@ import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities
|
||||
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities
|
||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
|
||||
import org.whispersystems.signalservice.loki.utilities.recover
|
||||
import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
|
||||
|
@ -2,15 +2,16 @@ package org.thoughtcrime.securesms.loki.redesign.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.TextView.OnEditorActionListener
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_display_name.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.push
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.setUpActionBarSessionLogo
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.show
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipher
|
||||
|
||||
@ -21,6 +22,19 @@ class DisplayNameActivity : BaseActionBarActivity() {
|
||||
setUpActionBarSessionLogo()
|
||||
setContentView(R.layout.activity_display_name)
|
||||
displayNameEditText.imeOptions = displayNameEditText.imeOptions or 16777216 // Always use incognito keyboard
|
||||
displayNameEditText.setOnEditorActionListener(
|
||||
OnEditorActionListener { _, actionId, event ->
|
||||
// Handle validation from keyboard to trigger registration
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
|
||||
actionId == EditorInfo.IME_ACTION_DONE ||
|
||||
(event.action === KeyEvent.ACTION_DOWN
|
||||
&& event.keyCode === KeyEvent.KEYCODE_ENTER)) {
|
||||
this.register();
|
||||
return@OnEditorActionListener true
|
||||
}
|
||||
// Return true if you have consumed the action, else false.
|
||||
false
|
||||
})
|
||||
registerButton.setOnClickListener { register() }
|
||||
}
|
||||
|
||||
@ -38,20 +52,7 @@ class DisplayNameActivity : BaseActionBarActivity() {
|
||||
val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(displayNameEditText.windowToken, 0)
|
||||
TextSecurePreferences.setProfileName(this, displayName)
|
||||
TextSecurePreferences.setHasSeenWelcomeScreen(this, true)
|
||||
TextSecurePreferences.setPromptedPushRegistration(this, true)
|
||||
val application = ApplicationContext.getInstance(this)
|
||||
application.setUpStorageAPIIfNeeded()
|
||||
application.setUpP2PAPI()
|
||||
val publicChatAPI = ApplicationContext.getInstance(this).lokiPublicChatAPI
|
||||
if (publicChatAPI != null) {
|
||||
// TODO: This won't be necessary anymore when we don't auto-join the Loki Public Chat anymore
|
||||
application.createDefaultPublicChatsIfNeeded()
|
||||
val servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers()
|
||||
servers.forEach { publicChatAPI.setDisplayName(displayName, it) }
|
||||
}
|
||||
val intent = Intent(this, HomeActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
show(intent)
|
||||
val intent = Intent(this, PNModeActivity::class.java)
|
||||
push(intent)
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||
import org.thoughtcrime.securesms.loki.getColorWithID
|
||||
import org.thoughtcrime.securesms.loki.redesign.dialogs.PNModeBottomSheet
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.push
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.show
|
||||
import org.thoughtcrime.securesms.loki.redesign.views.ConversationView
|
||||
@ -156,32 +157,20 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
if (hasViewedSeed || !isMasterDevice) {
|
||||
seedReminderView.visibility = View.GONE
|
||||
}
|
||||
// if (!TextSecurePreferences.getHasSeenOpenGroupSuggestionSheet(this)) {
|
||||
// val bottomSheet = OpenGroupSuggestionBottomSheet()
|
||||
// bottomSheet.onJoinTapped = {
|
||||
// TextSecurePreferences.setHasSeenOpenGroupSuggestionSheet(this)
|
||||
// bottomSheet.dismiss()
|
||||
// // TODO: Duplication of the code in JoinPublicChatActivity
|
||||
// val application = ApplicationContext.getInstance(this)
|
||||
// val channel: Long = 1
|
||||
// val displayName = TextSecurePreferences.getProfileName(this)
|
||||
// val lokiPublicChatAPI = application.lokiPublicChatAPI!!
|
||||
// val url = "https://chat.getsession.org"
|
||||
// application.lokiPublicChatManager.addChat(url, channel).successUi {
|
||||
// lokiPublicChatAPI.getMessages(channel, url)
|
||||
// lokiPublicChatAPI.setDisplayName(displayName, url)
|
||||
// lokiPublicChatAPI.join(channel, url)
|
||||
// val profileKey: ByteArray = ProfileKeyUtil.getProfileKey(this)
|
||||
// val profileUrl: String? = TextSecurePreferences.getProfileAvatarUrl(this)
|
||||
// lokiPublicChatAPI.setProfilePicture(url, profileKey, profileUrl)
|
||||
// }
|
||||
// }
|
||||
// bottomSheet.onDismissTapped = {
|
||||
// TextSecurePreferences.setHasSeenOpenGroupSuggestionSheet(this)
|
||||
// bottomSheet.dismiss()
|
||||
// }
|
||||
// bottomSheet.show(supportFragmentManager, bottomSheet.tag)
|
||||
// }
|
||||
if (!TextSecurePreferences.hasSeenPNModeSheet(this)) {
|
||||
val bottomSheet = PNModeBottomSheet()
|
||||
bottomSheet.onConfirmTapped = { isUsingFCM ->
|
||||
TextSecurePreferences.setHasSeenPNModeSheet(this, true)
|
||||
TextSecurePreferences.setIsUsingFCM(this, isUsingFCM)
|
||||
ApplicationContext.getInstance(this).registerForFCMIfNeeded(true)
|
||||
bottomSheet.dismiss()
|
||||
}
|
||||
bottomSheet.onSkipTapped = {
|
||||
TextSecurePreferences.setHasSeenPNModeSheet(this, true)
|
||||
bottomSheet.dismiss()
|
||||
}
|
||||
bottomSheet.show(supportFragmentManager, bottomSheet.tag)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
|
@ -26,7 +26,7 @@ import org.whispersystems.curve25519.Curve25519
|
||||
import org.whispersystems.libsignal.ecc.Curve
|
||||
import org.whispersystems.libsignal.ecc.ECKeyPair
|
||||
import org.whispersystems.libsignal.util.KeyHelper
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.utilities.hexEncodedPublicKey
|
||||
import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
|
||||
|
||||
|
@ -23,9 +23,9 @@ import org.thoughtcrime.securesms.loki.redesign.dialogs.*
|
||||
import org.thoughtcrime.securesms.loki.signAndSendDeviceLinkMessage
|
||||
import org.thoughtcrime.securesms.sms.MessageSender
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPI
|
||||
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI
|
||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI
|
||||
import java.util.*
|
||||
import kotlin.concurrent.schedule
|
||||
|
||||
|
@ -6,7 +6,7 @@ import org.thoughtcrime.securesms.devicelist.Device
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.util.AsyncLoader
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities
|
||||
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec
|
||||
import java.io.File
|
||||
|
||||
|
@ -0,0 +1,112 @@
|
||||
package org.thoughtcrime.securesms.loki.redesign.activities
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.TransitionDrawable
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.support.annotation.DrawableRes
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_display_name.registerButton
|
||||
import kotlinx.android.synthetic.main.activity_home.*
|
||||
import kotlinx.android.synthetic.main.activity_pn_mode.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.setUpActionBarSessionLogo
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.show
|
||||
import org.thoughtcrime.securesms.util.GroupUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
|
||||
class PNModeActivity : BaseActionBarActivity() {
|
||||
private var selectedOptionView: LinearLayout? = null
|
||||
|
||||
// region Lifecycle
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setUpActionBarSessionLogo()
|
||||
setContentView(R.layout.activity_pn_mode)
|
||||
fcmOptionView.setOnClickListener { toggleFCM() }
|
||||
backgroundPollingOptionView.setOnClickListener { toggleBackgroundPolling() }
|
||||
registerButton.setOnClickListener { register() }
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Animation
|
||||
private fun performTransition(@DrawableRes transitionID: Int, subject: View) {
|
||||
val drawable = resources.getDrawable(transitionID, theme) as TransitionDrawable
|
||||
subject.background = drawable
|
||||
drawable.startTransition(250)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
private fun toggleFCM() {
|
||||
when (selectedOptionView) {
|
||||
null -> {
|
||||
performTransition(R.drawable.pn_option_background_select_transition, fcmOptionView)
|
||||
selectedOptionView = fcmOptionView
|
||||
}
|
||||
fcmOptionView -> {
|
||||
performTransition(R.drawable.pn_option_background_deselect_transition, fcmOptionView)
|
||||
selectedOptionView = null
|
||||
}
|
||||
backgroundPollingOptionView -> {
|
||||
performTransition(R.drawable.pn_option_background_select_transition, fcmOptionView)
|
||||
performTransition(R.drawable.pn_option_background_deselect_transition, backgroundPollingOptionView)
|
||||
selectedOptionView = fcmOptionView
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleBackgroundPolling() {
|
||||
when (selectedOptionView) {
|
||||
null -> {
|
||||
performTransition(R.drawable.pn_option_background_select_transition, backgroundPollingOptionView)
|
||||
selectedOptionView = backgroundPollingOptionView
|
||||
}
|
||||
backgroundPollingOptionView -> {
|
||||
performTransition(R.drawable.pn_option_background_deselect_transition, backgroundPollingOptionView)
|
||||
selectedOptionView = null
|
||||
}
|
||||
fcmOptionView -> {
|
||||
performTransition(R.drawable.pn_option_background_select_transition, backgroundPollingOptionView)
|
||||
performTransition(R.drawable.pn_option_background_deselect_transition, fcmOptionView)
|
||||
selectedOptionView = backgroundPollingOptionView
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun register() {
|
||||
if (selectedOptionView == null) {
|
||||
val dialog = AlertDialog.Builder(this)
|
||||
dialog.setTitle(R.string.activity_pn_mode_no_option_picked_dialog_title)
|
||||
dialog.setPositiveButton(R.string.ok) { _, _ -> }
|
||||
dialog.create().show()
|
||||
return
|
||||
}
|
||||
val displayName = TextSecurePreferences.getProfileName(this)
|
||||
TextSecurePreferences.setHasSeenWelcomeScreen(this, true)
|
||||
TextSecurePreferences.setPromptedPushRegistration(this, true)
|
||||
TextSecurePreferences.setIsUsingFCM(this, (selectedOptionView == fcmOptionView))
|
||||
TextSecurePreferences.setHasSeenPNModeSheet(this, true) // Shouldn't be shown to users who've done the new onboarding
|
||||
val application = ApplicationContext.getInstance(this)
|
||||
application.setUpStorageAPIIfNeeded()
|
||||
application.setUpP2PAPI()
|
||||
val publicChatAPI = ApplicationContext.getInstance(this).lokiPublicChatAPI
|
||||
if (publicChatAPI != null) {
|
||||
// TODO: This won't be necessary anymore when we don't auto-join the Loki Public Chat anymore
|
||||
application.createDefaultPublicChatsIfNeeded()
|
||||
val servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers()
|
||||
servers.forEach { publicChatAPI.setDisplayName(displayName, it) }
|
||||
}
|
||||
application.registerForFCMIfNeeded(true)
|
||||
val intent = Intent(this, HomeActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
show(intent)
|
||||
}
|
||||
// endregion
|
||||
}
|
@ -42,7 +42,7 @@ import org.thoughtcrime.securesms.util.BitmapUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipher
|
||||
import org.whispersystems.signalservice.api.util.StreamDetails
|
||||
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI
|
||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
import java.security.SecureRandom
|
||||
|
@ -17,9 +17,9 @@ import org.thoughtcrime.securesms.loki.redesign.utilities.QRCodeUtilities
|
||||
import org.thoughtcrime.securesms.loki.toPx
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLinkingSession
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLinkingSessionListener
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLinkingSession
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLinkingSessionListener
|
||||
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec
|
||||
|
||||
class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListener {
|
||||
|
@ -15,9 +15,9 @@ import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLinkingSession
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLinkingSessionListener
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLinkingSession
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLinkingSessionListener
|
||||
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec
|
||||
|
||||
class LinkDeviceSlaveModeDialog : DialogFragment(), DeviceLinkingSessionListener {
|
||||
|
@ -8,7 +8,7 @@ import android.view.ViewGroup
|
||||
import kotlinx.android.synthetic.main.fragment_open_group_suggestion_bottom_sheet.*
|
||||
import network.loki.messenger.R
|
||||
|
||||
public class OpenGroupSuggestionBottomSheet : BottomSheetDialogFragment() {
|
||||
class OpenGroupSuggestionBottomSheet : BottomSheetDialogFragment() {
|
||||
var onJoinTapped: (() -> Unit)? = null
|
||||
var onDismissTapped: (() -> Unit)? = null
|
||||
|
||||
|
@ -0,0 +1,100 @@
|
||||
package org.thoughtcrime.securesms.loki.redesign.dialogs
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.drawable.TransitionDrawable
|
||||
import android.os.Bundle
|
||||
import android.support.annotation.DrawableRes
|
||||
import android.support.design.widget.BottomSheetDialogFragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.fragment_pn_mode_bottom_sheet.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
|
||||
class PNModeBottomSheet : BottomSheetDialogFragment() {
|
||||
private var selectedOptionView: LinearLayout? = null
|
||||
var onConfirmTapped: ((Boolean) -> Unit)? = null
|
||||
var onSkipTapped: (() -> Unit)? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(STYLE_NORMAL, R.style.SessionBottomSheetDialogTheme)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_pn_mode_bottom_sheet, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
fcmOptionView.setOnClickListener { toggleFCM() }
|
||||
backgroundPollingOptionView.setOnClickListener { toggleBackgroundPolling() }
|
||||
confirmButton.setOnClickListener { confirm() }
|
||||
skipButton.setOnClickListener { onSkipTapped?.invoke() }
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface?) {
|
||||
TextSecurePreferences.setHasSeenPNModeSheet(context, true)
|
||||
super.onDismiss(dialog)
|
||||
}
|
||||
|
||||
// region Animation
|
||||
private fun performTransition(@DrawableRes transitionID: Int, subject: View) {
|
||||
val drawable = resources.getDrawable(transitionID, context!!.theme) as TransitionDrawable
|
||||
subject.background = drawable
|
||||
drawable.startTransition(250)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
private fun toggleFCM() {
|
||||
when (selectedOptionView) {
|
||||
null -> {
|
||||
performTransition(R.drawable.pn_option_background_select_transition, fcmOptionView)
|
||||
selectedOptionView = fcmOptionView
|
||||
}
|
||||
fcmOptionView -> {
|
||||
performTransition(R.drawable.pn_option_background_deselect_transition, fcmOptionView)
|
||||
selectedOptionView = null
|
||||
}
|
||||
backgroundPollingOptionView -> {
|
||||
performTransition(R.drawable.pn_option_background_select_transition, fcmOptionView)
|
||||
performTransition(R.drawable.pn_option_background_deselect_transition, backgroundPollingOptionView)
|
||||
selectedOptionView = fcmOptionView
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleBackgroundPolling() {
|
||||
when (selectedOptionView) {
|
||||
null -> {
|
||||
performTransition(R.drawable.pn_option_background_select_transition, backgroundPollingOptionView)
|
||||
selectedOptionView = backgroundPollingOptionView
|
||||
}
|
||||
backgroundPollingOptionView -> {
|
||||
performTransition(R.drawable.pn_option_background_deselect_transition, backgroundPollingOptionView)
|
||||
selectedOptionView = null
|
||||
}
|
||||
fcmOptionView -> {
|
||||
performTransition(R.drawable.pn_option_background_select_transition, backgroundPollingOptionView)
|
||||
performTransition(R.drawable.pn_option_background_deselect_transition, fcmOptionView)
|
||||
selectedOptionView = backgroundPollingOptionView
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun confirm() {
|
||||
if (selectedOptionView == null) {
|
||||
val dialog = AlertDialog.Builder(context)
|
||||
dialog.setTitle(R.string.sheet_pn_mode_no_option_picked_dialog_title)
|
||||
dialog.setPositiveButton(R.string.ok) { _, _ -> }
|
||||
dialog.create().show()
|
||||
return
|
||||
}
|
||||
onConfirmTapped?.invoke(selectedOptionView == fcmOptionView)
|
||||
}
|
||||
// endregion
|
||||
}
|
@ -28,13 +28,15 @@ class BackgroundPollWorker : PersistentAlarmManagerListener() {
|
||||
}
|
||||
|
||||
override fun onAlarm(context: Context, scheduledTime: Long): Long {
|
||||
if (TextSecurePreferences.isUsingFCM(context)) { return 0L }
|
||||
if (scheduledTime != 0L) {
|
||||
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context)
|
||||
try {
|
||||
val applicationContext = context.applicationContext as ApplicationContext
|
||||
val broadcaster = applicationContext.broadcaster
|
||||
LokiAPI(userHexEncodedPublicKey, lokiAPIDatabase, broadcaster).getMessages().map { messages ->
|
||||
LokiAPI.configureIfNeeded(userHexEncodedPublicKey, lokiAPIDatabase, broadcaster)
|
||||
LokiAPI.shared.getMessages().map { messages ->
|
||||
messages.forEach {
|
||||
PushContentReceiveJob(context).processEnvelope(SignalServiceEnvelope(it))
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.*
|
||||
import org.thoughtcrime.securesms.util.Base64
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLink
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPITarget
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.DeviceLink
|
||||
|
||||
// TODO: Clean this up a bit
|
||||
|
||||
@ -84,7 +84,7 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
||||
var string = "${target.address}-${target.port}"
|
||||
val keySet = target.publicKeySet
|
||||
if (keySet != null) {
|
||||
string += "-${keySet.idKey}-${keySet.encryptionKey}"
|
||||
string += "-${keySet.ed25519Key}-${keySet.x25519Key}"
|
||||
}
|
||||
string
|
||||
}
|
||||
|
@ -21,7 +21,11 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
||||
import org.whispersystems.signalservice.loki.api.*
|
||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatMessage
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
|
||||
import org.whispersystems.signalservice.loki.utilities.successBackground
|
||||
import java.security.MessageDigest
|
||||
|
@ -13,8 +13,8 @@ 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.push.SignalServiceAddress
|
||||
import org.whispersystems.signalservice.loki.api.LokiRSSFeed
|
||||
import org.whispersystems.signalservice.loki.api.LokiRSSFeedProxy
|
||||
import org.whispersystems.signalservice.loki.api.rssfeeds.LokiRSSFeed
|
||||
import org.whispersystems.signalservice.loki.api.rssfeeds.LokiRSSFeedProxy
|
||||
import org.whispersystems.signalservice.loki.utilities.successBackground
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.regex.Pattern
|
||||
|
@ -8,7 +8,7 @@ import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.groups.GroupManager
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChat
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChat
|
||||
|
||||
object OpenGroupUtilities {
|
||||
|
||||
|
@ -9,7 +9,7 @@ import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.view_mention_candidate.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI
|
||||
import org.whispersystems.signalservice.loki.api.publicchats.LokiPublicChatAPI
|
||||
import org.whispersystems.signalservice.loki.messaging.Mention
|
||||
|
||||
class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.database.Address
|
||||
import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
|
||||
// TODO: Look into a better way of handling different sizes. Maybe an enum (with associated values) encapsulating the different modes?
|
||||
|
||||
@ -60,12 +61,15 @@ class ProfilePictureView : RelativeLayout {
|
||||
fun setProfilePictureIfNeeded(imageView: ImageView, hexEncodedPublicKey: String, @DimenRes sizeID: Int) {
|
||||
glide.clear(imageView)
|
||||
if (hexEncodedPublicKey.isNotEmpty()) {
|
||||
val signalProfilePicture = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false).contactPhoto
|
||||
val recipient = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false);
|
||||
val signalProfilePicture = recipient.contactPhoto
|
||||
if (signalProfilePicture != null && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "0" && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "") {
|
||||
glide.load(signalProfilePicture).diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(imageView)
|
||||
} else {
|
||||
val size = resources.getDimensionPixelSize(sizeID)
|
||||
val jazzIcon = JazzIdenticonDrawable(size, size, hexEncodedPublicKey)
|
||||
val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context)
|
||||
val hepk = if (recipient.isLocalNumber && masterHexEncodedPublicKey != null) masterHexEncodedPublicKey else hexEncodedPublicKey
|
||||
val jazzIcon = JazzIdenticonDrawable(size, size, hepk)
|
||||
glide.load(jazzIcon).diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(imageView)
|
||||
}
|
||||
} else {
|
||||
|
@ -3,7 +3,7 @@ package org.thoughtcrime.securesms.mms;
|
||||
import android.content.Context;
|
||||
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI;
|
||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
||||
|
||||
public class PushMediaConstraints extends MediaConstraints {
|
||||
|
||||
|
@ -23,7 +23,7 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI;
|
||||
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -14,6 +14,7 @@ import android.support.v7.preference.ListPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
@ -32,6 +33,16 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
|
||||
public void onCreate(Bundle paramBundle) {
|
||||
super.onCreate(paramBundle);
|
||||
|
||||
// Set up FCM toggle
|
||||
String fcmKey = "pref_key_use_fcm";
|
||||
((SwitchPreferenceCompat)findPreference(fcmKey)).setChecked(TextSecurePreferences.isUsingFCM(getContext()));
|
||||
this.findPreference(fcmKey)
|
||||
.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
TextSecurePreferences.setIsUsingFCM(getContext(), (boolean) newValue);
|
||||
ApplicationContext.getInstance(getContext()).registerForFCMIfNeeded(true);
|
||||
return true;
|
||||
});
|
||||
|
||||
Preference ledBlinkPref = this.findPreference(TextSecurePreferences.LED_BLINK_PREF);
|
||||
|
||||
if (NotificationChannels.supported()) {
|
||||
|
@ -0,0 +1,36 @@
|
||||
package org.thoughtcrime.securesms.service
|
||||
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob
|
||||
import org.thoughtcrime.securesms.loki.LokiPushNotificationManager
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.libsignal.logging.Log
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope
|
||||
import org.whispersystems.signalservice.internal.util.Base64
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiMessageWrapper
|
||||
|
||||
class PushNotificationService : FirebaseMessagingService() {
|
||||
|
||||
override fun onNewToken(token: String) {
|
||||
super.onNewToken(token)
|
||||
Log.d("Loki", "New FCM token: $token.")
|
||||
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this) ?: return
|
||||
LokiPushNotificationManager.register(token, userHexEncodedPublicKey, this, false)
|
||||
}
|
||||
|
||||
override fun onMessageReceived(message: RemoteMessage) {
|
||||
val base64EncodedData = message.data["ENCRYPTED_DATA"]
|
||||
val data = base64EncodedData?.let { Base64.decode(it) }
|
||||
if (data != null) {
|
||||
try {
|
||||
val envelope = LokiMessageWrapper.unwrap(data)
|
||||
PushContentReceiveJob(this).processEnvelope(SignalServiceEnvelope(envelope))
|
||||
} catch (e: Exception) {
|
||||
Log.d("Loki", "Failed to unwrap data for message.")
|
||||
}
|
||||
} else {
|
||||
Log.d("Loki", "Failed to decode data for message.")
|
||||
}
|
||||
}
|
||||
}
|
@ -62,7 +62,7 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.push.ContactTokenDetails;
|
||||
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.api.multidevice.LokiDeviceLinkUtilities;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus;
|
||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
||||
|
||||
|
@ -10,7 +10,6 @@ import com.google.protobuf.ByteString;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@ -159,7 +158,7 @@ public class GroupUtil {
|
||||
|
||||
@NonNull private final Context context;
|
||||
@Nullable private final GroupContext groupContext;
|
||||
private final List<Recipient> members;
|
||||
private final List<Recipient> newMembers;
|
||||
private final List<Recipient> removedMembers;
|
||||
private boolean ourDeviceWasRemoved;
|
||||
|
||||
@ -167,35 +166,35 @@ public class GroupUtil {
|
||||
this.context = context.getApplicationContext();
|
||||
this.groupContext = groupContext;
|
||||
|
||||
this.members = new LinkedList<>();
|
||||
this.newMembers = new LinkedList<>();
|
||||
this.removedMembers = new LinkedList<>();
|
||||
this.ourDeviceWasRemoved = false;
|
||||
|
||||
if (groupContext != null && !groupContext.getMembersList().isEmpty()) {
|
||||
List<String> memberList = groupContext.getMembersList();
|
||||
List<Address> currentMembers = getCurrentGroupMembers();
|
||||
if (groupContext != null) {
|
||||
List<String> newMembers = groupContext.getNewMembersList();
|
||||
for (String member : newMembers) {
|
||||
this.newMembers.add(this.toRecipient(member));
|
||||
}
|
||||
|
||||
// Add them to the member or removed members lists
|
||||
for (String member : memberList) {
|
||||
Address address = Address.fromSerialized(member);
|
||||
Recipient recipient = Recipient.from(context, address, true);
|
||||
if (currentMembers == null || currentMembers.contains(address)) {
|
||||
this.members.add(recipient);
|
||||
} else {
|
||||
this.removedMembers.add(recipient);
|
||||
}
|
||||
List<String> removedMembers = groupContext.getRemovedMembersList();
|
||||
for (String member : removedMembers) {
|
||||
this.removedMembers.add(this.toRecipient(member));
|
||||
}
|
||||
|
||||
// Check if our device was removed
|
||||
if (!removedMembers.isEmpty()) {
|
||||
String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||
String hexEncodedPublicKey = masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : TextSecurePreferences.getLocalNumber(context);
|
||||
Recipient self = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false);
|
||||
ourDeviceWasRemoved = removedMembers.contains(self);
|
||||
ourDeviceWasRemoved = removedMembers.contains(hexEncodedPublicKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Recipient toRecipient(String hexEncodedPublicKey) {
|
||||
Address address = Address.fromSerialized(hexEncodedPublicKey);
|
||||
return Recipient.from(context, address, false);
|
||||
}
|
||||
|
||||
public String toString(Recipient sender) {
|
||||
// Show the local removed message
|
||||
if (ourDeviceWasRemoved) {
|
||||
@ -211,10 +210,10 @@ public class GroupUtil {
|
||||
|
||||
String title = groupContext.getName();
|
||||
|
||||
if (!members.isEmpty()) {
|
||||
if (!newMembers.isEmpty()) {
|
||||
description.append("\n");
|
||||
description.append(context.getResources().getQuantityString(R.plurals.GroupUtil_joined_the_group,
|
||||
members.size(), toString(members)));
|
||||
newMembers.size(), toString(newMembers)));
|
||||
}
|
||||
|
||||
if (!removedMembers.isEmpty()) {
|
||||
@ -224,8 +223,8 @@ public class GroupUtil {
|
||||
}
|
||||
|
||||
if (title != null && !title.trim().isEmpty()) {
|
||||
if (!members.isEmpty()) description.append(" ");
|
||||
else description.append("\n");
|
||||
String separator = (!newMembers.isEmpty() || !removedMembers.isEmpty()) ? " " : "\n";
|
||||
description.append(separator);
|
||||
description.append(context.getString(R.string.GroupUtil_group_name_is_now, title));
|
||||
}
|
||||
|
||||
@ -233,8 +232,8 @@ public class GroupUtil {
|
||||
}
|
||||
|
||||
public void addListener(RecipientModifiedListener listener) {
|
||||
if (!this.members.isEmpty()) {
|
||||
for (Recipient member : this.members) {
|
||||
if (!this.newMembers.isEmpty()) {
|
||||
for (Recipient member : this.newMembers) {
|
||||
member.addListener(listener);
|
||||
}
|
||||
}
|
||||
@ -252,23 +251,5 @@ public class GroupUtil {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Address> getCurrentGroupMembers() {
|
||||
if (groupContext == null) { return null; }
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
byte[] decodedGroupId = groupContext.getId().toByteArray();
|
||||
String signalGroupId = getEncodedId(decodedGroupId, false);
|
||||
String publicChatId = getEncodedPublicChatId(decodedGroupId);
|
||||
String rssFeedId = getEncodedRSSFeedId(decodedGroupId);
|
||||
GroupRecord groupRecord = null;
|
||||
if (!groupDatabase.isUnknownGroup(signalGroupId)) {
|
||||
groupRecord = groupDatabase.getGroup(signalGroupId).orNull();
|
||||
} else if (!groupDatabase.isUnknownGroup(publicChatId)) {
|
||||
groupRecord = groupDatabase.getGroup(publicChatId).orNull();
|
||||
} else if (!groupDatabase.isUnknownGroup(rssFeedId)) {
|
||||
groupRecord = groupDatabase.getGroup(rssFeedId).orNull();
|
||||
}
|
||||
return (groupRecord != null) ? groupRecord.getMembers() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,6 +185,45 @@ public class TextSecurePreferences {
|
||||
|
||||
private static final String MEDIA_KEYBOARD_MODE = "pref_media_keyboard_mode";
|
||||
|
||||
// region FCM
|
||||
private static final String IS_USING_FCM = "pref_is_using_fcm";
|
||||
private static final String FCM_TOKEN = "pref_fcm_token";
|
||||
private static final String LAST_FCM_TOKEN_UPLOAD_TIME = "pref_last_fcm_token_upload_time";
|
||||
private static final String HAS_SEEN_PN_MODE_SHEET = "pref_has_seen_pn_mode_sheet";
|
||||
|
||||
public static boolean isUsingFCM(Context context) {
|
||||
return getBooleanPreference(context, IS_USING_FCM, false);
|
||||
}
|
||||
|
||||
public static void setIsUsingFCM(Context context, boolean value) {
|
||||
setBooleanPreference(context, IS_USING_FCM, value);
|
||||
}
|
||||
|
||||
public static String getFCMToken(Context context) {
|
||||
return getStringPreference(context, FCM_TOKEN, "");
|
||||
}
|
||||
|
||||
public static void setFCMToken(Context context, String value) {
|
||||
setStringPreference(context, FCM_TOKEN, value);
|
||||
}
|
||||
|
||||
public static long getLastFCMUploadTime(Context context) {
|
||||
return getLongPreference(context, LAST_FCM_TOKEN_UPLOAD_TIME, 0);
|
||||
}
|
||||
|
||||
public static void setLastFCMUploadTime(Context context, long value) {
|
||||
setLongPreference(context, LAST_FCM_TOKEN_UPLOAD_TIME, value);
|
||||
}
|
||||
|
||||
public static boolean hasSeenPNModeSheet(Context context) {
|
||||
return getBooleanPreference(context, HAS_SEEN_PN_MODE_SHEET, false);
|
||||
}
|
||||
|
||||
public static void setHasSeenPNModeSheet(Context context, boolean value) {
|
||||
setBooleanPreference(context, HAS_SEEN_PN_MODE_SHEET, value);
|
||||
}
|
||||
// endregion
|
||||
|
||||
public static boolean isScreenLockEnabled(@NonNull Context context) {
|
||||
return getBooleanPreference(context, SCREEN_LOCK, false);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user