Merge branch 'dev' into open-group-syncing

This commit is contained in:
Niels Andriesse 2020-02-28 08:56:37 +07:00
commit fb9567a61b
39 changed files with 126 additions and 1310 deletions

View File

@ -38,58 +38,36 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<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.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.MODIFY_AUDIO_SETTINGS" /> <!-- <uses-permission android:name="android.permission.READ_CALL_STATE"/> -->
<!-- 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.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<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.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.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" /> <!-- For conversation 'shortcuts' on the desktop -->
<!-- For conversation 'shortcuts' on the desktop -->
<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="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- Set image as wallpaper -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- Set image as wallpaper -->
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.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.RAISED_THREAD_PRIORITY" />
<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
android:name="org.thoughtcrime.securesms.ApplicationContext"
android:allowBackup="false"
@ -101,22 +79,13 @@
android:theme="@style/Session.DarkTheme"
tools:replace="android:allowBackup">
<meta-data
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" />
-->
<!-- Disable analytics -->
<meta-data
android:name="firebase_analytics_collection_deactivated"
android:value="true" />
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="false" />
<meta-data
android:name="google_analytics_adid_collection_enabled"
android:value="false" />
@ -462,10 +431,6 @@
android:noHistory="true"
android:stateNotNeeded="true"
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">
<intent-filter>
<action android:name="android.intent.action.SENDTO" />
@ -590,20 +555,6 @@
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</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
android:name="org.thoughtcrime.securesms.service.DirectShareService"
android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
@ -612,11 +563,6 @@
</intent-filter>
</service>
<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
android:name="org.thoughtcrime.securesms.service.SmsListener"

View File

@ -11,13 +11,11 @@ buildscript {
mavenLocal()
google()
mavenCentral()
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath "com.android.tools.build:gradle:$gradle_version"
classpath files('libs/gradle-witness.jar')
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'
apply plugin: 'witness'
apply plugin: 'io.fabric'
apply plugin: 'kotlin-kapt'
repositories {
@ -62,7 +59,6 @@ repositories {
}
google()
jcenter()
maven { url 'https://maven.fabric.io/public' }
maven { url "https://jitpack.io" }
}
@ -91,16 +87,6 @@ dependencies {
implementation 'android.arch.lifecycle:extensions: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-ui:2.9.1'
@ -186,7 +172,6 @@ dependencies {
// Remote:
// implementation "com.github.loki-project:loki-messenger-android-service:dev-SNAPSHOT"
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.squareup.okhttp3:okhttp:3.12.1"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
@ -199,8 +184,8 @@ dependencies {
implementation "com.github.ybq:Android-SpinKit:1.4.0"
}
def canonicalVersionCode = 36
def canonicalVersionName = "1.0.2"
def canonicalVersionCode = 38
def canonicalVersionName = "1.0.4"
def postFixSize = 10
def abiPostFix = ['armeabi-v7a' : 1,
@ -279,8 +264,6 @@ android {
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-firebase-messaging.pro',
'proguard-google-play-services.pro',
'proguard-dagger.pro',
'proguard-jackson.pro',
'proguard-sqlite.pro',
@ -371,12 +354,12 @@ android {
def assembleWebsiteDescriptor = { variant, file ->
if (file.exists()) {
MessageDigest md = MessageDigest.getInstance("SHA-256");
MessageDigest md = MessageDigest.getInstance("SHA-256")
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 apkName = file.getName()

View File

@ -1 +0,0 @@
-dontwarn com.google.firebase.analytics.connector.AnalyticsConnector

View File

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

View File

@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
@ -39,23 +37,6 @@
</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
android:id="@+id/footer_insecure_indicator"
android:layout_width="12dp"

View File

@ -5,11 +5,13 @@
<FrameLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<!--
<com.google.android.gms.maps.MapView
android:id="@+id/map_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
-->
<ImageView android:id="@+id/image_view"
android:layout_width="match_parent"

View File

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

View File

@ -16,7 +16,6 @@
*/
package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.arch.lifecycle.DefaultLifecycleObserver;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.ProcessLifecycleOwner;
@ -31,8 +30,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.multidex.MultiDexApplication;
import com.google.android.gms.security.ProviderInstaller;
import org.conscrypt.Conscrypt;
import org.jetbrains.annotations.NotNull;
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.jobs.CreateSignedPreKeyJob;
import org.thoughtcrime.securesms.jobs.FastJobStorage;
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
import org.thoughtcrime.securesms.jobs.JobManagerFactories;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob;
@ -115,7 +111,6 @@ import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import dagger.ObjectGraph;
import kotlin.Unit;
@ -176,10 +171,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
initializeExpiringMessageManager();
initializeTypingStatusRepository();
initializeTypingStatusSender();
initializeGcmCheck();
initializeSignedPreKeyCheck();
initializePeriodicTasks();
initializeCircumvention();
initializeWebRtc();
initializePendingMessages();
initializeUnidentifiedDeliveryAbilityRefresh();
@ -194,6 +187,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
if (userHexEncodedPublicKey != null) {
if (TextSecurePreferences.getNeedsIsRevokedSlaveDeviceCheck(this)) {
MultiDeviceUtilities.checkIsRevokedSlaveDevice(this);
} else {
// We always update our current device links onto the server in case we failed to do so upon linking
MultiDeviceUtilities.updateDeviceLinksOnServer(this);
}
}
}
@ -337,16 +333,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
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() {
if (!TextSecurePreferences.isSignedPreKeyRegistered(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() {
if (TextSecurePreferences.needsFullContactSync(this)) {
ApplicationContext.getInstance(this).getJobManager().add(new MultiDeviceContactUpdateJob(this, true));

View File

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

View File

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

View File

@ -3,10 +3,8 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.animation.Animator;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
@ -29,17 +27,6 @@ import android.widget.TextView;
import android.widget.Toast;
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;
@ -62,7 +49,6 @@ import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.NoExternalStorageException;
import org.thoughtcrime.securesms.gcm.FcmUtil;
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
import org.thoughtcrime.securesms.jobs.RotateCertificateJob;
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.service.DirectoryRefreshListener;
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
import org.thoughtcrime.securesms.service.VerificationCodeParser;
import org.thoughtcrime.securesms.util.BackupUtil;
import org.thoughtcrime.securesms.util.DateUtils;
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.TextSecurePreferences;
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 AsYouTypeFormatter countryFormatter;
private ArrayAdapter<String> countrySpinnerAdapter;
private Spinner countrySpinner;
private LabeledEditText countryCode;
@ -149,7 +131,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
private VerificationPinKeyboard keyboard;
private VerificationCodeView verificationCodeView;
private RegistrationState registrationState;
private SmsRetrieverReceiver smsRetrieverReceiver;
private SignalServiceAccountManager accountManager;
private int debugTapCounter;
@ -163,13 +144,11 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
initializeSpinner();
initializeNumber();
initializeBackupDetection();
initializeChallengeListener();
}
@Override
public void onDestroy() {
super.onDestroy();
shutdownChallengeListener();
markAsVerifying(false);
EventBus.getDefault().unregister(this);
}
@ -179,7 +158,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
if (requestCode == PICK_COUNTRY && resultCode == RESULT_OK && data != null) {
this.countryCode.setText(String.valueOf(data.getIntExtra("country_code", 1)));
setCountryDisplay(data.getStringExtra("country_name"));
setCountryFormatter(data.getIntExtra("country_code", 1));
} else if (requestCode == CAPTCHA && resultCode == RESULT_OK && data != null) {
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() {
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")
@ -338,14 +299,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
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() {
return PhoneNumberFormatter.formatE164(countryCode.getText().toString(),
number.getText().toString());
@ -436,20 +389,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
Dialogs.showAlertDialog(this,
getString(R.string.RegistrationActivity_invalid_number),
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.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);
}
}
@SuppressLint("StaticFieldLeak")
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);
Optional<String> fcmToken;
if (gcmSupported) {
fcmToken = FcmUtil.getToken();
} else {
fcmToken = Optional.absent();
}
Optional<String> fcmToken = Optional.absent();
accountManager = AccountManagerFactory.createManager(RegistrationActivity.this, e164number, password);
accountManager.requestSmsVerificationCode(smsRetrieverSupported, registrationState.captchaToken);
@ -939,19 +857,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
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) {
TextSecurePreferences.setVerifying(this, verifying);
@ -961,13 +866,8 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
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;
}
}
private void onWrongNumberClicked() {
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()));
}
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 {
@Override
public void afterTextChanged(Editable s) {
if (TextUtils.isEmpty(s) || !TextUtils.isDigitsOnly(s)) {
setCountryDisplay(getString(R.string.RegistrationActivity_select_your_country));
countryFormatter = null;
return;
}
int countryCode = Integer.parseInt(s.toString());
String regionCode = PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(countryCode);
setCountryFormatter(countryCode);
setCountryDisplay(PhoneNumberFormatter.getRegionDisplayName(regionCode));
if (!TextUtils.isEmpty(regionCode) && !regionCode.equals("ZZ")) {
number.requestFocus();
}
setCountryDisplay("N/A");
}
@Override
@ -1042,24 +905,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
@Override
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

View File

@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.components;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
@ -14,22 +13,18 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import org.thoughtcrime.securesms.ApplicationContext;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
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 network.loki.messenger.R;
public class ConversationItemFooter extends LinearLayout {
private TextView dateView;
private TextView simView;
private ExpirationTimerView timerView;
private ImageView insecureIndicatorView;
private DeliveryStatusView deliveryStatusView;
@ -53,7 +48,6 @@ public class ConversationItemFooter extends LinearLayout {
inflate(getContext(), R.layout.conversation_item_footer, this);
dateView = findViewById(R.id.footer_date);
simView = findViewById(R.id.footer_sim_info);
timerView = findViewById(R.id.footer_expiration_timer);
insecureIndicatorView = findViewById(R.id.footer_insecure_indicator);
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) {
presentDate(messageRecord, locale);
presentSimInfo(messageRecord);
presentTimer(messageRecord);
presentInsecureIndicator(messageRecord);
presentDeliveryStatus(messageRecord);
@ -82,7 +75,6 @@ public class ConversationItemFooter extends LinearLayout {
public void setTextColor(int color) {
dateView.setTextColor(color);
simView.setTextColor(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")
private void presentTimer(@NonNull final MessageRecord messageRecord) {
if (messageRecord.getExpiresIn() > 0 && !messageRecord.isPending()) {

View File

@ -7,26 +7,18 @@ import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
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.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
import network.loki.messenger.R;
public class SignalMapView extends LinearLayout {
private MapView mapView;
private ImageView imageView;
private TextView textView;
@ -49,7 +41,6 @@ public class SignalMapView extends LinearLayout {
setOrientation(LinearLayout.VERTICAL);
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.textView = ViewUtil.findById(this, R.id.address_view);
}
@ -57,39 +48,8 @@ public class SignalMapView extends LinearLayout {
public ListenableFuture<Bitmap> display(final SignalPlace place) {
final SettableFuture<Bitmap> future = new SettableFuture<>();
this.mapView.onCreate(null);
this.mapView.onResume();
this.mapView.setVisibility(View.VISIBLE);
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());
return future;

View File

@ -7,8 +7,6 @@ import android.text.TextUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
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.util.JsonUtils;
@ -17,6 +15,22 @@ import java.io.IOException;
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 TAG = SignalPlace.class.getSimpleName();

View File

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

View File

@ -13,11 +13,7 @@ import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
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.contactshare.Contact.Email;
import org.thoughtcrime.securesms.contactshare.Contact.Phone;
@ -34,6 +30,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import network.loki.messenger.R;
public final class ContactUtil {
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) {
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
try {
PhoneNumber parsed = util.parse(phoneNumber, fallbackLocale.getISO3Country());
return util.format(parsed, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL);
} catch (NumberParseException e) {
return phoneNumber;
}
}
public static @NonNull String getNormalizedPhoneNumber(@NonNull Context context, @NonNull String number) {
Address address = Address.fromExternal(context, number);

View File

@ -77,7 +77,6 @@ import android.widget.TextView;
import android.widget.Toast;
import com.annimon.stream.Stream;
import com.google.android.gms.location.places.ui.PlacePicker;
import org.greenrobot.eventbus.EventBus;
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.Draft;
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.IdentityRecord;
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.MediaConstraints;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.mms.QuoteId;
@ -662,10 +659,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
recipient.addListener(this);
fragment.reloadList();
break;
/*
case PICK_LOCATION:
SignalPlace place = new SignalPlace(PlacePicker.getPlace(data, this));
attachmentManager.setLocation(place, getCurrentMediaConstraints());
break;
*/
case PICK_GIF:
setMedia(data.getData(),
MediaType.GIF,
@ -1240,15 +1239,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private boolean handleDisplayQuickContact() {
if (recipient.getAddress().isGroup()) return false;
return !recipient.getAddress().isGroup();
// if (recipient.getContactUri() != null) {
// ContactsContract.QuickContact.showQuickContact(ConversationActivity.this, titleView, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
// } else {
// handleAddToContacts();
// }
return true;
}
private void handleAddAttachment() {

View File

@ -10,12 +10,6 @@ import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
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.GroupUtil;
import org.thoughtcrime.securesms.util.NumberUtil;
@ -200,19 +194,10 @@ public class Address implements Parcelable, Comparable<Address> {
private final Optional<PhoneNumber> localNumber;
private final String localCountryCode;
private final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
private final Pattern ALPHA_PATTERN = Pattern.compile("[a-zA-Z]");
ExternalAddressFormatter(@NonNull String localNumberString) {
try {
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);
}
throw new AssertionError("Not Implemented");
}
ExternalAddressFormatter(@NonNull String localCountryCode, boolean countryCode) {
@ -222,61 +207,7 @@ public class Address implements Parcelable, Comparable<Address> {
public String format(@Nullable String number) {
if (number == null) return "Unknown";
if (GroupUtil.isEncodedGroup(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;
}
return number;
}
private @Nullable String parseAreaCode(@NonNull String e164Number, int countryCode) {

View File

@ -1,24 +1,16 @@
package org.thoughtcrime.securesms.database.helpers;
import android.Manifest;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.thoughtcrime.securesms.logging.Log;
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.crypto.AttachmentSecret;
@ -26,7 +18,6 @@ import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream;
import org.thoughtcrime.securesms.crypto.MasterCipher;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DraftDatabase;
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.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.DelimiterUtil;
import org.thoughtcrime.securesms.util.Hex;
@ -1385,71 +1376,18 @@ public class ClassicOpenHelper extends SQLiteOpenHelper {
add("AC");
}};
private final Phonenumber.PhoneNumber localNumber;
private final String localNumberString;
private final String localCountryCode;
private final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
private final Pattern ALPHA_PATTERN = Pattern.compile("[a-zA-Z]");
public NumberMigrator(String localNumber) {
try {
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) {
if (number == null) return "Unknown";
if (number.startsWith("__textsecure_group__!")) 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;
}
return number;
}
}

View File

@ -1,19 +1,12 @@
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.support.v4.content.AsyncTaskLoader;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Map;
public class CountryListLoader extends AsyncTaskLoader<ArrayList<Map<String, String>>> {
@ -23,19 +16,7 @@ public class CountryListLoader extends AsyncTaskLoader<ArrayList<Map<String, Str
@Override
public ArrayList<Map<String, String>> loadInBackground() {
Set<String> regions = PhoneNumberUtil.getInstance().getSupportedRegions();
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;
return new ArrayList<>();
}
private static class RegionComparator implements Comparator<Map<String, String>> {

View File

@ -9,13 +9,11 @@ import org.thoughtcrime.securesms.DeviceListFragment;
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
import org.thoughtcrime.securesms.gcm.FcmService;
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
import org.thoughtcrime.securesms.jobs.AttachmentUploadJob;
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob;
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
@ -87,7 +85,6 @@ import network.loki.messenger.BuildConfig;
MultiDeviceBlockedUpdateJob.class,
DeviceListFragment.class,
RefreshAttributesJob.class,
FcmRefreshJob.class,
RequestGroupInfoJob.class,
PushGroupUpdateJob.class,
AvatarDownloadJob.class,
@ -100,7 +97,6 @@ import network.loki.messenger.BuildConfig;
MultiDeviceProfileKeyUpdateJob.class,
SendReadReceiptJob.class,
AppProtectionPreferenceFragment.class,
FcmService.class,
RotateCertificateJob.class,
SendDeliveryReceiptJob.class,
RotateProfileKeyJob.class,

View File

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

View File

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

View File

@ -9,7 +9,6 @@ import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob;
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
import org.thoughtcrime.securesms.jobs.MmsDownloadJob;
import org.thoughtcrime.securesms.jobs.MmsReceiveJob;
@ -59,7 +58,6 @@ public class WorkManagerFactoryMappings {
put(CleanPreKeysJob.class.getName(), CleanPreKeysJob.KEY);
put(CreateSignedPreKeyJob.class.getName(), CreateSignedPreKeyJob.KEY);
put(DirectoryRefreshJob.class.getName(), DirectoryRefreshJob.KEY);
put(FcmRefreshJob.class.getName(), FcmRefreshJob.KEY);
put(LocalBackupJob.class.getName(), LocalBackupJob.KEY);
put(MmsDownloadJob.class.getName(), MmsDownloadJob.KEY);
put(MmsReceiveJob.class.getName(), MmsReceiveJob.KEY);

View File

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

View File

@ -32,7 +32,6 @@ public final class JobManagerFactories {
put(CleanPreKeysJob.KEY, new CleanPreKeysJob.Factory());
put(CreateSignedPreKeyJob.KEY, new CreateSignedPreKeyJob.Factory());
put(DirectoryRefreshJob.KEY, new DirectoryRefreshJob.Factory(application));
put(FcmRefreshJob.KEY, new FcmRefreshJob.Factory());
put(LocalBackupJob.KEY, new LocalBackupJob.Factory());
put(MmsDownloadJob.KEY, new MmsDownloadJob.Factory());
put(MmsReceiveJob.KEY, new MmsReceiveJob.Factory());

View File

@ -141,6 +141,7 @@ import org.whispersystems.signalservice.loki.api.DeviceLinkingSession;
import org.whispersystems.signalservice.loki.api.LokiAPI;
import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities;
import org.whispersystems.signalservice.loki.api.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI;
import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher;
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus;
import org.whispersystems.signalservice.loki.messaging.LokiServiceMessage;
@ -708,6 +709,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
LokiThreadFriendRequestStatus status = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
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");
Log.d("Loki", "Sent friend request to " + hexEncodedPublicKey);
} else if (status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
@ -1228,6 +1230,17 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
TextSecurePreferences.setMultiDevice(context, true);
// Send a background message to the master device
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
if (content.senderDisplayName.isPresent() && content.senderDisplayName.get().length() > 0) {
TextSecurePreferences.setProfileName(context, content.senderDisplayName.get());
@ -1240,7 +1253,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
if (content.getSyncMessage().isPresent() && content.getSyncMessage().get().getContacts().isPresent()) {
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) {

View File

@ -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> {
val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context)
return LokiDeviceLinkUtilities.getAllLinkedDeviceHexEncodedPublicKeys(hexEncodedPublicKey).map { keys ->

View File

@ -114,7 +114,6 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega
}
override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) {
LokiFileServerAPI.shared.addDeviceLink(deviceLink)
TextSecurePreferences.setMasterHexEncodedPublicKey(this, deviceLink.masterHexEncodedPublicKey)
val intent = Intent(this, HomeActivity::class.java)
show(intent)

View File

@ -12,6 +12,7 @@ import android.view.View
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_linked_devices.*
import network.loki.messenger.R
import nl.komponents.kovenant.functional.bind
import nl.komponents.kovenant.ui.failUi
import nl.komponents.kovenant.ui.successUi
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.util.TextSecurePreferences
import org.whispersystems.signalservice.loki.api.DeviceLink
import org.whispersystems.signalservice.loki.api.LokiAPI
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI
import java.util.*
import kotlin.concurrent.schedule
@ -143,8 +145,9 @@ class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LoaderManager
}
override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) {
LokiFileServerAPI.shared.addDeviceLink(deviceLink).success {
signAndSendDeviceLinkMessage(this, deviceLink).successUi {
LokiFileServerAPI.shared.addDeviceLink(deviceLink).bind(LokiAPI.sharedWorkContext) {
signAndSendDeviceLinkMessage(this, deviceLink)
}.successUi {
LoaderManager.getInstance(this).restartLoader(0, null, this)
}.success {
TextSecurePreferences.setMultiDevice(this, true)
@ -153,14 +156,10 @@ class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LoaderManager
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 {
LokiFileServerAPI.shared.removeDeviceLink(deviceLink) // If this fails we have a problem
DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slaveHexEncodedPublicKey)
}
}.failUi {
DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slaveHexEncodedPublicKey)
Toast.makeText(this, "Couldn't link device", Toast.LENGTH_LONG).show()
}
}

View File

@ -33,20 +33,12 @@ import android.provider.OpenableColumns;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
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.view.View;
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 network.loki.messenger.R;
import org.thoughtcrime.securesms.TransportOption;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.components.AudioView;
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.SignalPlace;
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.providers.BlobProvider;
import org.thoughtcrime.securesms.providers.DeprecatedPersistentBlobProvider;
@ -77,6 +71,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import network.loki.messenger.R;
public class AttachmentManager {

View File

@ -14,17 +14,14 @@ import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.Preference;
import org.thoughtcrime.securesms.logging.Log;
import android.widget.Toast;
import com.google.firebase.iid.FirebaseInstanceId;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.LogSubmitActivity;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.RegistrationActivity;
import org.thoughtcrime.securesms.contacts.ContactAccessor;
import org.thoughtcrime.securesms.contacts.ContactIdentityManager;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.push.AccountManagerFactory;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
@ -34,6 +31,8 @@ import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedE
import java.io.IOException;
import network.loki.messenger.R;
public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
private static final String TAG = AdvancedPreferenceFragment.class.getSimpleName();
@ -187,15 +186,11 @@ public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
SignalServiceAccountManager accountManager = AccountManagerFactory.createManager(context);
try {
accountManager.setGcmId(Optional.<String>absent());
accountManager.setGcmId(Optional.absent());
} catch (AuthorizationFailedException e) {
Log.w(TAG, e);
}
if (!TextSecurePreferences.isFcmDisabled(context)) {
FirebaseInstanceId.getInstance().deleteInstanceId();
}
return SUCCESS;
} catch (IOException ioe) {
Log.w(TAG, ioe);

View File

@ -1,15 +1,12 @@
package org.thoughtcrime.securesms.push;
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.whispersystems.signalservice.api.SignalServiceAccountManager;
import network.loki.messenger.BuildConfig;
public class AccountManagerFactory {
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) {
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),
number, password, BuildConfig.USER_AGENT);
}

View File

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

View File

@ -6,7 +6,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.WorkerThread;
import com.annimon.stream.Stream;
import com.google.android.gms.common.util.Hex;
import org.thoughtcrime.securesms.ApplicationContext;
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.dependencies.InjectableType;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.util.Hex;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.guava.Optional;
@ -81,8 +81,8 @@ public final class StickerPackPreviewRepository implements InjectableType {
@WorkerThread
private Optional<StickerManifestResult> getManifestRemote(@NonNull String packId, @NonNull String packKey) {
try {
byte[] packIdBytes = Hex.stringToBytes(packId);
byte[] packKeyBytes = Hex.stringToBytes(packKey);
byte[] packIdBytes = Hex.fromStringCondensed(packId);
byte[] packKeyBytes = Hex.fromStringCondensed(packKey);
SignalServiceStickerManifest remoteManifest = receiver.retrieveStickerManifest(packIdBytes, packKeyBytes);
StickerManifest localManifest = new StickerManifest(packId,
packKey,

View File

@ -5,9 +5,9 @@ import android.support.annotation.NonNull;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
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.util.Hex;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
@ -32,8 +32,8 @@ public final class StickerRemoteUriFetcher implements DataFetcher<InputStream> {
@Override
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
try {
byte[] packIdBytes = Hex.stringToBytes(stickerUri.getPackId());
byte[] packKeyBytes = Hex.stringToBytes(stickerUri.getPackKey());
byte[] packIdBytes = Hex.fromStringCondensed(stickerUri.getPackId());
byte[] packKeyBytes = Hex.fromStringCondensed(stickerUri.getPackKey());
InputStream stream = receiver.retrieveSticker(packIdBytes, packKeyBytes, stickerUri.getStickerId());
callback.onDataReady(stream);

View File

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

View File

@ -2,13 +2,6 @@ package org.thoughtcrime.securesms.util;
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.Set;
@ -24,23 +17,7 @@ public class ShortCodeUtil {
}};
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;
}
}
}

View File

@ -32,20 +32,14 @@ import android.os.Looper;
import android.provider.Telephony;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresPermission;
import android.telephony.TelephonyManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.StyleSpan;
import com.google.android.mms.pdu_alt.CharacterSets;
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.database.Address;
import org.thoughtcrime.securesms.logging.Log;
@ -58,7 +52,7 @@ import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.text.DecimalFormat;
import java.util.ArrayList;
@ -73,6 +67,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import network.loki.messenger.BuildConfig;
public class Util {
private static final String TAG = Util.class.getSimpleName();
@ -170,27 +166,15 @@ public class Util {
}
public static @NonNull String toIsoString(byte[] bytes) {
try {
return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1);
} catch (UnsupportedEncodingException e) {
throw new AssertionError("ISO_8859_1 must be supported!");
}
return new String(bytes, StandardCharsets.ISO_8859_1);
}
public static byte[] toIsoBytes(String isoString) {
try {
return isoString.getBytes(CharacterSets.MIMENAME_ISO_8859_1);
} catch (UnsupportedEncodingException e) {
throw new AssertionError("ISO_8859_1 must be supported!");
}
return isoString.getBytes(StandardCharsets.ISO_8859_1);
}
public static byte[] toUtf8Bytes(String utf8String) {
try {
return utf8String.getBytes(CharacterSets.MIMENAME_UTF_8);
} catch (UnsupportedEncodingException e) {
throw new AssertionError("UTF_8 must be supported!");
}
return utf8String.getBytes(StandardCharsets.UTF_8);
}
public static void wait(Object lock, long timeout) {
@ -279,27 +263,6 @@ public class Util {
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) {
String simCountryIso = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)).getSimCountryIso();
return Optional.fromNullable(simCountryIso != null ? simCountryIso.toUpperCase() : null);