mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-25 01:07:47 +00:00
Merge branch 'dev' into version
This commit is contained in:
commit
44fd72dfac
2
.gitignore
vendored
2
.gitignore
vendored
@ -24,3 +24,5 @@ obj/
|
|||||||
jni/libspeex/.deps/
|
jni/libspeex/.deps/
|
||||||
*.sh
|
*.sh
|
||||||
pkcs11.password
|
pkcs11.password
|
||||||
|
fabric.properties
|
||||||
|
play
|
||||||
|
@ -38,58 +38,36 @@
|
|||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||||
<uses-permission android:name="network.loki.messenger.ACCESS_SECRETS" />
|
<uses-permission android:name="network.loki.messenger.ACCESS_SECRETS" />
|
||||||
<uses-permission android:name="android.permission.READ_PROFILE" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_PROFILE" />
|
|
||||||
<uses-permission
|
|
||||||
android:name="android.permission.BROADCAST_WAP_PUSH"
|
|
||||||
tools:ignore="ProtectedPermissions" />
|
|
||||||
<!--
|
|
||||||
Loki - We don't need these at all
|
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
|
||||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
|
|
||||||
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
|
|
||||||
<uses-permission android:name="android.permission.READ_SMS"/>
|
|
||||||
<uses-permission android:name="android.permission.SEND_SMS"/>
|
|
||||||
<uses-permission android:name="android.permission.WRITE_SMS"/>
|
|
||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
|
||||||
-->
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<!--
|
|
||||||
Loki - Enable again once we have location sharing
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
|
||||||
-->
|
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <!-- <uses-permission android:name="android.permission.READ_CALL_STATE"/> -->
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
<!-- For sending/receiving events -->
|
|
||||||
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
|
|
||||||
<uses-permission android:name="android.permission.READ_CALENDAR" /> <!-- Normal -->
|
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
|
||||||
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> <!-- So we can add a TextSecure 'Account' -->
|
|
||||||
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
|
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
|
||||||
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
|
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
|
||||||
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
<!-- For conversation 'shortcuts' on the desktop -->
|
||||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" /> <!-- For conversation 'shortcuts' on the desktop -->
|
|
||||||
<uses-permission android:name="android.permission.INSTALL_SHORTCUT" />
|
<uses-permission android:name="android.permission.INSTALL_SHORTCUT" />
|
||||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> <!-- For fixing MMS -->
|
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<!-- Set image as wallpaper -->
|
||||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- Set image as wallpaper -->
|
|
||||||
<uses-permission android:name="android.permission.SET_WALLPAPER" />
|
<uses-permission android:name="android.permission.SET_WALLPAPER" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
|
||||||
<uses-permission android:name="android.permission.BROADCAST_STICKY" /> <!-- <uses-permission android:name="android.permission.CALL_PHONE" /> -->
|
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
||||||
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
||||||
<uses-permission android:name="android.permission.RAISED_THREAD_PRIORITY" />
|
<uses-permission android:name="android.permission.RAISED_THREAD_PRIORITY" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
|
|
||||||
|
<!-- Unused permissions that need to be removed -->
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH" tools:node="remove"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" tools:node="remove"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="org.thoughtcrime.securesms.ApplicationContext"
|
android:name="org.thoughtcrime.securesms.ApplicationContext"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
@ -101,22 +79,13 @@
|
|||||||
android:theme="@style/Session.DarkTheme"
|
android:theme="@style/Session.DarkTheme"
|
||||||
tools:replace="android:allowBackup">
|
tools:replace="android:allowBackup">
|
||||||
|
|
||||||
<meta-data
|
<!-- Disable analytics -->
|
||||||
android:name="io.fabric.ApiKey"
|
|
||||||
android:value="d0c4d13f424a96b9064aa0a9ecafabdb0db4287f" />
|
|
||||||
<meta-data
|
|
||||||
android:name="com.google.android.geo.API_KEY"
|
|
||||||
android:value="AIzaSyCSx9xea86GwDKGznCAULE9Y5a8b-TfN9U" />
|
|
||||||
<meta-data
|
|
||||||
android:name="com.google.android.gms.version"
|
|
||||||
android:value="@integer/google_play_services_version" />
|
|
||||||
<!--
|
|
||||||
<meta-data android:name="com.google.android.gms.car.application"
|
|
||||||
android:resource="@xml/automotive_app_desc" />
|
|
||||||
-->
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="firebase_analytics_collection_deactivated"
|
android:name="firebase_analytics_collection_deactivated"
|
||||||
android:value="true" />
|
android:value="true" />
|
||||||
|
<meta-data
|
||||||
|
android:name="firebase_crashlytics_collection_enabled"
|
||||||
|
android:value="false" />
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="google_analytics_adid_collection_enabled"
|
android:name="google_analytics_adid_collection_enabled"
|
||||||
android:value="false" />
|
android:value="false" />
|
||||||
@ -462,10 +431,6 @@
|
|||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
android:stateNotNeeded="true"
|
android:stateNotNeeded="true"
|
||||||
android:theme="@android:style/Theme.NoDisplay" />
|
android:theme="@android:style/Theme.NoDisplay" />
|
||||||
<activity
|
|
||||||
android:name="org.thoughtcrime.securesms.PlayServicesProblemActivity"
|
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
|
||||||
android:theme="@style/TextSecure.DialogActivity" />
|
|
||||||
<activity android:name="org.thoughtcrime.securesms.SmsSendtoActivity">
|
<activity android:name="org.thoughtcrime.securesms.SmsSendtoActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SENDTO" />
|
<action android:name="android.intent.action.SENDTO" />
|
||||||
@ -590,20 +555,6 @@
|
|||||||
android:name="android.accounts.AccountAuthenticator"
|
android:name="android.accounts.AccountAuthenticator"
|
||||||
android:resource="@xml/authenticator" />
|
android:resource="@xml/authenticator" />
|
||||||
</service>
|
</service>
|
||||||
<service
|
|
||||||
android:name="org.thoughtcrime.securesms.service.ContactsSyncAdapterService"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.content.SyncAdapter" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<meta-data
|
|
||||||
android:name="android.content.SyncAdapter"
|
|
||||||
android:resource="@xml/syncadapter" />
|
|
||||||
<meta-data
|
|
||||||
android:name="android.provider.CONTACTS_STRUCTURE"
|
|
||||||
android:resource="@xml/contactsformat" />
|
|
||||||
</service>
|
|
||||||
<service
|
<service
|
||||||
android:name="org.thoughtcrime.securesms.service.DirectShareService"
|
android:name="org.thoughtcrime.securesms.service.DirectShareService"
|
||||||
android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
|
android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
|
||||||
@ -612,11 +563,6 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
<service android:name="org.thoughtcrime.securesms.service.GenericForegroundService" />
|
<service android:name="org.thoughtcrime.securesms.service.GenericForegroundService" />
|
||||||
<service android:name="org.thoughtcrime.securesms.gcm.FcmService">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
|
||||||
</intent-filter>
|
|
||||||
</service>
|
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name="org.thoughtcrime.securesms.service.SmsListener"
|
android:name="org.thoughtcrime.securesms.service.SmsListener"
|
||||||
|
27
build.gradle
27
build.gradle
@ -11,13 +11,11 @@ buildscript {
|
|||||||
mavenLocal()
|
mavenLocal()
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven { url 'https://maven.fabric.io/public' }
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "com.android.tools.build:gradle:$gradle_version"
|
classpath "com.android.tools.build:gradle:$gradle_version"
|
||||||
classpath files('libs/gradle-witness.jar')
|
classpath files('libs/gradle-witness.jar')
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "io.fabric.tools:gradle:1.+"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +23,6 @@ apply plugin: 'com.android.application'
|
|||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-android-extensions'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply plugin: 'io.fabric'
|
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@ -62,7 +59,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
maven { url 'https://maven.fabric.io/public' }
|
|
||||||
maven { url "https://jitpack.io" }
|
maven { url "https://jitpack.io" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,16 +87,6 @@ dependencies {
|
|||||||
implementation 'android.arch.lifecycle:extensions:1.1.1'
|
implementation 'android.arch.lifecycle:extensions:1.1.1'
|
||||||
implementation 'android.arch.lifecycle:common-java8:1.1.1'
|
implementation 'android.arch.lifecycle:common-java8:1.1.1'
|
||||||
|
|
||||||
implementation('com.google.firebase:firebase-messaging:17.3.4') {
|
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-analytics'
|
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
|
|
||||||
}
|
|
||||||
|
|
||||||
implementation 'com.google.android.gms:play-services-maps:16.0.0'
|
|
||||||
implementation 'com.google.android.gms:play-services-places:16.0.0'
|
|
||||||
implementation 'com.google.android.gms:play-services-auth:16.0.1'
|
|
||||||
|
|
||||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.1'
|
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.1'
|
||||||
implementation 'com.google.android.exoplayer:exoplayer-ui:2.9.1'
|
implementation 'com.google.android.exoplayer:exoplayer-ui:2.9.1'
|
||||||
|
|
||||||
@ -186,7 +172,6 @@ dependencies {
|
|||||||
// Remote:
|
// Remote:
|
||||||
// implementation "com.github.loki-project:loki-messenger-android-service:dev-SNAPSHOT"
|
// implementation "com.github.loki-project:loki-messenger-android-service:dev-SNAPSHOT"
|
||||||
implementation "com.google.protobuf:protobuf-java:2.5.0"
|
implementation "com.google.protobuf:protobuf-java:2.5.0"
|
||||||
implementation "com.googlecode.libphonenumber:libphonenumber:8.10.7"
|
|
||||||
implementation "com.fasterxml.jackson.core:jackson-databind:2.9.8"
|
implementation "com.fasterxml.jackson.core:jackson-databind:2.9.8"
|
||||||
implementation "com.squareup.okhttp3:okhttp:3.12.1"
|
implementation "com.squareup.okhttp3:okhttp:3.12.1"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
@ -199,8 +184,8 @@ dependencies {
|
|||||||
implementation "com.github.ybq:Android-SpinKit:1.4.0"
|
implementation "com.github.ybq:Android-SpinKit:1.4.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
def canonicalVersionCode = 36
|
def canonicalVersionCode = 39
|
||||||
def canonicalVersionName = "1.0.2"
|
def canonicalVersionName = "1.0.5"
|
||||||
|
|
||||||
def postFixSize = 10
|
def postFixSize = 10
|
||||||
def abiPostFix = ['armeabi-v7a' : 1,
|
def abiPostFix = ['armeabi-v7a' : 1,
|
||||||
@ -279,8 +264,6 @@ android {
|
|||||||
debug {
|
debug {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
||||||
'proguard-firebase-messaging.pro',
|
|
||||||
'proguard-google-play-services.pro',
|
|
||||||
'proguard-dagger.pro',
|
'proguard-dagger.pro',
|
||||||
'proguard-jackson.pro',
|
'proguard-jackson.pro',
|
||||||
'proguard-sqlite.pro',
|
'proguard-sqlite.pro',
|
||||||
@ -371,12 +354,12 @@ android {
|
|||||||
|
|
||||||
def assembleWebsiteDescriptor = { variant, file ->
|
def assembleWebsiteDescriptor = { variant, file ->
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
MessageDigest md = MessageDigest.getInstance("SHA-256")
|
||||||
file.eachByte 4096, {bytes, size ->
|
file.eachByte 4096, {bytes, size ->
|
||||||
md.update(bytes, 0, size);
|
md.update(bytes, 0, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
String digest = md.digest().collect {String.format "%02x", it}.join();
|
String digest = md.digest().collect {String.format "%02x", it}.join()
|
||||||
String url = variant.productFlavors.get(0).ext.websiteUpdateUrl
|
String url = variant.productFlavors.get(0).ext.websiteUpdateUrl
|
||||||
String apkName = file.getName()
|
String apkName = file.getName()
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
-dontwarn com.google.firebase.analytics.connector.AnalyticsConnector
|
|
@ -1,19 +0,0 @@
|
|||||||
## Google Play Services 4.3.23 specific rules ##
|
|
||||||
## https://developer.android.com/google/play-services/setup.html#Proguard ##
|
|
||||||
|
|
||||||
-keep class * extends java.util.ListResourceBundle {
|
|
||||||
protected Object[][] getContents();
|
|
||||||
}
|
|
||||||
|
|
||||||
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
|
|
||||||
public static final *** NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
-keepnames @com.google.android.gms.common.annotation.KeepName class *
|
|
||||||
-keepclassmembernames class * {
|
|
||||||
@com.google.android.gms.common.annotation.KeepName *;
|
|
||||||
}
|
|
||||||
|
|
||||||
-keepnames class * implements android.os.Parcelable {
|
|
||||||
public static final ** CREATOR;
|
|
||||||
}
|
|
@ -1,8 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<merge
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
@ -39,23 +37,6 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/footer_sim_info"
|
|
||||||
android:autoLink="none"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:maxWidth="140dp"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:linksClickable="false"
|
|
||||||
style="@style/Signal.Text.Caption.MessageSent"
|
|
||||||
android:layout_gravity="end|bottom"
|
|
||||||
android:fontFamily="sans-serif-light"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible"
|
|
||||||
tools:text="to SIM1" />
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/footer_insecure_indicator"
|
android:id="@+id/footer_insecure_indicator"
|
||||||
android:layout_width="12dp"
|
android:layout_width="12dp"
|
||||||
|
@ -5,11 +5,13 @@
|
|||||||
<FrameLayout android:layout_width="match_parent"
|
<FrameLayout android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1">
|
android:layout_weight="1">
|
||||||
|
<!--
|
||||||
<com.google.android.gms.maps.MapView
|
<com.google.android.gms.maps.MapView
|
||||||
android:id="@+id/map_view"
|
android:id="@+id/map_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="gone"/>
|
android:visibility="gone"/>
|
||||||
|
-->
|
||||||
|
|
||||||
<ImageView android:id="@+id/image_view"
|
<ImageView android:id="@+id/image_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string name="google_app_id" translatable="false">1:312334754206:android:a9297b152879f266</string>
|
|
||||||
<string name="gcm_defaultSenderId" translatable="false">312334754206</string>
|
|
||||||
<string name="default_web_client_id" translatable="false">312334754206-dg1p1mtekis8ivja3ica50vonmrlunh4.apps.googleusercontent.com</string>
|
|
||||||
<string name="firebase_database_url" translatable="false">https://api-project-312334754206.firebaseio.com</string>
|
|
||||||
<string name="google_api_key" translatable="false">AIzaSyDrfzNAPBPzX6key51hqo3p5LZXF5Y-yxU</string>
|
|
||||||
<string name="google_crash_reporting_api_key" translatable="false">AIzaSyDrfzNAPBPzX6key51hqo3p5LZXF5Y-yxU</string>
|
|
||||||
<string name="project_id" translatable="false">api-project-312334754206</string>
|
|
||||||
</resources>
|
|
@ -16,7 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms;
|
package org.thoughtcrime.securesms;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.arch.lifecycle.DefaultLifecycleObserver;
|
import android.arch.lifecycle.DefaultLifecycleObserver;
|
||||||
import android.arch.lifecycle.LifecycleOwner;
|
import android.arch.lifecycle.LifecycleOwner;
|
||||||
import android.arch.lifecycle.ProcessLifecycleOwner;
|
import android.arch.lifecycle.ProcessLifecycleOwner;
|
||||||
@ -31,8 +30,6 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.multidex.MultiDexApplication;
|
import android.support.multidex.MultiDexApplication;
|
||||||
|
|
||||||
import com.google.android.gms.security.ProviderInstaller;
|
|
||||||
|
|
||||||
import org.conscrypt.Conscrypt;
|
import org.conscrypt.Conscrypt;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.signal.aesgcmprovider.AesGcmProvider;
|
import org.signal.aesgcmprovider.AesGcmProvider;
|
||||||
@ -53,7 +50,6 @@ import org.thoughtcrime.securesms.jobmanager.JobManager;
|
|||||||
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
|
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
|
||||||
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
||||||
import org.thoughtcrime.securesms.jobs.FastJobStorage;
|
import org.thoughtcrime.securesms.jobs.FastJobStorage;
|
||||||
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
|
|
||||||
import org.thoughtcrime.securesms.jobs.JobManagerFactories;
|
import org.thoughtcrime.securesms.jobs.JobManagerFactories;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
||||||
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob;
|
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob;
|
||||||
@ -115,7 +111,6 @@ import java.util.Date;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import dagger.ObjectGraph;
|
import dagger.ObjectGraph;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
@ -176,10 +171,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
initializeExpiringMessageManager();
|
initializeExpiringMessageManager();
|
||||||
initializeTypingStatusRepository();
|
initializeTypingStatusRepository();
|
||||||
initializeTypingStatusSender();
|
initializeTypingStatusSender();
|
||||||
initializeGcmCheck();
|
|
||||||
initializeSignedPreKeyCheck();
|
initializeSignedPreKeyCheck();
|
||||||
initializePeriodicTasks();
|
initializePeriodicTasks();
|
||||||
initializeCircumvention();
|
|
||||||
initializeWebRtc();
|
initializeWebRtc();
|
||||||
initializePendingMessages();
|
initializePendingMessages();
|
||||||
initializeUnidentifiedDeliveryAbilityRefresh();
|
initializeUnidentifiedDeliveryAbilityRefresh();
|
||||||
@ -194,6 +187,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
if (userHexEncodedPublicKey != null) {
|
if (userHexEncodedPublicKey != null) {
|
||||||
if (TextSecurePreferences.getNeedsIsRevokedSlaveDeviceCheck(this)) {
|
if (TextSecurePreferences.getNeedsIsRevokedSlaveDeviceCheck(this)) {
|
||||||
MultiDeviceUtilities.checkIsRevokedSlaveDevice(this);
|
MultiDeviceUtilities.checkIsRevokedSlaveDevice(this);
|
||||||
|
} else {
|
||||||
|
// We always update our current device links onto the server in case we failed to do so upon linking
|
||||||
|
MultiDeviceUtilities.updateDeviceLinksOnServer(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -337,16 +333,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
this.objectGraph = ObjectGraph.create(communicationModule, new AxolotlStorageModule(this));
|
this.objectGraph = ObjectGraph.create(communicationModule, new AxolotlStorageModule(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeGcmCheck() {
|
|
||||||
if (TextSecurePreferences.isPushRegistered(this)) {
|
|
||||||
long nextSetTime = TextSecurePreferences.getFcmTokenLastSetTime(this) + TimeUnit.HOURS.toMillis(6);
|
|
||||||
|
|
||||||
if (TextSecurePreferences.getFcmToken(this) == null || nextSetTime <= System.currentTimeMillis()) {
|
|
||||||
this.jobManager.add(new FcmRefreshJob());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeSignedPreKeyCheck() {
|
private void initializeSignedPreKeyCheck() {
|
||||||
if (!TextSecurePreferences.isSignedPreKeyRegistered(this)) {
|
if (!TextSecurePreferences.isSignedPreKeyRegistered(this)) {
|
||||||
jobManager.add(new CreateSignedPreKeyJob(this));
|
jobManager.add(new CreateSignedPreKeyJob(this));
|
||||||
@ -413,25 +399,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
private void initializeCircumvention() {
|
|
||||||
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... params) {
|
|
||||||
if (new SignalServiceNetworkAccess(ApplicationContext.this).isCensored(ApplicationContext.this)) {
|
|
||||||
try {
|
|
||||||
ProviderInstaller.installIfNeeded(ApplicationContext.this);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
Log.w(TAG, t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void executePendingContactSync() {
|
private void executePendingContactSync() {
|
||||||
if (TextSecurePreferences.needsFullContactSync(this)) {
|
if (TextSecurePreferences.needsFullContactSync(this)) {
|
||||||
ApplicationContext.getInstance(this).getJobManager().add(new MultiDeviceContactUpdateJob(this, true));
|
ApplicationContext.getInstance(this).getJobManager().add(new MultiDeviceContactUpdateJob(this, true));
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.v4.app.FragmentActivity;
|
|
||||||
|
|
||||||
public class PlayServicesProblemActivity extends FragmentActivity {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle bundle) {
|
|
||||||
super.onCreate(bundle);
|
|
||||||
PlayServicesProblemFragment fragment = new PlayServicesProblemFragment();
|
|
||||||
fragment.show(getSupportFragmentManager(), "dialog");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.thoughtcrime.securesms;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v4.app.DialogFragment;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
|
|
||||||
import com.google.android.gms.common.GoogleApiAvailability;
|
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
|
|
||||||
public class PlayServicesProblemFragment extends DialogFragment {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NonNull Dialog onCreateDialog(@Nullable Bundle bundle) {
|
|
||||||
int code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(getActivity());
|
|
||||||
Dialog dialog = GoogleApiAvailability.getInstance().getErrorDialog(getActivity(), code, 9111);
|
|
||||||
|
|
||||||
if (dialog == null) {
|
|
||||||
return new AlertDialog.Builder(requireActivity())
|
|
||||||
.setNegativeButton(android.R.string.ok, null)
|
|
||||||
.setMessage(R.string.PlayServicesProblemFragment_the_version_of_google_play_services_you_have_installed_is_not_functioning)
|
|
||||||
.create();
|
|
||||||
} else {
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
super.onCancel(dialog);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDismiss(DialogInterface dialog) {
|
|
||||||
super.onDismiss(dialog);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finish() {
|
|
||||||
Activity activity = getActivity();
|
|
||||||
if (activity != null) activity.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -3,10 +3,8 @@ package org.thoughtcrime.securesms;
|
|||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@ -29,17 +27,6 @@ import android.widget.TextView;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.dd.CircularProgressButton;
|
import com.dd.CircularProgressButton;
|
||||||
import com.google.android.gms.auth.api.phone.SmsRetriever;
|
|
||||||
import com.google.android.gms.auth.api.phone.SmsRetrieverClient;
|
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
|
||||||
import com.google.android.gms.common.GoogleApiAvailability;
|
|
||||||
import com.google.android.gms.common.api.CommonStatusCodes;
|
|
||||||
import com.google.android.gms.common.api.Status;
|
|
||||||
import com.google.android.gms.tasks.Task;
|
|
||||||
import com.google.i18n.phonenumbers.AsYouTypeFormatter;
|
|
||||||
import com.google.i18n.phonenumbers.NumberParseException;
|
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
|
||||||
import com.google.i18n.phonenumbers.Phonenumber;
|
|
||||||
|
|
||||||
import net.sqlcipher.database.SQLiteDatabase;
|
import net.sqlcipher.database.SQLiteDatabase;
|
||||||
|
|
||||||
@ -62,7 +49,6 @@ import org.thoughtcrime.securesms.database.Address;
|
|||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
import org.thoughtcrime.securesms.database.NoExternalStorageException;
|
import org.thoughtcrime.securesms.database.NoExternalStorageException;
|
||||||
import org.thoughtcrime.securesms.gcm.FcmUtil;
|
|
||||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RotateCertificateJob;
|
import org.thoughtcrime.securesms.jobs.RotateCertificateJob;
|
||||||
import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
|
import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
|
||||||
@ -73,12 +59,9 @@ import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
|||||||
import org.thoughtcrime.securesms.registration.CaptchaActivity;
|
import org.thoughtcrime.securesms.registration.CaptchaActivity;
|
||||||
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
|
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
|
||||||
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
||||||
import org.thoughtcrime.securesms.service.VerificationCodeParser;
|
|
||||||
import org.thoughtcrime.securesms.util.BackupUtil;
|
import org.thoughtcrime.securesms.util.BackupUtil;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
import org.thoughtcrime.securesms.util.Dialogs;
|
import org.thoughtcrime.securesms.util.Dialogs;
|
||||||
import org.thoughtcrime.securesms.util.PlayServicesUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.PlayServicesUtil.PlayServicesStatus;
|
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
@ -121,7 +104,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
|
|
||||||
private static final String TAG = RegistrationActivity.class.getSimpleName();
|
private static final String TAG = RegistrationActivity.class.getSimpleName();
|
||||||
|
|
||||||
private AsYouTypeFormatter countryFormatter;
|
|
||||||
private ArrayAdapter<String> countrySpinnerAdapter;
|
private ArrayAdapter<String> countrySpinnerAdapter;
|
||||||
private Spinner countrySpinner;
|
private Spinner countrySpinner;
|
||||||
private LabeledEditText countryCode;
|
private LabeledEditText countryCode;
|
||||||
@ -149,7 +131,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
private VerificationPinKeyboard keyboard;
|
private VerificationPinKeyboard keyboard;
|
||||||
private VerificationCodeView verificationCodeView;
|
private VerificationCodeView verificationCodeView;
|
||||||
private RegistrationState registrationState;
|
private RegistrationState registrationState;
|
||||||
private SmsRetrieverReceiver smsRetrieverReceiver;
|
|
||||||
private SignalServiceAccountManager accountManager;
|
private SignalServiceAccountManager accountManager;
|
||||||
private int debugTapCounter;
|
private int debugTapCounter;
|
||||||
|
|
||||||
@ -163,13 +144,11 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
initializeSpinner();
|
initializeSpinner();
|
||||||
initializeNumber();
|
initializeNumber();
|
||||||
initializeBackupDetection();
|
initializeBackupDetection();
|
||||||
initializeChallengeListener();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
shutdownChallengeListener();
|
|
||||||
markAsVerifying(false);
|
markAsVerifying(false);
|
||||||
EventBus.getDefault().unregister(this);
|
EventBus.getDefault().unregister(this);
|
||||||
}
|
}
|
||||||
@ -179,7 +158,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
if (requestCode == PICK_COUNTRY && resultCode == RESULT_OK && data != null) {
|
if (requestCode == PICK_COUNTRY && resultCode == RESULT_OK && data != null) {
|
||||||
this.countryCode.setText(String.valueOf(data.getIntExtra("country_code", 1)));
|
this.countryCode.setText(String.valueOf(data.getIntExtra("country_code", 1)));
|
||||||
setCountryDisplay(data.getStringExtra("country_name"));
|
setCountryDisplay(data.getStringExtra("country_name"));
|
||||||
setCountryFormatter(data.getIntExtra("country_code", 1));
|
|
||||||
} else if (requestCode == CAPTCHA && resultCode == RESULT_OK && data != null) {
|
} else if (requestCode == CAPTCHA && resultCode == RESULT_OK && data != null) {
|
||||||
registrationState = new RegistrationState(Optional.fromNullable(data.getStringExtra(CaptchaActivity.KEY_TOKEN)), registrationState);
|
registrationState = new RegistrationState(Optional.fromNullable(data.getStringExtra(CaptchaActivity.KEY_TOKEN)), registrationState);
|
||||||
|
|
||||||
@ -286,24 +264,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
|
||||||
private void initializeNumber() {
|
private void initializeNumber() {
|
||||||
Optional<Phonenumber.PhoneNumber> localNumber = Optional.absent();
|
|
||||||
|
|
||||||
if (Permissions.hasAll(this, Manifest.permission.READ_PHONE_STATE)) {
|
|
||||||
localNumber = Util.getDeviceNumber(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (localNumber.isPresent()) {
|
|
||||||
this.countryCode.setText(String.valueOf(localNumber.get().getCountryCode()));
|
|
||||||
this.number.setText(String.valueOf(localNumber.get().getNationalNumber()));
|
|
||||||
} else {
|
|
||||||
Optional<String> simCountryIso = Util.getSimCountryIso(this);
|
|
||||||
|
|
||||||
if (simCountryIso.isPresent() && !TextUtils.isEmpty(simCountryIso.get())) {
|
|
||||||
this.countryCode.setText(String.valueOf(PhoneNumberUtil.getInstance().getCountryCodeForRegion(simCountryIso.get())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
@ -338,14 +299,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
this.countrySpinnerAdapter.add(value);
|
this.countrySpinnerAdapter.add(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCountryFormatter(int countryCode) {
|
|
||||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
|
||||||
String regionCode = util.getRegionCodeForCountryCode(countryCode);
|
|
||||||
|
|
||||||
if (regionCode == null) this.countryFormatter = null;
|
|
||||||
else this.countryFormatter = util.getAsYouTypeFormatter(regionCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getConfiguredE164Number() {
|
private String getConfiguredE164Number() {
|
||||||
return PhoneNumberFormatter.formatE164(countryCode.getText().toString(),
|
return PhoneNumberFormatter.formatE164(countryCode.getText().toString(),
|
||||||
number.getText().toString());
|
number.getText().toString());
|
||||||
@ -436,20 +389,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
Dialogs.showAlertDialog(this,
|
Dialogs.showAlertDialog(this,
|
||||||
getString(R.string.RegistrationActivity_invalid_number),
|
getString(R.string.RegistrationActivity_invalid_number),
|
||||||
String.format(getString(R.string.RegistrationActivity_the_number_you_specified_s_is_invalid), e164number));
|
String.format(getString(R.string.RegistrationActivity_the_number_you_specified_s_is_invalid), e164number));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayServicesStatus gcmStatus = PlayServicesUtil.getPlayServicesStatus(this);
|
|
||||||
|
|
||||||
if (gcmStatus == PlayServicesStatus.SUCCESS) {
|
|
||||||
handleRequestVerification(e164number, true);
|
|
||||||
} else if (gcmStatus == PlayServicesStatus.MISSING) {
|
|
||||||
handlePromptForNoPlayServices(e164number);
|
|
||||||
} else if (gcmStatus == PlayServicesStatus.NEEDS_UPDATE) {
|
|
||||||
GoogleApiAvailability.getInstance().getErrorDialog(this, ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED, 0).show();
|
|
||||||
} else {
|
|
||||||
Dialogs.showAlertDialog(this, getString(R.string.RegistrationActivity_play_services_error),
|
|
||||||
getString(R.string.RegistrationActivity_google_play_services_is_updating_or_unavailable));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,23 +396,8 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
createButton.setIndeterminateProgressMode(true);
|
createButton.setIndeterminateProgressMode(true);
|
||||||
createButton.setProgress(50);
|
createButton.setProgress(50);
|
||||||
|
|
||||||
if (gcmSupported) {
|
|
||||||
SmsRetrieverClient client = SmsRetriever.getClient(this);
|
|
||||||
Task<Void> task = client.startSmsRetriever();
|
|
||||||
|
|
||||||
task.addOnSuccessListener(none -> {
|
|
||||||
Log.i(TAG, "Successfully registered SMS listener.");
|
|
||||||
requestVerificationCode(e164number, true, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
task.addOnFailureListener(e -> {
|
|
||||||
Log.w(TAG, "Failed to register SMS listener.", e);
|
|
||||||
requestVerificationCode(e164number, true, false);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
requestVerificationCode(e164number, false, false);
|
requestVerificationCode(e164number, false, false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
private void requestVerificationCode(@NonNull String e164number, boolean gcmSupported, boolean smsRetrieverSupported) {
|
private void requestVerificationCode(@NonNull String e164number, boolean gcmSupported, boolean smsRetrieverSupported) {
|
||||||
@ -485,13 +409,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
|
|
||||||
String password = Util.getSecret(18);
|
String password = Util.getSecret(18);
|
||||||
|
|
||||||
Optional<String> fcmToken;
|
Optional<String> fcmToken = Optional.absent();
|
||||||
|
|
||||||
if (gcmSupported) {
|
|
||||||
fcmToken = FcmUtil.getToken();
|
|
||||||
} else {
|
|
||||||
fcmToken = Optional.absent();
|
|
||||||
}
|
|
||||||
|
|
||||||
accountManager = AccountManagerFactory.createManager(RegistrationActivity.this, e164number, password);
|
accountManager = AccountManagerFactory.createManager(RegistrationActivity.this, e164number, password);
|
||||||
accountManager.requestSmsVerificationCode(smsRetrieverSupported, registrationState.captchaToken);
|
accountManager.requestSmsVerificationCode(smsRetrieverSupported, registrationState.captchaToken);
|
||||||
@ -939,19 +857,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeChallengeListener() {
|
|
||||||
smsRetrieverReceiver = new SmsRetrieverReceiver();
|
|
||||||
IntentFilter filter = new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION);
|
|
||||||
registerReceiver(smsRetrieverReceiver, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void shutdownChallengeListener() {
|
|
||||||
if (smsRetrieverReceiver != null) {
|
|
||||||
unregisterReceiver(smsRetrieverReceiver);
|
|
||||||
smsRetrieverReceiver = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markAsVerifying(boolean verifying) {
|
private void markAsVerifying(boolean verifying) {
|
||||||
TextSecurePreferences.setVerifying(this, verifying);
|
TextSecurePreferences.setVerifying(this, verifying);
|
||||||
|
|
||||||
@ -961,13 +866,8 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String formatNumber(@NonNull String e164Number) {
|
private String formatNumber(@NonNull String e164Number) {
|
||||||
try {
|
|
||||||
Phonenumber.PhoneNumber number = PhoneNumberUtil.getInstance().parse(e164Number, null);
|
|
||||||
return PhoneNumberUtil.getInstance().format(number, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
return e164Number;
|
return e164Number;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void onWrongNumberClicked() {
|
private void onWrongNumberClicked() {
|
||||||
displayInitialView(false);
|
displayInitialView(false);
|
||||||
@ -980,53 +880,16 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
else restoreBackupProgress.setText(getString(R.string.RegistrationActivity_d_messages_so_far, event.getCount()));
|
else restoreBackupProgress.setText(getString(R.string.RegistrationActivity_d_messages_so_far, event.getCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SmsRetrieverReceiver extends BroadcastReceiver {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
Log.i(TAG, "SmsRetrieverReceiver received a broadcast...");
|
|
||||||
|
|
||||||
if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
|
|
||||||
Bundle extras = intent.getExtras();
|
|
||||||
Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
|
|
||||||
|
|
||||||
switch (status.getStatusCode()) {
|
|
||||||
case CommonStatusCodes.SUCCESS:
|
|
||||||
Optional<String> code = VerificationCodeParser.parse(context, (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE));
|
|
||||||
if (code.isPresent()) {
|
|
||||||
Log.i(TAG, "Received verification code.");
|
|
||||||
handleVerificationCodeReceived(code.get());
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Could not parse verification code.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CommonStatusCodes.TIMEOUT:
|
|
||||||
Log.w(TAG, "Hit a timeout waiting for the SMS to arrive.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "SmsRetrieverReceiver received the wrong action?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CountryCodeChangedListener implements TextWatcher {
|
private class CountryCodeChangedListener implements TextWatcher {
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable s) {
|
public void afterTextChanged(Editable s) {
|
||||||
if (TextUtils.isEmpty(s) || !TextUtils.isDigitsOnly(s)) {
|
if (TextUtils.isEmpty(s) || !TextUtils.isDigitsOnly(s)) {
|
||||||
setCountryDisplay(getString(R.string.RegistrationActivity_select_your_country));
|
setCountryDisplay(getString(R.string.RegistrationActivity_select_your_country));
|
||||||
countryFormatter = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int countryCode = Integer.parseInt(s.toString());
|
int countryCode = Integer.parseInt(s.toString());
|
||||||
String regionCode = PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(countryCode);
|
setCountryDisplay("N/A");
|
||||||
|
|
||||||
setCountryFormatter(countryCode);
|
|
||||||
setCountryDisplay(PhoneNumberFormatter.getRegionDisplayName(regionCode));
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(regionCode) && !regionCode.equals("ZZ")) {
|
|
||||||
number.requestFocus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1042,24 +905,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable s) {
|
public void afterTextChanged(Editable s) {
|
||||||
if (countryFormatter == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(s))
|
|
||||||
return;
|
|
||||||
|
|
||||||
countryFormatter.clear();
|
|
||||||
|
|
||||||
String number = s.toString().replaceAll("[^\\d.]", "");
|
|
||||||
String formattedNumber = null;
|
|
||||||
|
|
||||||
for (int i=0;i<number.length();i++) {
|
|
||||||
formattedNumber = countryFormatter.inputDigit(number.charAt(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formattedNumber != null && !s.toString().equals(formattedNumber)) {
|
|
||||||
s.replace(0, s.length(), formattedNumber);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.thoughtcrime.securesms.components;
|
package org.thoughtcrime.securesms.components;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
@ -14,22 +13,18 @@ import android.widget.LinearLayout;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
|
||||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
import org.thoughtcrime.securesms.util.dualsim.SubscriptionInfoCompat;
|
|
||||||
import org.thoughtcrime.securesms.util.dualsim.SubscriptionManagerCompat;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
public class ConversationItemFooter extends LinearLayout {
|
public class ConversationItemFooter extends LinearLayout {
|
||||||
|
|
||||||
private TextView dateView;
|
private TextView dateView;
|
||||||
private TextView simView;
|
|
||||||
private ExpirationTimerView timerView;
|
private ExpirationTimerView timerView;
|
||||||
private ImageView insecureIndicatorView;
|
private ImageView insecureIndicatorView;
|
||||||
private DeliveryStatusView deliveryStatusView;
|
private DeliveryStatusView deliveryStatusView;
|
||||||
@ -53,7 +48,6 @@ public class ConversationItemFooter extends LinearLayout {
|
|||||||
inflate(getContext(), R.layout.conversation_item_footer, this);
|
inflate(getContext(), R.layout.conversation_item_footer, this);
|
||||||
|
|
||||||
dateView = findViewById(R.id.footer_date);
|
dateView = findViewById(R.id.footer_date);
|
||||||
simView = findViewById(R.id.footer_sim_info);
|
|
||||||
timerView = findViewById(R.id.footer_expiration_timer);
|
timerView = findViewById(R.id.footer_expiration_timer);
|
||||||
insecureIndicatorView = findViewById(R.id.footer_insecure_indicator);
|
insecureIndicatorView = findViewById(R.id.footer_insecure_indicator);
|
||||||
deliveryStatusView = findViewById(R.id.footer_delivery_status);
|
deliveryStatusView = findViewById(R.id.footer_delivery_status);
|
||||||
@ -74,7 +68,6 @@ public class ConversationItemFooter extends LinearLayout {
|
|||||||
|
|
||||||
public void setMessageRecord(@NonNull MessageRecord messageRecord, @NonNull Locale locale) {
|
public void setMessageRecord(@NonNull MessageRecord messageRecord, @NonNull Locale locale) {
|
||||||
presentDate(messageRecord, locale);
|
presentDate(messageRecord, locale);
|
||||||
presentSimInfo(messageRecord);
|
|
||||||
presentTimer(messageRecord);
|
presentTimer(messageRecord);
|
||||||
presentInsecureIndicator(messageRecord);
|
presentInsecureIndicator(messageRecord);
|
||||||
presentDeliveryStatus(messageRecord);
|
presentDeliveryStatus(messageRecord);
|
||||||
@ -82,7 +75,6 @@ public class ConversationItemFooter extends LinearLayout {
|
|||||||
|
|
||||||
public void setTextColor(int color) {
|
public void setTextColor(int color) {
|
||||||
dateView.setTextColor(color);
|
dateView.setTextColor(color);
|
||||||
simView.setTextColor(color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIconColor(int color) {
|
public void setIconColor(int color) {
|
||||||
@ -103,26 +95,6 @@ public class ConversationItemFooter extends LinearLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void presentSimInfo(@NonNull MessageRecord messageRecord) {
|
|
||||||
SubscriptionManagerCompat subscriptionManager = new SubscriptionManagerCompat(getContext());
|
|
||||||
|
|
||||||
if (messageRecord.isPush() || messageRecord.getSubscriptionId() == -1 || !Permissions.hasAll(getContext(), Manifest.permission.READ_PHONE_STATE) || !subscriptionManager.isMultiSim()) {
|
|
||||||
simView.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
Optional<SubscriptionInfoCompat> subscriptionInfo = subscriptionManager.getActiveSubscriptionInfo(messageRecord.getSubscriptionId());
|
|
||||||
|
|
||||||
if (subscriptionInfo.isPresent() && messageRecord.isOutgoing()) {
|
|
||||||
simView.setText(getContext().getString(R.string.ConversationItem_from_s, subscriptionInfo.get().getDisplayName()));
|
|
||||||
simView.setVisibility(View.VISIBLE);
|
|
||||||
} else if (subscriptionInfo.isPresent()) {
|
|
||||||
simView.setText(getContext().getString(R.string.ConversationItem_to_s, subscriptionInfo.get().getDisplayName()));
|
|
||||||
simView.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
simView.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
private void presentTimer(@NonNull final MessageRecord messageRecord) {
|
private void presentTimer(@NonNull final MessageRecord messageRecord) {
|
||||||
if (messageRecord.getExpiresIn() > 0 && !messageRecord.isPending()) {
|
if (messageRecord.getExpiresIn() > 0 && !messageRecord.isPending()) {
|
||||||
|
@ -7,26 +7,18 @@ import android.os.Build;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.google.android.gms.location.places.Place;
|
|
||||||
import com.google.android.gms.maps.CameraUpdateFactory;
|
|
||||||
import com.google.android.gms.maps.GoogleMap;
|
|
||||||
import com.google.android.gms.maps.MapView;
|
|
||||||
import com.google.android.gms.maps.OnMapReadyCallback;
|
|
||||||
import com.google.android.gms.maps.model.MarkerOptions;
|
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
||||||
|
|
||||||
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
public class SignalMapView extends LinearLayout {
|
public class SignalMapView extends LinearLayout {
|
||||||
|
|
||||||
private MapView mapView;
|
|
||||||
private ImageView imageView;
|
private ImageView imageView;
|
||||||
private TextView textView;
|
private TextView textView;
|
||||||
|
|
||||||
@ -49,7 +41,6 @@ public class SignalMapView extends LinearLayout {
|
|||||||
setOrientation(LinearLayout.VERTICAL);
|
setOrientation(LinearLayout.VERTICAL);
|
||||||
LayoutInflater.from(context).inflate(R.layout.signal_map_view, this, true);
|
LayoutInflater.from(context).inflate(R.layout.signal_map_view, this, true);
|
||||||
|
|
||||||
this.mapView = ViewUtil.findById(this, R.id.map_view);
|
|
||||||
this.imageView = ViewUtil.findById(this, R.id.image_view);
|
this.imageView = ViewUtil.findById(this, R.id.image_view);
|
||||||
this.textView = ViewUtil.findById(this, R.id.address_view);
|
this.textView = ViewUtil.findById(this, R.id.address_view);
|
||||||
}
|
}
|
||||||
@ -57,39 +48,8 @@ public class SignalMapView extends LinearLayout {
|
|||||||
public ListenableFuture<Bitmap> display(final SignalPlace place) {
|
public ListenableFuture<Bitmap> display(final SignalPlace place) {
|
||||||
final SettableFuture<Bitmap> future = new SettableFuture<>();
|
final SettableFuture<Bitmap> future = new SettableFuture<>();
|
||||||
|
|
||||||
this.mapView.onCreate(null);
|
|
||||||
this.mapView.onResume();
|
|
||||||
|
|
||||||
this.mapView.setVisibility(View.VISIBLE);
|
|
||||||
this.imageView.setVisibility(View.GONE);
|
this.imageView.setVisibility(View.GONE);
|
||||||
|
|
||||||
this.mapView.getMapAsync(new OnMapReadyCallback() {
|
|
||||||
@Override
|
|
||||||
public void onMapReady(final GoogleMap googleMap) {
|
|
||||||
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(place.getLatLong(), 13));
|
|
||||||
googleMap.addMarker(new MarkerOptions().position(place.getLatLong()));
|
|
||||||
googleMap.setBuildingsEnabled(true);
|
|
||||||
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
|
|
||||||
googleMap.getUiSettings().setAllGesturesEnabled(false);
|
|
||||||
googleMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
|
|
||||||
@Override
|
|
||||||
public void onMapLoaded() {
|
|
||||||
googleMap.snapshot(new GoogleMap.SnapshotReadyCallback() {
|
|
||||||
@Override
|
|
||||||
public void onSnapshotReady(Bitmap bitmap) {
|
|
||||||
future.set(bitmap);
|
|
||||||
imageView.setImageBitmap(bitmap);
|
|
||||||
imageView.setVisibility(View.VISIBLE);
|
|
||||||
mapView.setVisibility(View.GONE);
|
|
||||||
mapView.onPause();
|
|
||||||
mapView.onDestroy();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.textView.setText(place.getDescription());
|
this.textView.setText(place.getDescription());
|
||||||
|
|
||||||
return future;
|
return future;
|
||||||
|
@ -7,8 +7,6 @@ import android.text.TextUtils;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.google.android.gms.location.places.Place;
|
|
||||||
import com.google.android.gms.maps.model.LatLng;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
@ -17,6 +15,22 @@ import java.io.IOException;
|
|||||||
|
|
||||||
public class SignalPlace {
|
public class SignalPlace {
|
||||||
|
|
||||||
|
/* Loki - Temporary Placeholders */
|
||||||
|
class LatLng {
|
||||||
|
double latitude;
|
||||||
|
double longitude;
|
||||||
|
LatLng(double latitude, double longitude) {
|
||||||
|
this.latitude = latitude;
|
||||||
|
this.longitude = longitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Place {
|
||||||
|
public CharSequence getName() { return ""; }
|
||||||
|
public CharSequence getAddress() { return ""; }
|
||||||
|
LatLng getLatLng() { return new LatLng(0, 0); }
|
||||||
|
}
|
||||||
|
|
||||||
private static final String URL = "https://maps.google.com/maps";
|
private static final String URL = "https://maps.google.com/maps";
|
||||||
private static final String TAG = SignalPlace.class.getSimpleName();
|
private static final String TAG = SignalPlace.class.getSimpleName();
|
||||||
|
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.contacts;
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.content.AbstractThreadedSyncAdapter;
|
|
||||||
import android.content.ContentProviderClient;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SyncResult;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.util.DirectoryHelper;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class ContactsSyncAdapter extends AbstractThreadedSyncAdapter {
|
|
||||||
|
|
||||||
private static final String TAG = ContactsSyncAdapter.class.getSimpleName();
|
|
||||||
|
|
||||||
public ContactsSyncAdapter(Context context, boolean autoInitialize) {
|
|
||||||
super(context, autoInitialize);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPerformSync(Account account, Bundle extras, String authority,
|
|
||||||
ContentProviderClient provider, SyncResult syncResult)
|
|
||||||
{
|
|
||||||
Log.i(TAG, "onPerformSync(" + authority +")");
|
|
||||||
|
|
||||||
if (TextSecurePreferences.isPushRegistered(getContext())) {
|
|
||||||
try {
|
|
||||||
DirectoryHelper.refreshDirectory(getContext(), true);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSyncCanceled() {
|
|
||||||
Log.w(TAG, "onSyncCanceled()");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSyncCanceled(Thread thread) {
|
|
||||||
Log.w(TAG, "onSyncCanceled(" + thread + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -13,11 +13,7 @@ import android.support.v7.app.AlertDialog;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
import com.google.i18n.phonenumbers.NumberParseException;
|
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
|
||||||
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
|
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiStrings;
|
import org.thoughtcrime.securesms.components.emoji.EmojiStrings;
|
||||||
import org.thoughtcrime.securesms.contactshare.Contact.Email;
|
import org.thoughtcrime.securesms.contactshare.Contact.Email;
|
||||||
import org.thoughtcrime.securesms.contactshare.Contact.Phone;
|
import org.thoughtcrime.securesms.contactshare.Contact.Phone;
|
||||||
@ -34,6 +30,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
public final class ContactUtil {
|
public final class ContactUtil {
|
||||||
|
|
||||||
private static final String TAG = ContactUtil.class.getSimpleName();
|
private static final String TAG = ContactUtil.class.getSimpleName();
|
||||||
@ -102,14 +100,8 @@ public final class ContactUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static @NonNull String getPrettyPhoneNumber(@NonNull String phoneNumber, @NonNull Locale fallbackLocale) {
|
private static @NonNull String getPrettyPhoneNumber(@NonNull String phoneNumber, @NonNull Locale fallbackLocale) {
|
||||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
|
||||||
try {
|
|
||||||
PhoneNumber parsed = util.parse(phoneNumber, fallbackLocale.getISO3Country());
|
|
||||||
return util.format(parsed, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
return phoneNumber;
|
return phoneNumber;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static @NonNull String getNormalizedPhoneNumber(@NonNull Context context, @NonNull String number) {
|
public static @NonNull String getNormalizedPhoneNumber(@NonNull Context context, @NonNull String number) {
|
||||||
Address address = Address.fromExternal(context, number);
|
Address address = Address.fromExternal(context, number);
|
||||||
|
@ -77,7 +77,6 @@ import android.widget.TextView;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
import com.google.android.gms.location.places.ui.PlacePicker;
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
import org.greenrobot.eventbus.Subscribe;
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
@ -133,7 +132,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|||||||
import org.thoughtcrime.securesms.database.DraftDatabase;
|
import org.thoughtcrime.securesms.database.DraftDatabase;
|
||||||
import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
|
import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
|
||||||
import org.thoughtcrime.securesms.database.DraftDatabase.Drafts;
|
import org.thoughtcrime.securesms.database.DraftDatabase.Drafts;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||||
@ -179,7 +177,6 @@ import org.thoughtcrime.securesms.mms.ImageSlide;
|
|||||||
import org.thoughtcrime.securesms.mms.LocationSlide;
|
import org.thoughtcrime.securesms.mms.LocationSlide;
|
||||||
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.QuoteId;
|
import org.thoughtcrime.securesms.mms.QuoteId;
|
||||||
@ -662,10 +659,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
recipient.addListener(this);
|
recipient.addListener(this);
|
||||||
fragment.reloadList();
|
fragment.reloadList();
|
||||||
break;
|
break;
|
||||||
|
/*
|
||||||
case PICK_LOCATION:
|
case PICK_LOCATION:
|
||||||
SignalPlace place = new SignalPlace(PlacePicker.getPlace(data, this));
|
SignalPlace place = new SignalPlace(PlacePicker.getPlace(data, this));
|
||||||
attachmentManager.setLocation(place, getCurrentMediaConstraints());
|
attachmentManager.setLocation(place, getCurrentMediaConstraints());
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
case PICK_GIF:
|
case PICK_GIF:
|
||||||
setMedia(data.getData(),
|
setMedia(data.getData(),
|
||||||
MediaType.GIF,
|
MediaType.GIF,
|
||||||
@ -1240,15 +1239,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleDisplayQuickContact() {
|
private boolean handleDisplayQuickContact() {
|
||||||
if (recipient.getAddress().isGroup()) return false;
|
return !recipient.getAddress().isGroup();
|
||||||
|
|
||||||
// if (recipient.getContactUri() != null) {
|
// if (recipient.getContactUri() != null) {
|
||||||
// ContactsContract.QuickContact.showQuickContact(ConversationActivity.this, titleView, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
// ContactsContract.QuickContact.showQuickContact(ConversationActivity.this, titleView, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
||||||
// } else {
|
// } else {
|
||||||
// handleAddToContacts();
|
// handleAddToContacts();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleAddAttachment() {
|
private void handleAddAttachment() {
|
||||||
|
@ -10,12 +10,6 @@ import android.support.annotation.VisibleForTesting;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.google.i18n.phonenumbers.NumberParseException;
|
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
|
||||||
import com.google.i18n.phonenumbers.Phonenumber;
|
|
||||||
import com.google.i18n.phonenumbers.ShortNumberInfo;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.NumberUtil;
|
import org.thoughtcrime.securesms.util.NumberUtil;
|
||||||
@ -111,7 +105,7 @@ public class Address implements Parcelable, Comparable<Address> {
|
|||||||
|
|
||||||
public boolean isGroup() { return GroupUtil.isEncodedGroup(address); }
|
public boolean isGroup() { return GroupUtil.isEncodedGroup(address); }
|
||||||
|
|
||||||
public boolean isSignalGroup() { return !isPublicChat() && !isRSSFeed(); }
|
public boolean isSignalGroup() { return GroupUtil.isSignalGroup(address); }
|
||||||
|
|
||||||
public boolean isPublicChat() { return GroupUtil.isPublicChat(address); }
|
public boolean isPublicChat() { return GroupUtil.isPublicChat(address); }
|
||||||
|
|
||||||
@ -200,19 +194,10 @@ public class Address implements Parcelable, Comparable<Address> {
|
|||||||
private final Optional<PhoneNumber> localNumber;
|
private final Optional<PhoneNumber> localNumber;
|
||||||
private final String localCountryCode;
|
private final String localCountryCode;
|
||||||
|
|
||||||
private final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
|
|
||||||
private final Pattern ALPHA_PATTERN = Pattern.compile("[a-zA-Z]");
|
private final Pattern ALPHA_PATTERN = Pattern.compile("[a-zA-Z]");
|
||||||
|
|
||||||
ExternalAddressFormatter(@NonNull String localNumberString) {
|
ExternalAddressFormatter(@NonNull String localNumberString) {
|
||||||
try {
|
throw new AssertionError("Not Implemented");
|
||||||
Phonenumber.PhoneNumber libNumber = phoneNumberUtil.parse(localNumberString, null);
|
|
||||||
int countryCode = libNumber.getCountryCode();
|
|
||||||
|
|
||||||
this.localNumber = Optional.of(new PhoneNumber(localNumberString, countryCode, parseAreaCode(localNumberString, countryCode)));
|
|
||||||
this.localCountryCode = phoneNumberUtil.getRegionCodeForNumber(libNumber);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalAddressFormatter(@NonNull String localCountryCode, boolean countryCode) {
|
ExternalAddressFormatter(@NonNull String localCountryCode, boolean countryCode) {
|
||||||
@ -222,61 +207,7 @@ public class Address implements Parcelable, Comparable<Address> {
|
|||||||
|
|
||||||
public String format(@Nullable String number) {
|
public String format(@Nullable String number) {
|
||||||
if (number == null) return "Unknown";
|
if (number == null) return "Unknown";
|
||||||
if (GroupUtil.isEncodedGroup(number)) return number;
|
return number;
|
||||||
if (ALPHA_PATTERN.matcher(number).find()) return number.trim();
|
|
||||||
|
|
||||||
String bareNumber = number.replaceAll("[^0-9+]", "");
|
|
||||||
|
|
||||||
if (bareNumber.length() == 0) {
|
|
||||||
if (number.trim().length() == 0) return "Unknown";
|
|
||||||
else return number.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
// libphonenumber doesn't seem to be correct for Germany and Finland
|
|
||||||
if (bareNumber.length() <= 6 && ("DE".equals(localCountryCode) || "FI".equals(localCountryCode) || "SK".equals(localCountryCode))) {
|
|
||||||
return bareNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
// libphonenumber seems incorrect for Russia and a few other countries with 4 digit short codes.
|
|
||||||
if (bareNumber.length() <= 4 && !SHORT_COUNTRIES.contains(localCountryCode)) {
|
|
||||||
return bareNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isShortCode(bareNumber, localCountryCode)) {
|
|
||||||
return bareNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
String processedNumber = applyAreaCodeRules(localNumber, bareNumber);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Phonenumber.PhoneNumber parsedNumber = phoneNumberUtil.parse(processedNumber, localCountryCode);
|
|
||||||
return phoneNumberUtil.format(parsedNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
if (bareNumber.charAt(0) == '+')
|
|
||||||
return bareNumber;
|
|
||||||
|
|
||||||
String localNumberImprecise = localNumber.isPresent() ? localNumber.get().getE164Number() : "";
|
|
||||||
|
|
||||||
if (localNumberImprecise.charAt(0) == '+')
|
|
||||||
localNumberImprecise = localNumberImprecise.substring(1);
|
|
||||||
|
|
||||||
if (localNumberImprecise.length() == bareNumber.length() || bareNumber.length() > localNumberImprecise.length())
|
|
||||||
return "+" + number;
|
|
||||||
|
|
||||||
int difference = localNumberImprecise.length() - bareNumber.length();
|
|
||||||
|
|
||||||
return "+" + localNumberImprecise.substring(0, difference) + bareNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isShortCode(@NonNull String bareNumber, String localCountryCode) {
|
|
||||||
try {
|
|
||||||
Phonenumber.PhoneNumber parsedNumber = phoneNumberUtil.parse(bareNumber, localCountryCode);
|
|
||||||
return ShortNumberInfo.getInstance().isPossibleShortNumberForRegion(parsedNumber, localCountryCode);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable String parseAreaCode(@NonNull String e164Number, int countryCode) {
|
private @Nullable String parseAreaCode(@NonNull String e164Number, int countryCode) {
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
package org.thoughtcrime.securesms.database.helpers;
|
package org.thoughtcrime.securesms.database.helpers;
|
||||||
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteConstraintException;
|
import android.database.sqlite.SQLiteConstraintException;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.net.Uri;
|
|
||||||
import android.provider.ContactsContract;
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.google.i18n.phonenumbers.NumberParseException;
|
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
|
||||||
import com.google.i18n.phonenumbers.Phonenumber;
|
|
||||||
import com.google.i18n.phonenumbers.ShortNumberInfo;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.DatabaseUpgradeActivity;
|
import org.thoughtcrime.securesms.DatabaseUpgradeActivity;
|
||||||
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
|
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
|
||||||
@ -26,7 +18,6 @@ import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
|
||||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||||
import org.thoughtcrime.securesms.database.DraftDatabase;
|
import org.thoughtcrime.securesms.database.DraftDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
@ -37,8 +28,8 @@ import org.thoughtcrime.securesms.database.PushDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||||
import org.thoughtcrime.securesms.util.Hex;
|
import org.thoughtcrime.securesms.util.Hex;
|
||||||
@ -1385,71 +1376,18 @@ public class ClassicOpenHelper extends SQLiteOpenHelper {
|
|||||||
add("AC");
|
add("AC");
|
||||||
}};
|
}};
|
||||||
|
|
||||||
private final Phonenumber.PhoneNumber localNumber;
|
|
||||||
private final String localNumberString;
|
private final String localNumberString;
|
||||||
private final String localCountryCode;
|
|
||||||
|
|
||||||
private final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
|
|
||||||
private final Pattern ALPHA_PATTERN = Pattern.compile("[a-zA-Z]");
|
private final Pattern ALPHA_PATTERN = Pattern.compile("[a-zA-Z]");
|
||||||
|
|
||||||
|
|
||||||
public NumberMigrator(String localNumber) {
|
public NumberMigrator(String localNumber) {
|
||||||
try {
|
|
||||||
this.localNumberString = localNumber;
|
this.localNumberString = localNumber;
|
||||||
this.localNumber = phoneNumberUtil.parse(localNumber, null);
|
|
||||||
this.localCountryCode = phoneNumberUtil.getRegionCodeForNumber(this.localNumber);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String migrate(@Nullable String number) {
|
public String migrate(@Nullable String number) {
|
||||||
if (number == null) return "Unknown";
|
if (number == null) return "Unknown";
|
||||||
if (number.startsWith("__textsecure_group__!")) return number;
|
return number;
|
||||||
if (ALPHA_PATTERN.matcher(number).find()) return number.trim();
|
|
||||||
|
|
||||||
String bareNumber = number.replaceAll("[^0-9+]", "");
|
|
||||||
|
|
||||||
if (bareNumber.length() == 0) {
|
|
||||||
if (TextUtils.isEmpty(number.trim())) return "Unknown";
|
|
||||||
else return number.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
// libphonenumber doesn't seem to be correct for Germany and Finland
|
|
||||||
if (bareNumber.length() <= 6 && ("DE".equals(localCountryCode) || "FI".equals(localCountryCode) || "SK".equals(localCountryCode))) {
|
|
||||||
return bareNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
// libphonenumber seems incorrect for Russia and a few other countries with 4 digit short codes.
|
|
||||||
if (bareNumber.length() <= 4 && !SHORT_COUNTRIES.contains(localCountryCode)) {
|
|
||||||
return bareNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Phonenumber.PhoneNumber parsedNumber = phoneNumberUtil.parse(bareNumber, localCountryCode);
|
|
||||||
|
|
||||||
if (ShortNumberInfo.getInstance().isPossibleShortNumberForRegion(parsedNumber, localCountryCode)) {
|
|
||||||
return bareNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
return phoneNumberUtil.format(parsedNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
if (bareNumber.charAt(0) == '+')
|
|
||||||
return bareNumber;
|
|
||||||
|
|
||||||
String localNumberImprecise = localNumberString;
|
|
||||||
|
|
||||||
if (localNumberImprecise.charAt(0) == '+')
|
|
||||||
localNumberImprecise = localNumberImprecise.substring(1);
|
|
||||||
|
|
||||||
if (localNumberImprecise.length() == bareNumber.length() || bareNumber.length() > localNumberImprecise.length())
|
|
||||||
return "+" + number;
|
|
||||||
|
|
||||||
int difference = localNumberImprecise.length() - bareNumber.length();
|
|
||||||
|
|
||||||
return "+" + localNumberImprecise.substring(0, difference) + bareNumber;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,12 @@
|
|||||||
package org.thoughtcrime.securesms.database.loaders;
|
package org.thoughtcrime.securesms.database.loaders;
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.v4.content.AsyncTaskLoader;
|
import android.support.v4.content.AsyncTaskLoader;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
import java.util.Comparator;
|
||||||
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
|
import java.util.Map;
|
||||||
|
|
||||||
public class CountryListLoader extends AsyncTaskLoader<ArrayList<Map<String, String>>> {
|
public class CountryListLoader extends AsyncTaskLoader<ArrayList<Map<String, String>>> {
|
||||||
|
|
||||||
@ -23,19 +16,7 @@ public class CountryListLoader extends AsyncTaskLoader<ArrayList<Map<String, Str
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayList<Map<String, String>> loadInBackground() {
|
public ArrayList<Map<String, String>> loadInBackground() {
|
||||||
Set<String> regions = PhoneNumberUtil.getInstance().getSupportedRegions();
|
return new ArrayList<>();
|
||||||
ArrayList<Map<String, String>> results = new ArrayList<Map<String, String>>(regions.size());
|
|
||||||
|
|
||||||
for (String region : regions) {
|
|
||||||
Map<String, String> data = new HashMap<String, String>(2);
|
|
||||||
data.put("country_name", PhoneNumberFormatter.getRegionDisplayName(region));
|
|
||||||
data.put("country_code", "+" +PhoneNumberUtil.getInstance().getCountryCodeForRegion(region));
|
|
||||||
results.add(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Collections.sort(results, new RegionComparator());
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class RegionComparator implements Comparator<Map<String, String>> {
|
private static class RegionComparator implements Comparator<Map<String, String>> {
|
||||||
|
@ -9,13 +9,11 @@ import org.thoughtcrime.securesms.DeviceListFragment;
|
|||||||
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
|
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
|
||||||
import org.thoughtcrime.securesms.gcm.FcmService;
|
|
||||||
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
|
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
|
||||||
import org.thoughtcrime.securesms.jobs.AttachmentUploadJob;
|
import org.thoughtcrime.securesms.jobs.AttachmentUploadJob;
|
||||||
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
||||||
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob;
|
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob;
|
||||||
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
||||||
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
|
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
||||||
@ -48,6 +46,7 @@ import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
|||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.LokiSessionResetImplementation;
|
import org.thoughtcrime.securesms.loki.LokiSessionResetImplementation;
|
||||||
|
import org.thoughtcrime.securesms.loki.MultiDeviceOpenGroupUpdateJob;
|
||||||
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
||||||
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
||||||
import org.thoughtcrime.securesms.push.MessageSenderEventListener;
|
import org.thoughtcrime.securesms.push.MessageSenderEventListener;
|
||||||
@ -86,7 +85,6 @@ import network.loki.messenger.BuildConfig;
|
|||||||
MultiDeviceBlockedUpdateJob.class,
|
MultiDeviceBlockedUpdateJob.class,
|
||||||
DeviceListFragment.class,
|
DeviceListFragment.class,
|
||||||
RefreshAttributesJob.class,
|
RefreshAttributesJob.class,
|
||||||
FcmRefreshJob.class,
|
|
||||||
RequestGroupInfoJob.class,
|
RequestGroupInfoJob.class,
|
||||||
PushGroupUpdateJob.class,
|
PushGroupUpdateJob.class,
|
||||||
AvatarDownloadJob.class,
|
AvatarDownloadJob.class,
|
||||||
@ -99,7 +97,6 @@ import network.loki.messenger.BuildConfig;
|
|||||||
MultiDeviceProfileKeyUpdateJob.class,
|
MultiDeviceProfileKeyUpdateJob.class,
|
||||||
SendReadReceiptJob.class,
|
SendReadReceiptJob.class,
|
||||||
AppProtectionPreferenceFragment.class,
|
AppProtectionPreferenceFragment.class,
|
||||||
FcmService.class,
|
|
||||||
RotateCertificateJob.class,
|
RotateCertificateJob.class,
|
||||||
SendDeliveryReceiptJob.class,
|
SendDeliveryReceiptJob.class,
|
||||||
RotateProfileKeyJob.class,
|
RotateProfileKeyJob.class,
|
||||||
@ -115,7 +112,8 @@ import network.loki.messenger.BuildConfig;
|
|||||||
MultiDeviceStickerPackOperationJob.class,
|
MultiDeviceStickerPackOperationJob.class,
|
||||||
MultiDeviceStickerPackSyncJob.class,
|
MultiDeviceStickerPackSyncJob.class,
|
||||||
LinkPreviewRepository.class,
|
LinkPreviewRepository.class,
|
||||||
PushMessageSyncSendJob.class})
|
PushMessageSyncSendJob.class,
|
||||||
|
MultiDeviceOpenGroupUpdateJob.class})
|
||||||
|
|
||||||
public class SignalCommunicationModule {
|
public class SignalCommunicationModule {
|
||||||
|
|
||||||
|
@ -1,158 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.gcm;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.PowerManager;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
|
||||||
import com.google.firebase.messaging.RemoteMessage;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
|
||||||
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
|
|
||||||
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
|
||||||
import org.thoughtcrime.securesms.service.GenericForegroundService;
|
|
||||||
import org.thoughtcrime.securesms.util.PowerManagerCompat;
|
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.thoughtcrime.securesms.util.WakeLockUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
|
||||||
import org.whispersystems.signalservice.internal.util.Util;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
public class FcmService extends FirebaseMessagingService implements InjectableType {
|
|
||||||
|
|
||||||
private static final String TAG = FcmService.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final Executor MESSAGE_EXECUTOR = SignalExecutors.newCachedSingleThreadExecutor("FcmMessageProcessing");
|
|
||||||
private static final String WAKE_LOCK_TAG = "FcmMessageProcessing";
|
|
||||||
|
|
||||||
@Inject SignalServiceMessageReceiver messageReceiver;
|
|
||||||
|
|
||||||
private static int activeCount;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMessageReceived(RemoteMessage remoteMessage) {
|
|
||||||
Log.i(TAG, "FCM message... Original Priority: " + remoteMessage.getOriginalPriority() + ", Actual Priority: " + remoteMessage.getPriority());
|
|
||||||
ApplicationContext.getInstance(getApplicationContext()).injectDependencies(this);
|
|
||||||
|
|
||||||
WakeLockUtil.runWithLock(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK, 60000, WAKE_LOCK_TAG, () -> {
|
|
||||||
handleReceivedNotification(getApplicationContext());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNewToken(String token) {
|
|
||||||
Log.i(TAG, "onNewToken()");
|
|
||||||
|
|
||||||
if (!TextSecurePreferences.isPushRegistered(getApplicationContext())) {
|
|
||||||
Log.i(TAG, "Got a new FCM token, but the user isn't registered.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplicationContext.getInstance(getApplicationContext())
|
|
||||||
.getJobManager()
|
|
||||||
.add(new FcmRefreshJob());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleReceivedNotification(Context context) {
|
|
||||||
if (!incrementActiveGcmCount()) {
|
|
||||||
Log.i(TAG, "Skipping FCM processing -- there's already one enqueued.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextSecurePreferences.setNeedsMessagePull(context, true);
|
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
|
||||||
PowerManager powerManager = ServiceUtil.getPowerManager(getApplicationContext());
|
|
||||||
boolean doze = PowerManagerCompat.isDeviceIdleMode(powerManager);
|
|
||||||
boolean network = new NetworkConstraint.Factory(ApplicationContext.getInstance(context)).create().isMet();
|
|
||||||
|
|
||||||
final Object foregroundLock = new Object();
|
|
||||||
final AtomicBoolean foregroundRunning = new AtomicBoolean(false);
|
|
||||||
final AtomicBoolean taskCompleted = new AtomicBoolean(false);
|
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
|
||||||
|
|
||||||
if (doze || !network) {
|
|
||||||
Log.i(TAG, "Starting a foreground task because we may be operating in a constrained environment. Doze: " + doze + " Network: " + network);
|
|
||||||
showForegroundNotification(context);
|
|
||||||
foregroundRunning.set(true);
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
MESSAGE_EXECUTOR.execute(() -> {
|
|
||||||
try {
|
|
||||||
new PushNotificationReceiveJob(context).pullAndProcessMessages(messageReceiver, TAG, startTime);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.i(TAG, "Failed to retrieve the envelope. Scheduling on JobManager.", e);
|
|
||||||
ApplicationContext.getInstance(context)
|
|
||||||
.getJobManager()
|
|
||||||
.add(new PushNotificationReceiveJob(context));
|
|
||||||
} finally {
|
|
||||||
synchronized (foregroundLock) {
|
|
||||||
if (foregroundRunning.getAndSet(false)) {
|
|
||||||
GenericForegroundService.stopForegroundTask(context);
|
|
||||||
} else {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
taskCompleted.set(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
decrementActiveGcmCount();
|
|
||||||
Log.i(TAG, "Processing complete.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!foregroundRunning.get()) {
|
|
||||||
new Thread("FcmForegroundServiceTimer") {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Util.sleep(7000);
|
|
||||||
synchronized (foregroundLock) {
|
|
||||||
if (!taskCompleted.get() && !foregroundRunning.getAndSet(true)) {
|
|
||||||
Log.i(TAG, "Starting a foreground task because the job is running long.");
|
|
||||||
showForegroundNotification(context);
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
latch.await();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.w(TAG, "Latch was interrupted.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showForegroundNotification(@NonNull Context context) {
|
|
||||||
GenericForegroundService.startForegroundTask(context,
|
|
||||||
context.getString(R.string.GcmBroadcastReceiver_retrieving_a_message),
|
|
||||||
NotificationChannels.OTHER,
|
|
||||||
R.drawable.ic_signal_downloading);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static synchronized boolean incrementActiveGcmCount() {
|
|
||||||
if (activeCount < 2) {
|
|
||||||
activeCount++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static synchronized void decrementActiveGcmCount() {
|
|
||||||
activeCount--;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.gcm;
|
|
||||||
|
|
||||||
import android.support.annotation.WorkerThread;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import com.google.firebase.iid.FirebaseInstanceId;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
public final class FcmUtil {
|
|
||||||
|
|
||||||
private static final String TAG = FcmUtil.class.getSimpleName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the current FCM token. If one isn't available, it'll be generated.
|
|
||||||
*/
|
|
||||||
@WorkerThread
|
|
||||||
public static Optional<String> getToken() {
|
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
|
||||||
AtomicReference<String> token = new AtomicReference<>(null);
|
|
||||||
|
|
||||||
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(task -> {
|
|
||||||
if (task.isSuccessful() && task.getResult() != null && !TextUtils.isEmpty(task.getResult().getToken())) {
|
|
||||||
token.set(task.getResult().getToken());
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Failed to get the token.", task.getException());
|
|
||||||
}
|
|
||||||
|
|
||||||
latch.countDown();
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
latch.await();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.w(TAG, "Was interrupted while waiting for the token.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.fromNullable(token.get());
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,7 +9,6 @@ import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
|||||||
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob;
|
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob;
|
||||||
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
||||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||||
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
|
|
||||||
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
|
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
|
||||||
import org.thoughtcrime.securesms.jobs.MmsDownloadJob;
|
import org.thoughtcrime.securesms.jobs.MmsDownloadJob;
|
||||||
import org.thoughtcrime.securesms.jobs.MmsReceiveJob;
|
import org.thoughtcrime.securesms.jobs.MmsReceiveJob;
|
||||||
@ -59,7 +58,6 @@ public class WorkManagerFactoryMappings {
|
|||||||
put(CleanPreKeysJob.class.getName(), CleanPreKeysJob.KEY);
|
put(CleanPreKeysJob.class.getName(), CleanPreKeysJob.KEY);
|
||||||
put(CreateSignedPreKeyJob.class.getName(), CreateSignedPreKeyJob.KEY);
|
put(CreateSignedPreKeyJob.class.getName(), CreateSignedPreKeyJob.KEY);
|
||||||
put(DirectoryRefreshJob.class.getName(), DirectoryRefreshJob.KEY);
|
put(DirectoryRefreshJob.class.getName(), DirectoryRefreshJob.KEY);
|
||||||
put(FcmRefreshJob.class.getName(), FcmRefreshJob.KEY);
|
|
||||||
put(LocalBackupJob.class.getName(), LocalBackupJob.KEY);
|
put(LocalBackupJob.class.getName(), LocalBackupJob.KEY);
|
||||||
put(MmsDownloadJob.class.getName(), MmsDownloadJob.KEY);
|
put(MmsDownloadJob.class.getName(), MmsDownloadJob.KEY);
|
||||||
put(MmsReceiveJob.class.getName(), MmsReceiveJob.KEY);
|
put(MmsReceiveJob.class.getName(), MmsReceiveJob.KEY);
|
||||||
|
@ -1,151 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms.jobs;
|
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.v4.app.NotificationCompat;
|
|
||||||
|
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
|
||||||
import com.google.android.gms.common.GoogleApiAvailability;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.gcm.FcmUtil;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.PlayServicesProblemActivity;
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
|
||||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
|
||||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
public class FcmRefreshJob extends BaseJob implements InjectableType {
|
|
||||||
|
|
||||||
public static final String KEY = "FcmRefreshJob";
|
|
||||||
|
|
||||||
private static final String TAG = FcmRefreshJob.class.getSimpleName();
|
|
||||||
|
|
||||||
@Inject SignalServiceAccountManager textSecureAccountManager;
|
|
||||||
|
|
||||||
public FcmRefreshJob() {
|
|
||||||
this(new Job.Parameters.Builder()
|
|
||||||
.setQueue("FcmRefreshJob")
|
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
|
||||||
.setMaxAttempts(1)
|
|
||||||
.setLifespan(TimeUnit.MINUTES.toMillis(5))
|
|
||||||
.setMaxInstances(1)
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
private FcmRefreshJob(@NonNull Job.Parameters parameters) {
|
|
||||||
super(parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NonNull Data serialize() {
|
|
||||||
return Data.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NonNull String getFactoryKey() {
|
|
||||||
return KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRun() throws Exception {
|
|
||||||
if (TextSecurePreferences.isFcmDisabled(context)) return;
|
|
||||||
|
|
||||||
Log.i(TAG, "Reregistering FCM...");
|
|
||||||
|
|
||||||
int result = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
|
|
||||||
|
|
||||||
if (result != ConnectionResult.SUCCESS) {
|
|
||||||
notifyFcmFailure();
|
|
||||||
} else {
|
|
||||||
Optional<String> token = FcmUtil.getToken();
|
|
||||||
|
|
||||||
if (token.isPresent()) {
|
|
||||||
String oldToken = TextSecurePreferences.getFcmToken(context);
|
|
||||||
|
|
||||||
if (!token.get().equals(oldToken)) {
|
|
||||||
int oldLength = oldToken != null ? oldToken.length() : -1;
|
|
||||||
Log.i(TAG, "Token changed. oldLength: " + oldLength + " newLength: " + token.get().length());
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "Token didn't change.");
|
|
||||||
}
|
|
||||||
|
|
||||||
textSecureAccountManager.setGcmId(token);
|
|
||||||
TextSecurePreferences.setFcmToken(context, token.get());
|
|
||||||
TextSecurePreferences.setFcmTokenLastSetTime(context, System.currentTimeMillis());
|
|
||||||
TextSecurePreferences.setWebsocketRegistered(context, true);
|
|
||||||
} else {
|
|
||||||
throw new RetryLaterException(new IOException("Failed to retrieve a token."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCanceled() {
|
|
||||||
Log.w(TAG, "GCM reregistration failed after retry attempt exhaustion!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onShouldRetry(@NonNull Exception throwable) {
|
|
||||||
if (throwable instanceof NonSuccessfulResponseCodeException) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyFcmFailure() {
|
|
||||||
Intent intent = new Intent(context, PlayServicesProblemActivity.class);
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1122, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NotificationChannels.FAILURES);
|
|
||||||
|
|
||||||
builder.setSmallIcon(R.drawable.ic_notification);
|
|
||||||
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(),
|
|
||||||
R.drawable.ic_action_warning_red));
|
|
||||||
builder.setContentTitle(context.getString(R.string.GcmRefreshJob_Permanent_Signal_communication_failure));
|
|
||||||
builder.setContentText(context.getString(R.string.GcmRefreshJob_Signal_was_unable_to_register_with_Google_Play_Services));
|
|
||||||
builder.setTicker(context.getString(R.string.GcmRefreshJob_Permanent_Signal_communication_failure));
|
|
||||||
builder.setVibrate(new long[] {0, 1000});
|
|
||||||
builder.setContentIntent(pendingIntent);
|
|
||||||
|
|
||||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
|
||||||
.notify(12, builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Factory implements Job.Factory<FcmRefreshJob> {
|
|
||||||
@Override
|
|
||||||
public @NonNull FcmRefreshJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
|
||||||
return new FcmRefreshJob(parameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraintObserver;
|
|||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver;
|
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver;
|
||||||
|
import org.thoughtcrime.securesms.loki.MultiDeviceOpenGroupUpdateJob;
|
||||||
import org.thoughtcrime.securesms.loki.PushBackgroundMessageSendJob;
|
import org.thoughtcrime.securesms.loki.PushBackgroundMessageSendJob;
|
||||||
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
||||||
|
|
||||||
@ -31,7 +32,6 @@ public final class JobManagerFactories {
|
|||||||
put(CleanPreKeysJob.KEY, new CleanPreKeysJob.Factory());
|
put(CleanPreKeysJob.KEY, new CleanPreKeysJob.Factory());
|
||||||
put(CreateSignedPreKeyJob.KEY, new CreateSignedPreKeyJob.Factory());
|
put(CreateSignedPreKeyJob.KEY, new CreateSignedPreKeyJob.Factory());
|
||||||
put(DirectoryRefreshJob.KEY, new DirectoryRefreshJob.Factory(application));
|
put(DirectoryRefreshJob.KEY, new DirectoryRefreshJob.Factory(application));
|
||||||
put(FcmRefreshJob.KEY, new FcmRefreshJob.Factory());
|
|
||||||
put(LocalBackupJob.KEY, new LocalBackupJob.Factory());
|
put(LocalBackupJob.KEY, new LocalBackupJob.Factory());
|
||||||
put(MmsDownloadJob.KEY, new MmsDownloadJob.Factory());
|
put(MmsDownloadJob.KEY, new MmsDownloadJob.Factory());
|
||||||
put(MmsReceiveJob.KEY, new MmsReceiveJob.Factory());
|
put(MmsReceiveJob.KEY, new MmsReceiveJob.Factory());
|
||||||
@ -74,6 +74,7 @@ public final class JobManagerFactories {
|
|||||||
put(UpdateApkJob.KEY, new UpdateApkJob.Factory());
|
put(UpdateApkJob.KEY, new UpdateApkJob.Factory());
|
||||||
put(PushMessageSyncSendJob.KEY, new PushMessageSyncSendJob.Factory());
|
put(PushMessageSyncSendJob.KEY, new PushMessageSyncSendJob.Factory());
|
||||||
put(PushBackgroundMessageSendJob.KEY, new PushBackgroundMessageSendJob.Factory());
|
put(PushBackgroundMessageSendJob.KEY, new PushBackgroundMessageSendJob.Factory());
|
||||||
|
put(MultiDeviceOpenGroupUpdateJob.KEY, new MultiDeviceOpenGroupUpdateJob.Factory());
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<ContactData> getAllContacts() {
|
private List<ContactData> getAllContacts() {
|
||||||
List<Address> contactAddresses = DatabaseFactory.getRecipientDatabase(context).getRegistered();
|
List<Address> contactAddresses = new ArrayList<>(DatabaseFactory.getRecipientDatabase(context).getAllAddresses());
|
||||||
List<ContactData> contacts = new ArrayList<>(contactAddresses.size());
|
List<ContactData> contacts = new ArrayList<>(contactAddresses.size());
|
||||||
for (Address address : contactAddresses) {
|
for (Address address : contactAddresses) {
|
||||||
if (!address.isPhone()) { continue; }
|
if (!address.isPhone()) { continue; }
|
||||||
|
@ -59,6 +59,7 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
|||||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
import org.thoughtcrime.securesms.groups.GroupMessageProcessor;
|
import org.thoughtcrime.securesms.groups.GroupMessageProcessor;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
@ -72,6 +73,7 @@ import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
|
|||||||
import org.thoughtcrime.securesms.loki.LokiSessionResetImplementation;
|
import org.thoughtcrime.securesms.loki.LokiSessionResetImplementation;
|
||||||
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
|
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
|
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
|
||||||
|
import org.thoughtcrime.securesms.loki.redesign.utilities.OpenGroupUtilities;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities;
|
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities;
|
||||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyBundleDatabase;
|
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyBundleDatabase;
|
||||||
@ -138,6 +140,8 @@ import org.whispersystems.signalservice.loki.api.DeviceLink;
|
|||||||
import org.whispersystems.signalservice.loki.api.DeviceLinkingSession;
|
import org.whispersystems.signalservice.loki.api.DeviceLinkingSession;
|
||||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
||||||
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities;
|
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities;
|
||||||
|
import org.whispersystems.signalservice.loki.api.LokiPublicChat;
|
||||||
|
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI;
|
||||||
import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher;
|
import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher;
|
||||||
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus;
|
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus;
|
||||||
import org.whispersystems.signalservice.loki.messaging.LokiServiceMessage;
|
import org.whispersystems.signalservice.loki.messaging.LokiServiceMessage;
|
||||||
@ -393,6 +397,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
else if (syncMessage.getStickerPackOperations().isPresent()) handleSynchronizeStickerPackOperation(syncMessage.getStickerPackOperations().get());
|
else if (syncMessage.getStickerPackOperations().isPresent()) handleSynchronizeStickerPackOperation(syncMessage.getStickerPackOperations().get());
|
||||||
else if (syncMessage.getContacts().isPresent()) handleContactSyncMessage(syncMessage.getContacts().get());
|
else if (syncMessage.getContacts().isPresent()) handleContactSyncMessage(syncMessage.getContacts().get());
|
||||||
else if (syncMessage.getGroups().isPresent()) handleGroupSyncMessage(content, syncMessage.getGroups().get());
|
else if (syncMessage.getGroups().isPresent()) handleGroupSyncMessage(content, syncMessage.getGroups().get());
|
||||||
|
else if (syncMessage.getOpenGroups().isPresent()) handleOpenGroupSyncMessage(syncMessage.getOpenGroups().get());
|
||||||
else Log.w(TAG, "Contains no known sync types...");
|
else Log.w(TAG, "Contains no known sync types...");
|
||||||
} else if (content.getCallMessage().isPresent()) {
|
} else if (content.getCallMessage().isPresent()) {
|
||||||
Log.i(TAG, "Got call message...");
|
Log.i(TAG, "Got call message...");
|
||||||
@ -704,6 +709,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||||
LokiThreadFriendRequestStatus status = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
|
LokiThreadFriendRequestStatus status = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
|
||||||
if (status == LokiThreadFriendRequestStatus.NONE || status == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) {
|
if (status == LokiThreadFriendRequestStatus.NONE || status == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) {
|
||||||
|
// TODO: We should ensure that our mapping has been uploaded to the server before sending out this message
|
||||||
MessageSender.sendBackgroundFriendRequest(context, hexEncodedPublicKey, "Please accept to enable messages to be synced across devices");
|
MessageSender.sendBackgroundFriendRequest(context, hexEncodedPublicKey, "Please accept to enable messages to be synced across devices");
|
||||||
Log.d("Loki", "Sent friend request to " + hexEncodedPublicKey);
|
Log.d("Loki", "Sent friend request to " + hexEncodedPublicKey);
|
||||||
} else if (status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
|
} else if (status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
|
||||||
@ -749,6 +755,24 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleOpenGroupSyncMessage(@NonNull List<LokiPublicChat> openGroups) {
|
||||||
|
try {
|
||||||
|
for (LokiPublicChat openGroup : openGroups) {
|
||||||
|
long threadID = GroupManager.getPublicChatThreadId(openGroup.getId(), context);
|
||||||
|
if (threadID > -1) continue;
|
||||||
|
|
||||||
|
String url = openGroup.getServer();
|
||||||
|
long channel = openGroup.getChannel();
|
||||||
|
OpenGroupUtilities.addGroup(context, url, channel).fail(e -> {
|
||||||
|
Log.d("Loki", "Failed to sync open group: " + url + " due to error: " + e + ".");
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.d("Loki", "Failed to sync open groups due to error: " + e + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleSynchronizeSentMessage(@NonNull SignalServiceContent content,
|
private void handleSynchronizeSentMessage(@NonNull SignalServiceContent content,
|
||||||
@NonNull SentTranscriptMessage message)
|
@NonNull SentTranscriptMessage message)
|
||||||
throws StorageFailedException
|
throws StorageFailedException
|
||||||
@ -1206,6 +1230,17 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
TextSecurePreferences.setMultiDevice(context, true);
|
TextSecurePreferences.setMultiDevice(context, true);
|
||||||
// Send a background message to the master device
|
// Send a background message to the master device
|
||||||
MessageSender.sendBackgroundMessage(context, deviceLink.getMasterHexEncodedPublicKey());
|
MessageSender.sendBackgroundMessage(context, deviceLink.getMasterHexEncodedPublicKey());
|
||||||
|
/*
|
||||||
|
Update device link on the file server.
|
||||||
|
We put this here because after receiving the authorisation message, we will also receive all sync messages.
|
||||||
|
If these sync messages are contact syncs then we need to send them friend requests so that we can establish multi-device communication.
|
||||||
|
If our device mapping is not stored on the server before the other party receives our message, they will think that they got a friend request from a non-multi-device user.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
PromiseUtil.timeout(LokiFileServerAPI.shared.addDeviceLink(deviceLink), 8000).get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w("Loki", "Failed to upload device links to the file server! " + e);
|
||||||
|
}
|
||||||
// Update display name if needed
|
// Update display name if needed
|
||||||
if (content.senderDisplayName.isPresent() && content.senderDisplayName.get().length() > 0) {
|
if (content.senderDisplayName.isPresent() && content.senderDisplayName.get().length() > 0) {
|
||||||
TextSecurePreferences.setProfileName(context, content.senderDisplayName.get());
|
TextSecurePreferences.setProfileName(context, content.senderDisplayName.get());
|
||||||
@ -1218,7 +1253,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
if (content.getSyncMessage().isPresent() && content.getSyncMessage().get().getContacts().isPresent()) {
|
if (content.getSyncMessage().isPresent() && content.getSyncMessage().get().getContacts().isPresent()) {
|
||||||
handleContactSyncMessage(content.getSyncMessage().get().getContacts().get());
|
handleContactSyncMessage(content.getSyncMessage().get().getContacts().get());
|
||||||
}
|
}
|
||||||
// The device link is propagated to the file server in LandingActivity.onDeviceLinkAuthorized because we can handle the error there
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDisplayName(String hexEncodedPublicKey, String profileName) {
|
private void setDisplayName(String hexEncodedPublicKey, String profileName) {
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
package org.thoughtcrime.securesms.loki
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil
|
||||||
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
|
import org.thoughtcrime.securesms.dependencies.InjectableType
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupManager
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.Data
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.Job
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
|
||||||
|
import org.thoughtcrime.securesms.jobs.BaseJob
|
||||||
|
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 java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MultiDeviceOpenGroupUpdateJob private constructor(parameters: Parameters) : BaseJob(parameters), InjectableType {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val KEY = "MultiDeviceOpenGroupUpdateJob"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var messageSender: SignalServiceMessageSender
|
||||||
|
|
||||||
|
constructor() : this(Parameters.Builder()
|
||||||
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
|
.setQueue("MultiDeviceOpenGroupUpdateJob")
|
||||||
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
|
.setMaxAttempts(Parameters.UNLIMITED)
|
||||||
|
.build())
|
||||||
|
|
||||||
|
override fun getFactoryKey(): String { return KEY }
|
||||||
|
|
||||||
|
override fun serialize(): Data { return Data.EMPTY }
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
public override fun onRun() {
|
||||||
|
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||||
|
Log.d("Loki", "Not multi device; aborting...")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val openGroups = mutableListOf<LokiPublicChat>()
|
||||||
|
DatabaseFactory.getGroupDatabase(context).groups.use { reader ->
|
||||||
|
while (true) {
|
||||||
|
val record = reader.next ?: return@use
|
||||||
|
if (!record.isPublicChat) { continue; }
|
||||||
|
|
||||||
|
val threadID = GroupManager.getThreadIdFromGroupId(record.encodedId, context)
|
||||||
|
val openGroup = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
|
||||||
|
if (openGroup != null) {
|
||||||
|
openGroups.add(openGroup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openGroups.size > 0) {
|
||||||
|
messageSender.sendMessage(0, SignalServiceSyncMessage.forOpenGroups(openGroups),
|
||||||
|
UnidentifiedAccessUtil.getAccessForSync(context))
|
||||||
|
} else {
|
||||||
|
Log.d("Loki", "No open groups to sync.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onShouldRetry(exception: Exception): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCanceled() { }
|
||||||
|
|
||||||
|
class Factory : Job.Factory<MultiDeviceOpenGroupUpdateJob> {
|
||||||
|
|
||||||
|
override fun create(parameters: Parameters, data: Data): MultiDeviceOpenGroupUpdateJob {
|
||||||
|
return MultiDeviceOpenGroupUpdateJob(parameters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,12 @@ fun checkIsRevokedSlaveDevice(context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateDeviceLinksOnServer(context: Context) {
|
||||||
|
val hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||||
|
val deviceLinks = DatabaseFactory.getLokiAPIDatabase(context).getDeviceLinks(hexEncodedPublicKey)
|
||||||
|
LokiFileServerAPI.shared.setDeviceLinks(deviceLinks)
|
||||||
|
}
|
||||||
|
|
||||||
fun getAllDeviceFriendRequestStatuses(context: Context, hexEncodedPublicKey: String): Promise<Map<String, LokiThreadFriendRequestStatus>, Exception> {
|
fun getAllDeviceFriendRequestStatuses(context: Context, hexEncodedPublicKey: String): Promise<Map<String, LokiThreadFriendRequestStatus>, Exception> {
|
||||||
val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context)
|
val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context)
|
||||||
return LokiDeviceLinkUtilities.getAllLinkedDeviceHexEncodedPublicKeys(hexEncodedPublicKey).map { keys ->
|
return LokiDeviceLinkUtilities.getAllLinkedDeviceHexEncodedPublicKeys(hexEncodedPublicKey).map { keys ->
|
||||||
|
@ -194,7 +194,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
|||||||
|
|
||||||
private fun openConversation(thread: ThreadRecord) {
|
private fun openConversation(thread: ThreadRecord) {
|
||||||
val intent = Intent(this, ConversationActivity::class.java)
|
val intent = Intent(this, ConversationActivity::class.java)
|
||||||
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, thread.recipient.getAddress())
|
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, thread.recipient.address)
|
||||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, thread.threadId)
|
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, thread.threadId)
|
||||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, thread.distributionType)
|
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, thread.distributionType)
|
||||||
intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis())
|
intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis())
|
||||||
@ -255,9 +255,9 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
|||||||
val dialog = AlertDialog.Builder(activity)
|
val dialog = AlertDialog.Builder(activity)
|
||||||
dialog.setMessage(dialogMessage)
|
dialog.setMessage(dialogMessage)
|
||||||
dialog.setPositiveButton(R.string.yes) { _, _ ->
|
dialog.setPositiveButton(R.string.yes) { _, _ ->
|
||||||
val isGroup = recipient.isGroupRecipient
|
val isClosedGroup = recipient.address.isSignalGroup
|
||||||
// Send a leave group message if this is an active closed group
|
// Send a leave group message if this is an active closed group
|
||||||
if (isGroup && DatabaseFactory.getGroupDatabase(activity).isActive(recipient.address.toGroupString())) {
|
if (isClosedGroup && DatabaseFactory.getGroupDatabase(activity).isActive(recipient.address.toGroupString())) {
|
||||||
if (!GroupUtil.leaveGroup(activity, recipient)) {
|
if (!GroupUtil.leaveGroup(activity, recipient)) {
|
||||||
Toast.makeText(activity, "Couldn't leave group", Toast.LENGTH_LONG).show()
|
Toast.makeText(activity, "Couldn't leave group", Toast.LENGTH_LONG).show()
|
||||||
clearView(activity.recyclerView, viewHolder)
|
clearView(activity.recyclerView, viewHolder)
|
||||||
@ -267,10 +267,11 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
|||||||
// Archive the conversation and then delete it after 10 seconds (the case where the
|
// Archive the conversation and then delete it after 10 seconds (the case where the
|
||||||
// app was closed before the conversation could be deleted is handled in onCreate)
|
// app was closed before the conversation could be deleted is handled in onCreate)
|
||||||
threadDatabase.archiveConversation(threadID)
|
threadDatabase.archiveConversation(threadID)
|
||||||
|
val delay = if (isClosedGroup) 10000L else 1000L
|
||||||
val handler = Handler()
|
val handler = Handler()
|
||||||
handler.postDelayed(deleteThread, 10000)
|
handler.postDelayed(deleteThread, delay)
|
||||||
// Notify the user
|
// Notify the user
|
||||||
val toastMessage = if (isGroup) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message
|
val toastMessage = if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message
|
||||||
Toast.makeText(activity, toastMessage, Toast.LENGTH_LONG).show()
|
Toast.makeText(activity, toastMessage, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
dialog.setNegativeButton(R.string.no) { _, _ ->
|
dialog.setNegativeButton(R.string.no) { _, _ ->
|
||||||
|
@ -16,14 +16,12 @@ import kotlinx.android.synthetic.main.fragment_enter_chat_url.*
|
|||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import nl.komponents.kovenant.ui.failUi
|
import nl.komponents.kovenant.ui.failUi
|
||||||
import nl.komponents.kovenant.ui.successUi
|
import nl.komponents.kovenant.ui.successUi
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
|
||||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
|
import org.thoughtcrime.securesms.loki.redesign.utilities.OpenGroupUtilities
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
|
||||||
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragment
|
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragment
|
||||||
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragmentDelegate
|
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragmentDelegate
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
import org.thoughtcrime.securesms.sms.MessageSender
|
||||||
|
|
||||||
class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
||||||
private val adapter = JoinPublicChatActivityAdapter(this)
|
private val adapter = JoinPublicChatActivityAdapter(this)
|
||||||
@ -68,19 +66,11 @@ class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCode
|
|||||||
return Toast.makeText(this, "Invalid URL", Toast.LENGTH_SHORT).show()
|
return Toast.makeText(this, "Invalid URL", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
showLoader()
|
showLoader()
|
||||||
val application = ApplicationContext.getInstance(this)
|
|
||||||
val channel: Long = 1
|
val channel: Long = 1
|
||||||
val displayName = TextSecurePreferences.getProfileName(this)
|
OpenGroupUtilities.addGroup(this, url, channel).success {
|
||||||
val lokiPublicChatAPI = application.lokiPublicChatAPI!!
|
MessageSender.syncAllOpenGroups(this)
|
||||||
application.lokiPublicChatManager.addChat(url, channel).successUi {
|
}.successUi {
|
||||||
DatabaseFactory.getLokiAPIDatabase(this).removeLastMessageServerID(channel, url)
|
|
||||||
DatabaseFactory.getLokiAPIDatabase(this).removeLastDeletionServerID(channel, url)
|
|
||||||
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)
|
|
||||||
finish()
|
finish()
|
||||||
}.failUi {
|
}.failUi {
|
||||||
hideLoader()
|
hideLoader()
|
||||||
|
@ -114,7 +114,6 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) {
|
override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) {
|
||||||
LokiFileServerAPI.shared.addDeviceLink(deviceLink)
|
|
||||||
TextSecurePreferences.setMasterHexEncodedPublicKey(this, deviceLink.masterHexEncodedPublicKey)
|
TextSecurePreferences.setMasterHexEncodedPublicKey(this, deviceLink.masterHexEncodedPublicKey)
|
||||||
val intent = Intent(this, HomeActivity::class.java)
|
val intent = Intent(this, HomeActivity::class.java)
|
||||||
show(intent)
|
show(intent)
|
||||||
|
@ -12,6 +12,7 @@ import android.view.View
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import kotlinx.android.synthetic.main.activity_linked_devices.*
|
import kotlinx.android.synthetic.main.activity_linked_devices.*
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
|
import nl.komponents.kovenant.functional.bind
|
||||||
import nl.komponents.kovenant.ui.failUi
|
import nl.komponents.kovenant.ui.failUi
|
||||||
import nl.komponents.kovenant.ui.successUi
|
import nl.komponents.kovenant.ui.successUi
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
@ -23,6 +24,7 @@ import org.thoughtcrime.securesms.loki.signAndSendDeviceLinkMessage
|
|||||||
import org.thoughtcrime.securesms.sms.MessageSender
|
import org.thoughtcrime.securesms.sms.MessageSender
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||||
import org.whispersystems.signalservice.loki.api.DeviceLink
|
import org.whispersystems.signalservice.loki.api.DeviceLink
|
||||||
|
import org.whispersystems.signalservice.loki.api.LokiAPI
|
||||||
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI
|
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.concurrent.schedule
|
import kotlin.concurrent.schedule
|
||||||
@ -143,23 +145,21 @@ class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LoaderManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) {
|
override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) {
|
||||||
LokiFileServerAPI.shared.addDeviceLink(deviceLink).success {
|
LokiFileServerAPI.shared.addDeviceLink(deviceLink).bind(LokiAPI.sharedWorkContext) {
|
||||||
signAndSendDeviceLinkMessage(this, deviceLink).successUi {
|
signAndSendDeviceLinkMessage(this, deviceLink)
|
||||||
|
}.successUi {
|
||||||
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
||||||
}.success {
|
}.success {
|
||||||
TextSecurePreferences.setMultiDevice(this, true)
|
TextSecurePreferences.setMultiDevice(this, true)
|
||||||
Timer().schedule(4000) {
|
Timer().schedule(4000) {
|
||||||
MessageSender.syncAllGroups(this@LinkedDevicesActivity)
|
MessageSender.syncAllGroups(this@LinkedDevicesActivity)
|
||||||
MessageSender.syncAllContacts(this@LinkedDevicesActivity, Address.fromSerialized(deviceLink.slaveHexEncodedPublicKey))
|
MessageSender.syncAllContacts(this@LinkedDevicesActivity, Address.fromSerialized(deviceLink.slaveHexEncodedPublicKey))
|
||||||
|
MessageSender.syncAllOpenGroups(this@LinkedDevicesActivity)
|
||||||
}
|
}
|
||||||
}.failUi {
|
|
||||||
Toast.makeText(this, "Couldn't link device", Toast.LENGTH_LONG).show()
|
|
||||||
}.fail {
|
}.fail {
|
||||||
LokiFileServerAPI.shared.removeDeviceLink(deviceLink) // If this fails we have a problem
|
LokiFileServerAPI.shared.removeDeviceLink(deviceLink) // If this fails we have a problem
|
||||||
DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slaveHexEncodedPublicKey)
|
DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slaveHexEncodedPublicKey)
|
||||||
}
|
|
||||||
}.failUi {
|
}.failUi {
|
||||||
DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slaveHexEncodedPublicKey)
|
|
||||||
Toast.makeText(this, "Couldn't link device", Toast.LENGTH_LONG).show()
|
Toast.makeText(this, "Couldn't link device", Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package org.thoughtcrime.securesms.loki.redesign.utilities
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import nl.komponents.kovenant.Promise
|
||||||
|
import nl.komponents.kovenant.then
|
||||||
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
|
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
|
||||||
|
|
||||||
|
object OpenGroupUtilities {
|
||||||
|
|
||||||
|
@JvmStatic fun addGroup(context: Context, url: String, channel: Long): Promise<LokiPublicChat, Exception> {
|
||||||
|
// Check for an existing group
|
||||||
|
val groupID = LokiPublicChat.getId(channel, url)
|
||||||
|
val threadID = GroupManager.getPublicChatThreadId(groupID, context)
|
||||||
|
val openGroup = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
|
||||||
|
if (openGroup != null) { return Promise.of(openGroup) }
|
||||||
|
// Add the new group
|
||||||
|
val application = ApplicationContext.getInstance(context)
|
||||||
|
val displayName = TextSecurePreferences.getProfileName(context)
|
||||||
|
val lokiPublicChatAPI = application.lokiPublicChatAPI ?: throw Error("LokiPublicChatAPI is not initialized.")
|
||||||
|
return application.lokiPublicChatManager.addChat(url, channel).then { group ->
|
||||||
|
DatabaseFactory.getLokiAPIDatabase(context).removeLastMessageServerID(channel, url)
|
||||||
|
DatabaseFactory.getLokiAPIDatabase(context).removeLastDeletionServerID(channel, url)
|
||||||
|
lokiPublicChatAPI.getMessages(channel, url)
|
||||||
|
lokiPublicChatAPI.setDisplayName(displayName, url)
|
||||||
|
lokiPublicChatAPI.join(channel, url)
|
||||||
|
val profileKey: ByteArray = ProfileKeyUtil.getProfileKey(context)
|
||||||
|
val profileUrl: String? = TextSecurePreferences.getProfileAvatarUrl(context)
|
||||||
|
lokiPublicChatAPI.setProfilePicture(url, profileKey, profileUrl)
|
||||||
|
group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,20 +33,12 @@ import android.provider.OpenableColumns;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.TransportOption;
|
|
||||||
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
|
|
||||||
import com.google.android.gms.common.GooglePlayServicesRepairableException;
|
|
||||||
import com.google.android.gms.location.places.ui.PlacePicker;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.MediaPreviewActivity;
|
import org.thoughtcrime.securesms.MediaPreviewActivity;
|
||||||
import network.loki.messenger.R;
|
import org.thoughtcrime.securesms.TransportOption;
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.components.AudioView;
|
import org.thoughtcrime.securesms.components.AudioView;
|
||||||
import org.thoughtcrime.securesms.components.DocumentView;
|
import org.thoughtcrime.securesms.components.DocumentView;
|
||||||
@ -55,6 +47,8 @@ import org.thoughtcrime.securesms.components.ThumbnailView;
|
|||||||
import org.thoughtcrime.securesms.components.location.SignalMapView;
|
import org.thoughtcrime.securesms.components.location.SignalMapView;
|
||||||
import org.thoughtcrime.securesms.components.location.SignalPlace;
|
import org.thoughtcrime.securesms.components.location.SignalPlace;
|
||||||
import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
|
import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||||
import org.thoughtcrime.securesms.providers.DeprecatedPersistentBlobProvider;
|
import org.thoughtcrime.securesms.providers.DeprecatedPersistentBlobProvider;
|
||||||
@ -77,6 +71,8 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
|
|
||||||
public class AttachmentManager {
|
public class AttachmentManager {
|
||||||
|
|
||||||
|
@ -14,17 +14,14 @@ import android.support.annotation.Nullable;
|
|||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.preference.CheckBoxPreference;
|
import android.support.v7.preference.CheckBoxPreference;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.google.firebase.iid.FirebaseInstanceId;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||||
import org.thoughtcrime.securesms.LogSubmitActivity;
|
import org.thoughtcrime.securesms.LogSubmitActivity;
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.RegistrationActivity;
|
import org.thoughtcrime.securesms.RegistrationActivity;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactIdentityManager;
|
import org.thoughtcrime.securesms.contacts.ContactIdentityManager;
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
@ -34,6 +31,8 @@ import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedE
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
|
public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
|
||||||
private static final String TAG = AdvancedPreferenceFragment.class.getSimpleName();
|
private static final String TAG = AdvancedPreferenceFragment.class.getSimpleName();
|
||||||
|
|
||||||
@ -187,15 +186,11 @@ public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
|
|||||||
SignalServiceAccountManager accountManager = AccountManagerFactory.createManager(context);
|
SignalServiceAccountManager accountManager = AccountManagerFactory.createManager(context);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
accountManager.setGcmId(Optional.<String>absent());
|
accountManager.setGcmId(Optional.absent());
|
||||||
} catch (AuthorizationFailedException e) {
|
} catch (AuthorizationFailedException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TextSecurePreferences.isFcmDisabled(context)) {
|
|
||||||
FirebaseInstanceId.getInstance().deleteInstanceId();
|
|
||||||
}
|
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w(TAG, ioe);
|
Log.w(TAG, ioe);
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
package org.thoughtcrime.securesms.push;
|
package org.thoughtcrime.securesms.push;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
|
|
||||||
import com.google.android.gms.security.ProviderInstaller;
|
|
||||||
|
|
||||||
import network.loki.messenger.BuildConfig;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||||
|
|
||||||
|
import network.loki.messenger.BuildConfig;
|
||||||
|
|
||||||
public class AccountManagerFactory {
|
public class AccountManagerFactory {
|
||||||
|
|
||||||
private static final String TAG = AccountManagerFactory.class.getSimpleName();
|
private static final String TAG = AccountManagerFactory.class.getSimpleName();
|
||||||
@ -22,20 +19,6 @@ public class AccountManagerFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static SignalServiceAccountManager createManager(final Context context, String number, String password) {
|
public static SignalServiceAccountManager createManager(final Context context, String number, String password) {
|
||||||
if (new SignalServiceNetworkAccess(context).isCensored(number)) {
|
|
||||||
new AsyncTask<Void, Void, Void>() {
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... params) {
|
|
||||||
try {
|
|
||||||
ProviderInstaller.installIfNeeded(context);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
Log.w(TAG, t);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new SignalServiceAccountManager(new SignalServiceNetworkAccess(context).getConfiguration(number),
|
return new SignalServiceAccountManager(new SignalServiceNetworkAccess(context).getConfiguration(number),
|
||||||
number, password, BuildConfig.USER_AGENT);
|
number, password, BuildConfig.USER_AGENT);
|
||||||
}
|
}
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.service;
|
|
||||||
|
|
||||||
import android.app.Service;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactsSyncAdapter;
|
|
||||||
|
|
||||||
public class ContactsSyncAdapterService extends Service {
|
|
||||||
|
|
||||||
private static ContactsSyncAdapter syncAdapter;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void onCreate() {
|
|
||||||
if (syncAdapter == null) {
|
|
||||||
syncAdapter = new ContactsSyncAdapter(this, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public IBinder onBind(Intent intent) {
|
|
||||||
return syncAdapter.getSyncAdapterBinder();
|
|
||||||
}
|
|
||||||
}
|
|
@ -48,6 +48,7 @@ import org.thoughtcrime.securesms.logging.Log;
|
|||||||
import org.thoughtcrime.securesms.loki.BackgroundMessage;
|
import org.thoughtcrime.securesms.loki.BackgroundMessage;
|
||||||
import org.thoughtcrime.securesms.loki.FriendRequestHandler;
|
import org.thoughtcrime.securesms.loki.FriendRequestHandler;
|
||||||
import org.thoughtcrime.securesms.loki.GeneralUtilitiesKt;
|
import org.thoughtcrime.securesms.loki.GeneralUtilitiesKt;
|
||||||
|
import org.thoughtcrime.securesms.loki.MultiDeviceOpenGroupUpdateJob;
|
||||||
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
|
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
|
||||||
import org.thoughtcrime.securesms.loki.PushBackgroundMessageSendJob;
|
import org.thoughtcrime.securesms.loki.PushBackgroundMessageSendJob;
|
||||||
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
||||||
@ -86,6 +87,10 @@ public class MessageSender {
|
|||||||
ApplicationContext.getInstance(context).getJobManager().add(new MultiDeviceGroupUpdateJob());
|
ApplicationContext.getInstance(context).getJobManager().add(new MultiDeviceGroupUpdateJob());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void syncAllOpenGroups(Context context) {
|
||||||
|
ApplicationContext.getInstance(context).getJobManager().add(new MultiDeviceOpenGroupUpdateJob());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a contact sync message to all our devices telling them that we want to sync `contact`
|
* Send a contact sync message to all our devices telling them that we want to sync `contact`
|
||||||
*/
|
*/
|
||||||
|
@ -6,7 +6,6 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.WorkerThread;
|
import android.support.annotation.WorkerThread;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
import com.google.android.gms.common.util.Hex;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
@ -15,6 +14,7 @@ import org.thoughtcrime.securesms.database.model.StickerPackRecord;
|
|||||||
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.util.Hex;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
@ -81,8 +81,8 @@ public final class StickerPackPreviewRepository implements InjectableType {
|
|||||||
@WorkerThread
|
@WorkerThread
|
||||||
private Optional<StickerManifestResult> getManifestRemote(@NonNull String packId, @NonNull String packKey) {
|
private Optional<StickerManifestResult> getManifestRemote(@NonNull String packId, @NonNull String packKey) {
|
||||||
try {
|
try {
|
||||||
byte[] packIdBytes = Hex.stringToBytes(packId);
|
byte[] packIdBytes = Hex.fromStringCondensed(packId);
|
||||||
byte[] packKeyBytes = Hex.stringToBytes(packKey);
|
byte[] packKeyBytes = Hex.fromStringCondensed(packKey);
|
||||||
SignalServiceStickerManifest remoteManifest = receiver.retrieveStickerManifest(packIdBytes, packKeyBytes);
|
SignalServiceStickerManifest remoteManifest = receiver.retrieveStickerManifest(packIdBytes, packKeyBytes);
|
||||||
StickerManifest localManifest = new StickerManifest(packId,
|
StickerManifest localManifest = new StickerManifest(packId,
|
||||||
packKey,
|
packKey,
|
||||||
|
@ -5,9 +5,9 @@ import android.support.annotation.NonNull;
|
|||||||
import com.bumptech.glide.Priority;
|
import com.bumptech.glide.Priority;
|
||||||
import com.bumptech.glide.load.DataSource;
|
import com.bumptech.glide.load.DataSource;
|
||||||
import com.bumptech.glide.load.data.DataFetcher;
|
import com.bumptech.glide.load.data.DataFetcher;
|
||||||
import com.google.android.gms.common.util.Hex;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.util.Hex;
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||||
|
|
||||||
@ -32,8 +32,8 @@ public final class StickerRemoteUriFetcher implements DataFetcher<InputStream> {
|
|||||||
@Override
|
@Override
|
||||||
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
|
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
|
||||||
try {
|
try {
|
||||||
byte[] packIdBytes = Hex.stringToBytes(stickerUri.getPackId());
|
byte[] packIdBytes = Hex.fromStringCondensed(stickerUri.getPackId());
|
||||||
byte[] packKeyBytes = Hex.stringToBytes(stickerUri.getPackKey());
|
byte[] packKeyBytes = Hex.fromStringCondensed(stickerUri.getPackKey());
|
||||||
InputStream stream = receiver.retrieveSticker(packIdBytes, packKeyBytes, stickerUri.getStickerId());
|
InputStream stream = receiver.retrieveSticker(packIdBytes, packKeyBytes, stickerUri.getStickerId());
|
||||||
|
|
||||||
callback.onDataReady(stream);
|
callback.onDataReady(stream);
|
||||||
|
@ -4,15 +4,13 @@ import android.content.Context;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.WorkerThread;
|
import android.support.annotation.WorkerThread;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase.*;
|
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
@ -26,6 +24,8 @@ import java.util.Collections;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||||
|
|
||||||
public class GroupUtil {
|
public class GroupUtil {
|
||||||
@ -87,6 +87,10 @@ public class GroupUtil {
|
|||||||
return groupId.startsWith(ENCODED_RSS_FEED_GROUP_PREFIX);
|
return groupId.startsWith(ENCODED_RSS_FEED_GROUP_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isSignalGroup(@NonNull String groupId) {
|
||||||
|
return groupId.startsWith(ENCODED_SIGNAL_GROUP_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static Optional<OutgoingGroupMediaMessage> createGroupLeaveMessage(@NonNull Context context, @NonNull Recipient groupRecipient) {
|
public static Optional<OutgoingGroupMediaMessage> createGroupLeaveMessage(@NonNull Context context, @NonNull Recipient groupRecipient) {
|
||||||
String encodedGroupId = groupRecipient.getAddress().toGroupString();
|
String encodedGroupId = groupRecipient.getAddress().toGroupString();
|
||||||
@ -114,6 +118,8 @@ public class GroupUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean leaveGroup(@NonNull Context context, Recipient groupRecipient) {
|
public static boolean leaveGroup(@NonNull Context context, Recipient groupRecipient) {
|
||||||
|
if (!groupRecipient.getAddress().isSignalGroup()) { return true; }
|
||||||
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||||
Optional<OutgoingGroupMediaMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, groupRecipient);
|
Optional<OutgoingGroupMediaMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, groupRecipient);
|
||||||
|
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.util;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
|
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
|
||||||
import com.google.android.gms.common.GoogleApiAvailability;
|
|
||||||
|
|
||||||
public class PlayServicesUtil {
|
|
||||||
|
|
||||||
private static final String TAG = PlayServicesUtil.class.getSimpleName();
|
|
||||||
|
|
||||||
public enum PlayServicesStatus {
|
|
||||||
SUCCESS,
|
|
||||||
MISSING,
|
|
||||||
NEEDS_UPDATE,
|
|
||||||
TRANSIENT_ERROR
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PlayServicesStatus getPlayServicesStatus(Context context) {
|
|
||||||
int gcmStatus = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
gcmStatus = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
Log.w(TAG, t);
|
|
||||||
return PlayServicesStatus.MISSING;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG, "Play Services: " + gcmStatus);
|
|
||||||
|
|
||||||
switch (gcmStatus) {
|
|
||||||
case ConnectionResult.SUCCESS:
|
|
||||||
return PlayServicesStatus.SUCCESS;
|
|
||||||
case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:
|
|
||||||
try {
|
|
||||||
ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo("com.google.android.gms", 0);
|
|
||||||
|
|
||||||
if (applicationInfo != null && !applicationInfo.enabled) {
|
|
||||||
return PlayServicesStatus.MISSING;
|
|
||||||
}
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return PlayServicesStatus.NEEDS_UPDATE;
|
|
||||||
case ConnectionResult.SERVICE_DISABLED:
|
|
||||||
case ConnectionResult.SERVICE_MISSING:
|
|
||||||
case ConnectionResult.SERVICE_INVALID:
|
|
||||||
case ConnectionResult.API_UNAVAILABLE:
|
|
||||||
case ConnectionResult.SERVICE_MISSING_PERMISSION:
|
|
||||||
return PlayServicesStatus.MISSING;
|
|
||||||
default:
|
|
||||||
return PlayServicesStatus.TRANSIENT_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -2,13 +2,6 @@ package org.thoughtcrime.securesms.util;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import com.google.i18n.phonenumbers.NumberParseException;
|
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
|
||||||
import com.google.i18n.phonenumbers.Phonenumber;
|
|
||||||
import com.google.i18n.phonenumbers.ShortNumberInfo;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -24,23 +17,7 @@ public class ShortCodeUtil {
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
public static boolean isShortCode(@NonNull String localNumber, @NonNull String number) {
|
public static boolean isShortCode(@NonNull String localNumber, @NonNull String number) {
|
||||||
try {
|
|
||||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
|
||||||
Phonenumber.PhoneNumber localNumberObject = util.parse(localNumber, null);
|
|
||||||
String localCountryCode = util.getRegionCodeForNumber(localNumberObject);
|
|
||||||
String bareNumber = number.replaceAll("[^0-9+]", "");
|
|
||||||
|
|
||||||
// libphonenumber seems incorrect for Russia and a few other countries with 4 digit short codes.
|
|
||||||
if (bareNumber.length() <= 4 && !SHORT_COUNTRIES.contains(localCountryCode)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Phonenumber.PhoneNumber shortCode = util.parse(number, localCountryCode);
|
|
||||||
return ShortNumberInfo.getInstance().isPossibleShortNumberForRegion(shortCode, localCountryCode);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -32,20 +32,14 @@ import android.os.Looper;
|
|||||||
import android.provider.Telephony;
|
import android.provider.Telephony;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.RequiresPermission;
|
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
|
|
||||||
import com.google.android.mms.pdu_alt.CharacterSets;
|
|
||||||
import com.google.android.mms.pdu_alt.EncodedStringValue;
|
import com.google.android.mms.pdu_alt.EncodedStringValue;
|
||||||
import com.google.i18n.phonenumbers.NumberParseException;
|
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
|
||||||
import com.google.i18n.phonenumbers.Phonenumber;
|
|
||||||
|
|
||||||
import network.loki.messenger.BuildConfig;
|
|
||||||
import org.thoughtcrime.securesms.components.ComposeText;
|
import org.thoughtcrime.securesms.components.ComposeText;
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
@ -58,7 +52,7 @@ import java.io.EOFException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -73,6 +67,8 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import network.loki.messenger.BuildConfig;
|
||||||
|
|
||||||
public class Util {
|
public class Util {
|
||||||
private static final String TAG = Util.class.getSimpleName();
|
private static final String TAG = Util.class.getSimpleName();
|
||||||
|
|
||||||
@ -170,27 +166,15 @@ public class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull String toIsoString(byte[] bytes) {
|
public static @NonNull String toIsoString(byte[] bytes) {
|
||||||
try {
|
return new String(bytes, StandardCharsets.ISO_8859_1);
|
||||||
return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new AssertionError("ISO_8859_1 must be supported!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] toIsoBytes(String isoString) {
|
public static byte[] toIsoBytes(String isoString) {
|
||||||
try {
|
return isoString.getBytes(StandardCharsets.ISO_8859_1);
|
||||||
return isoString.getBytes(CharacterSets.MIMENAME_ISO_8859_1);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new AssertionError("ISO_8859_1 must be supported!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] toUtf8Bytes(String utf8String) {
|
public static byte[] toUtf8Bytes(String utf8String) {
|
||||||
try {
|
return utf8String.getBytes(StandardCharsets.UTF_8);
|
||||||
return utf8String.getBytes(CharacterSets.MIMENAME_UTF_8);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new AssertionError("UTF_8 must be supported!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void wait(Object lock, long timeout) {
|
public static void wait(Object lock, long timeout) {
|
||||||
@ -279,27 +263,6 @@ public class Util {
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresPermission(anyOf = {
|
|
||||||
android.Manifest.permission.READ_PHONE_STATE,
|
|
||||||
android.Manifest.permission.READ_SMS,
|
|
||||||
android.Manifest.permission.READ_PHONE_NUMBERS
|
|
||||||
})
|
|
||||||
@SuppressLint("MissingPermission")
|
|
||||||
public static Optional<Phonenumber.PhoneNumber> getDeviceNumber(Context context) {
|
|
||||||
try {
|
|
||||||
final String localNumber = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number();
|
|
||||||
final Optional<String> countryIso = getSimCountryIso(context);
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(localNumber)) return Optional.absent();
|
|
||||||
if (!countryIso.isPresent()) return Optional.absent();
|
|
||||||
|
|
||||||
return Optional.fromNullable(PhoneNumberUtil.getInstance().parse(localNumber, countryIso.get()));
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
return Optional.absent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Optional<String> getSimCountryIso(Context context) {
|
public static Optional<String> getSimCountryIso(Context context) {
|
||||||
String simCountryIso = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)).getSimCountryIso();
|
String simCountryIso = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)).getSimCountryIso();
|
||||||
return Optional.fromNullable(simCountryIso != null ? simCountryIso.toUpperCase() : null);
|
return Optional.fromNullable(simCountryIso != null ? simCountryIso.toUpperCase() : null);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user