diff --git a/README.md b/README.md
index 459a1abdbe4..c0c7f6f7b76 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,13 @@ Currently available on the Play store.
+#WebSocket Support#
+
+This branch adds rudimentary WebSocket-ONLY support to Signal Private Messenger.
+In order to build a modified version of libtextsecure is needed, for that [checkout](https://github.com/JavaJens/libtextsecure-java/tree/fix/maven_local) my fork
+
+and run: ````./gradlew tasks installArchives```` to install in local maven directory.
+
## Contributing Bug reports
We use GitHub for bug tracking. Please search the existing issues for your bug and create a new one if the issue is not yet tracked!
diff --git a/build.gradle b/build.gradle
index c422205bbcd..70fa66832d9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,6 @@
buildscript {
repositories {
+ mavenLocal()
maven {
url "https://repo1.maven.org/maven2"
}
@@ -72,7 +73,7 @@ dependencies {
compile 'org.whispersystems:jobmanager:1.0.2'
compile 'org.whispersystems:libpastelog:1.0.7'
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
- compile 'org.whispersystems:textsecure-android:1.8.6'
+ compile 'org.whispersystems:textsecure-android:2.8.6'
compile 'com.h6ah4i.android.compat:mulsellistprefcompat:1.0.0'
compile 'com.google.zxing:core:3.2.1'
@@ -165,11 +166,12 @@ android {
buildConfigField "long", "BUILD_TIMESTAMP", System.currentTimeMillis() + "L"
buildConfigField "String", "TEXTSECURE_URL", "\"https://textsecure-service.whispersystems.org\""
- buildConfigField "String", "USER_AGENT", "\"OWA\""
+ buildConfigField "String", "USER_AGENT", "\"JEN\""
buildConfigField "String", "REDPHONE_MASTER_URL", "\"https://redphone-master.whispersystems.org\""
buildConfigField "String", "REDPHONE_RELAY_HOST", "\"relay.whispersystems.org\""
buildConfigField "String", "REDPHONE_PREFIX_NAME", "\".whispersystems.org\""
buildConfigField "boolean", "DEV_BUILD", "false"
+ buildConfigField "boolean", "FORCE_WEBSOCKETS", "false"
}
compileOptions {
@@ -216,9 +218,24 @@ android {
dev.initWith(buildTypes.debug)
dev {
buildConfigField "boolean", "DEV_BUILD", "true"
+ versionNameSuffix "-dev"
+ }
+ websockets.initWith(buildTypes.dev)
+ websockets {
+ buildConfigField "boolean", "FORCE_WEBSOCKETS", "true"
}
}
+ productFlavors {
+ prod {
+ // defaults
+ }
+ staging {
+ buildConfigField "String", "TEXTSECURE_URL", "\"https://textsecure-service-staging.whispersystems.org\""
+ buildConfigField "String", "REDPHONE_MASTER_URL", "\"https://redphone-staging.whispersystems.org\""
+ buildConfigField "String", "REDPHONE_RELAY_HOST", "\"redphone-staging-relay.whispersystems.org\""
+ }
+ }
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cf6bd55c849..2d74297c884 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -474,11 +474,14 @@
than 4.0 must have a registered Google Account. Devices running Android 4.0 or newer do not
require a Google account, but must have the Play Store app installed.
+ "This device setup is not officially supported, and if you experience bugs you will have to resolve them yourself."
+
Double-check that this is your number! We\'re about to verify it with an SMS.
Continue
Edit
+ I Understand
Possible problems
diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java
index aaab48328d8..e6eea5f30cb 100644
--- a/src/org/thoughtcrime/securesms/ApplicationContext.java
+++ b/src/org/thoughtcrime/securesms/ApplicationContext.java
@@ -21,6 +21,7 @@
import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy;
import android.os.StrictMode.VmPolicy;
+import android.content.Intent;
import org.thoughtcrime.securesms.crypto.PRNGFixes;
import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule;
@@ -39,6 +40,7 @@
import org.whispersystems.jobqueue.requirements.NetworkRequirementProvider;
import org.whispersystems.libaxolotl.logging.AxolotlLoggerProvider;
import org.whispersystems.libaxolotl.util.AndroidAxolotlLogger;
+import org.thoughtcrime.securesms.service.MessageRetrievalService;
import dagger.ObjectGraph;
@@ -125,10 +127,14 @@ private void initializeDependencyInjection() {
}
private void initializeGcmCheck() {
- if (TextSecurePreferences.isPushRegistered(this) &&
+ if (TextSecurePreferences.isGcmRegistered(this) &&
TextSecurePreferences.getGcmRegistrationId(this) == null)
{
this.jobManager.add(new GcmRefreshJob(this));
+ } else if (!TextSecurePreferences.isGcmRegistered(this) &&
+ TextSecurePreferences.isPushRegistered(this))
+ {
+ startService(new Intent(this, MessageRetrievalService.class));
}
}
diff --git a/src/org/thoughtcrime/securesms/RegistrationActivity.java b/src/org/thoughtcrime/securesms/RegistrationActivity.java
index 61b94f92f60..45261ac6f1c 100644
--- a/src/org/thoughtcrime/securesms/RegistrationActivity.java
+++ b/src/org/thoughtcrime/securesms/RegistrationActivity.java
@@ -24,6 +24,7 @@
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
+import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.Dialogs;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -196,34 +197,51 @@ public void onClick(View v) {
int gcmStatus = GooglePlayServicesUtil.isGooglePlayServicesAvailable(self);
if (gcmStatus != ConnectionResult.SUCCESS) {
- if (GooglePlayServicesUtil.isUserRecoverableError(gcmStatus)) {
+ if(BuildConfig.FORCE_WEBSOCKETS) {
+ AlertDialog.Builder unsupportedDialog = new AlertDialog.Builder(self);
+ unsupportedDialog.setTitle(getString(R.string.RegistrationActivity_unsupported));
+ unsupportedDialog.setMessage(getString(R.string.RegistrationActivity_websockets_only_unsupported));
+ unsupportedDialog.setPositiveButton(getString(R.string.RegistrationActivity_I_understand),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ showDoubleCheckDialog(self,e164number);
+ }
+ });
+ unsupportedDialog.show();
+ } else if (GooglePlayServicesUtil.isUserRecoverableError(gcmStatus)) {
GooglePlayServicesUtil.getErrorDialog(gcmStatus, self, 9000).show();
+ return;
} else {
Dialogs.showAlertDialog(self, getString(R.string.RegistrationActivity_unsupported),
getString(R.string.RegistrationActivity_sorry_this_device_is_not_supported_for_data_messaging));
+ return;
}
- return;
+ } else {
+ showDoubleCheckDialog(self,e164number);
}
-
- AlertDialog.Builder dialog = new AlertDialog.Builder(self);
- dialog.setTitle(PhoneNumberFormatter.getInternationalFormatFromE164(e164number));
- dialog.setMessage(R.string.RegistrationActivity_we_will_now_verify_that_the_following_number_is_associated_with_your_device_s);
- dialog.setPositiveButton(getString(R.string.RegistrationActivity_continue),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Intent intent = new Intent(self, RegistrationProgressActivity.class);
- intent.putExtra("e164number", e164number);
- intent.putExtra("master_secret", masterSecret);
- startActivity(intent);
- finish();
- }
- });
- dialog.setNegativeButton(getString(R.string.RegistrationActivity_edit), null);
- dialog.show();
}
}
+ private void showDoubleCheckDialog(final RegistrationActivity self, final String e164number){
+ AlertDialog.Builder dialog = new AlertDialog.Builder(self);
+ dialog.setTitle(PhoneNumberFormatter.getInternationalFormatFromE164(e164number));
+ dialog.setMessage(R.string.RegistrationActivity_we_will_now_verify_that_the_following_number_is_associated_with_your_device_s);
+ dialog.setPositiveButton(getString(R.string.RegistrationActivity_continue),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent intent = new Intent(self, RegistrationProgressActivity.class);
+ intent.putExtra("e164number", e164number);
+ intent.putExtra("master_secret", masterSecret);
+ startActivity(intent);
+ finish();
+ }
+ });
+ dialog.setNegativeButton(getString(R.string.RegistrationActivity_edit), null);
+ dialog.show();
+ }
+
private class CountryCodeChangedListener implements TextWatcher {
@Override
public void afterTextChanged(Editable s) {
diff --git a/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java b/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java
index 0e7feeee0db..f5cab96f01b 100644
--- a/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java
+++ b/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java
@@ -31,6 +31,7 @@
import android.widget.Toast;
import org.thoughtcrime.securesms.crypto.MasterSecret;
+import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
import org.thoughtcrime.securesms.service.RegistrationService;
import org.thoughtcrime.securesms.util.Dialogs;
@@ -333,7 +334,9 @@ private void handleVerificationComplete() {
}
shutdownService();
- startActivity(new Intent(this, ConversationListActivity.class));
+ ApplicationContext.getInstance(this)
+ .getJobManager()
+ .add(new PushNotificationReceiveJob(this));
finish();
}
@@ -521,8 +524,7 @@ protected Integer doInBackground(Void... params) {
TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context, e164number, password);
int registrationId = TextSecurePreferences.getLocalRegistrationId(context);
- accountManager.verifyAccountWithCode(code, signalingKey, registrationId, true);
-
+ accountManager.verifyAccountWithCode(code, signalingKey, true, registrationId, true);
return SUCCESS;
} catch (ExpectationFailedException e) {
Log.w(TAG, e);
diff --git a/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java b/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java
index 7a37e0a236e..e1483d688ce 100644
--- a/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java
+++ b/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java
@@ -35,7 +35,7 @@ public void onReceive(Context context, Intent intent) {
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
Log.w(TAG, "GCM message...");
- if (!TextSecurePreferences.isPushRegistered(context)) {
+ if (!TextSecurePreferences.isGcmRegistered(context)) {
Log.w(TAG, "Not push registered!");
return;
}
diff --git a/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java b/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java
index c704864bbba..31f3350c401 100644
--- a/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java
@@ -28,6 +28,7 @@
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;
+import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.redphone.signaling.RedPhoneAccountManager;
import org.thoughtcrime.redphone.signaling.UnauthorizedException;
import org.thoughtcrime.securesms.PlayServicesProblemActivity;
@@ -66,7 +67,7 @@ public void onRun() throws Exception {
Log.w(TAG, "GCM registrationId expired, reregistering...");
int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
- if (result != ConnectionResult.SUCCESS) {
+ if (result != ConnectionResult.SUCCESS || BuildConfig.FORCE_WEBSOCKETS) {
notifyGcmFailure();
} else {
String gcmId = GoogleCloudMessaging.getInstance(context).register(REGISTRATION_ID);
@@ -79,8 +80,9 @@ public void onRun() throws Exception {
}
TextSecurePreferences.setGcmRegistrationId(context, gcmId);
- TextSecurePreferences.setWebsocketRegistered(context, true);
+ TextSecurePreferences.setGcmRegistered(context, true);
}
+ TextSecurePreferences.setWebsocketRegistered(context, true);
}
}
diff --git a/src/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java b/src/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java
index 654b3ce304e..531ca63320f 100644
--- a/src/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java
@@ -45,7 +45,7 @@ public void onRun() throws IOException {
String token = textSecureAccountManager.getAccountVerificationToken();
redPhoneAccountManager.createAccount(token, new RedPhoneAccountAttributes(signalingKey, gcmRegistrationId));
- textSecureAccountManager.setAccountAttributes(signalingKey, registrationId, true);
+ textSecureAccountManager.setAccountAttributes(signalingKey, true, registrationId, true);
}
@Override
diff --git a/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java b/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
index 87be7a2a276..fdffefaf594 100644
--- a/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
+++ b/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
@@ -194,20 +194,22 @@ protected Integer doInBackground(Void... params) {
TextSecurePreferences.getLocalNumber(context),
TextSecurePreferences.getPushServerPassword(context));
- try {
- accountManager.setGcmId(Optional.absent());
- } catch (AuthorizationFailedException e) {
- Log.w(TAG, e);
+ if (TextSecurePreferences.isGcmRegistered(context)) {
+ try {
+ accountManager.setGcmId(Optional.absent());
+ } catch (AuthorizationFailedException e) {
+ Log.w(TAG, e);
+ }
+
+ try {
+ redPhoneAccountManager.setGcmId(Optional.absent());
+ } catch (UnauthorizedException e) {
+ Log.w(TAG, e);
+ }
+
+ GoogleCloudMessaging.getInstance(context).unregister();
}
- try {
- redPhoneAccountManager.setGcmId(Optional.absent());
- } catch (UnauthorizedException e) {
- Log.w(TAG, e);
- }
-
- GoogleCloudMessaging.getInstance(context).unregister();
-
return SUCCESS;
} catch (IOException ioe) {
Log.w(TAG, ioe);
diff --git a/src/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java b/src/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java
index 9e70ce8cd98..5e2b1c4cfc7 100644
--- a/src/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java
+++ b/src/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java
@@ -37,6 +37,9 @@ private void handleRefreshAction(Context context) {
public static void schedule(Context context) {
if (!TextSecurePreferences.isPushRegistered(context)) return;
+ if (!TextSecurePreferences.isGcmRegistered(context)) {
+ context.startService(new Intent(context, MessageRetrievalService.class));
+ }
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(DirectoryRefreshListener.REFRESH_EVENT);
diff --git a/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java b/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java
index 1eb29e633ea..883b33fec53 100644
--- a/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java
+++ b/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java
@@ -149,8 +149,8 @@ private synchronized boolean isConnectionNecessary() {
Log.w(TAG, String.format("Network requirement: %s, active activities: %s, push pending: %s",
networkRequirement.isPresent(), activeActivities, pushPending.size()));
- return TextSecurePreferences.isWebsocketRegistered(this) &&
- (activeActivities > 0 || !pushPending.isEmpty()) &&
+ return TextSecurePreferences.isWebsocketRegistered(this) &&
+ (activeActivities > 0 || !pushPending.isEmpty() || !TextSecurePreferences.isGcmRegistered(this)) &&
networkRequirement.isPresent();
}
diff --git a/src/org/thoughtcrime/securesms/service/RegistrationService.java b/src/org/thoughtcrime/securesms/service/RegistrationService.java
index 879aac469ae..ae108355c20 100644
--- a/src/org/thoughtcrime/securesms/service/RegistrationService.java
+++ b/src/org/thoughtcrime/securesms/service/RegistrationService.java
@@ -10,6 +10,8 @@
import android.os.IBinder;
import android.util.Log;
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import org.thoughtcrime.redphone.signaling.RedPhoneAccountAttributes;
@@ -203,7 +205,7 @@ private void handleSmsRegistrationIntent(Intent intent) {
setState(new RegistrationState(RegistrationState.STATE_VERIFYING, number));
String challenge = waitForChallenge();
- accountManager.verifyAccountWithCode(challenge, signalingKey, registrationId, true);
+ accountManager.verifyAccountWithCode(challenge, signalingKey, true, registrationId, true);
handleCommonRegistration(accountManager, number, password, signalingKey);
markAsVerified(number, password, signalingKey);
@@ -242,23 +244,33 @@ private void handleCommonRegistration(TextSecureAccountManager accountManager, S
SignedPreKeyRecord signedPreKey = PreKeyUtil.generateSignedPreKey(this, identityKey);
accountManager.setPreKeys(identityKey.getPublicKey(),lastResort, signedPreKey, records);
- setState(new RegistrationState(RegistrationState.STATE_GCM_REGISTERING, number));
+ if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS &&
+ !BuildConfig.FORCE_WEBSOCKETS)
+ {
+ setState(new RegistrationState(RegistrationState.STATE_GCM_REGISTERING, number));
- String gcmRegistrationId = GoogleCloudMessaging.getInstance(this).register(GcmRefreshJob.REGISTRATION_ID);
- accountManager.setGcmId(Optional.of(gcmRegistrationId));
+ String gcmRegistrationId = GoogleCloudMessaging.getInstance(this).register(GcmRefreshJob.REGISTRATION_ID);
+ accountManager.setGcmId(Optional.of(gcmRegistrationId));
- TextSecurePreferences.setGcmRegistrationId(this, gcmRegistrationId);
+ TextSecurePreferences.setGcmRegistrationId(this, gcmRegistrationId);
+ TextSecurePreferences.setGcmRegistered(this, true);
+ }
TextSecurePreferences.setWebsocketRegistered(this, true);
DatabaseFactory.getIdentityDatabase(this).saveIdentity(self.getRecipientId(), identityKey.getPublicKey());
DirectoryHelper.refreshDirectory(this, accountManager, number);
- RedPhoneAccountManager redPhoneAccountManager = new RedPhoneAccountManager(BuildConfig.REDPHONE_MASTER_URL,
- new RedPhoneTrustStore(this),
- number, password);
-
- String verificationToken = accountManager.getAccountVerificationToken();
- redPhoneAccountManager.createAccount(verificationToken, new RedPhoneAccountAttributes(signalingKey, gcmRegistrationId));
+ //if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS &&
+ // !BuildConfig.FORCE_WEBSOCKETS)
+ //{
+ // RedPhoneAccountManager redPhoneAccountManager = new RedPhoneAccountManager(BuildConfig.REDPHONE_MASTER_URL,
+ // new RedPhoneTrustStore(this),
+ // number, password);
+ // String verificationToken = accountManager.getAccountVerificationToken();
+ // redPhoneAccountManager.createAccount(verificationToken, new RedPhoneAccountAttributes(signalingKey,
+ // TextSecurePreferences.getGcmRegistrationId(this)));
+ //}
+ accountManager.getAccountVerificationToken();
DirectoryRefreshListener.schedule(this);
}
@@ -290,6 +302,7 @@ private void markAsVerifying(boolean verifying) {
if (verifying) {
TextSecurePreferences.setPushRegistered(this, false);
+ TextSecurePreferences.setGcmRegistered(this, false);
}
}
diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
index 4b428d9fac9..a2aa1cd633e 100644
--- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
+++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
@@ -66,6 +66,7 @@ public class TextSecurePreferences {
private static final String LOCAL_NUMBER_PREF = "pref_local_number";
private static final String VERIFYING_STATE_PREF = "pref_verifying";
public static final String REGISTERED_GCM_PREF = "pref_gcm_registered";
+ public static final String REGISTERED_PUSH_PREF = "pref_push_registered";
private static final String GCM_PASSWORD_PREF = "pref_gcm_password";
private static final String PROMPTED_PUSH_REGISTRATION_PREF = "pref_prompted_push_registration";
private static final String PROMPTED_DEFAULT_SMS_PREF = "pref_prompted_default_sms";
@@ -392,11 +393,20 @@ public static void setVerifying(Context context, boolean verifying) {
}
public static boolean isPushRegistered(Context context) {
- return getBooleanPreference(context, REGISTERED_GCM_PREF, false);
+ return getBooleanPreference(context, REGISTERED_PUSH_PREF, false);
}
public static void setPushRegistered(Context context, boolean registered) {
Log.w("TextSecurePreferences", "Setting push registered: " + registered);
+ setBooleanPreference(context, REGISTERED_PUSH_PREF, registered);
+ }
+
+ public static boolean isGcmRegistered(Context context) {
+ return getBooleanPreference(context, REGISTERED_GCM_PREF, false);
+ }
+
+ public static void setGcmRegistered(Context context, boolean registered) {
+ Log.w("TextSecurePreferences", "Setting gcm registered: " + registered);
setBooleanPreference(context, REGISTERED_GCM_PREF, registered);
}