2013-03-26 04:26:03 +00:00
|
|
|
package org.thoughtcrime.securesms.service;
|
|
|
|
|
|
|
|
import android.app.Service;
|
|
|
|
import android.content.BroadcastReceiver;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.content.IntentFilter;
|
|
|
|
import android.os.Binder;
|
|
|
|
import android.os.Handler;
|
|
|
|
import android.os.IBinder;
|
|
|
|
import android.util.Log;
|
2013-07-19 00:42:45 +00:00
|
|
|
import android.util.Pair;
|
2013-03-26 04:26:03 +00:00
|
|
|
|
|
|
|
import com.google.android.gcm.GCMRegistrar;
|
2013-07-11 00:54:38 +00:00
|
|
|
import org.thoughtcrime.securesms.R;
|
2013-08-18 02:06:04 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
|
|
|
import org.whispersystems.textsecure.crypto.IdentityKey;
|
2013-08-18 01:37:18 +00:00
|
|
|
import org.whispersystems.textsecure.crypto.MasterSecret;
|
|
|
|
import org.whispersystems.textsecure.crypto.PreKeyUtil;
|
|
|
|
import org.whispersystems.textsecure.storage.PreKeyRecord;
|
2013-07-10 23:33:14 +00:00
|
|
|
import org.thoughtcrime.securesms.gcm.GcmIntentService;
|
|
|
|
import org.thoughtcrime.securesms.gcm.GcmRegistrationTimeoutException;
|
2013-07-11 21:58:40 +00:00
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
2013-07-19 00:42:45 +00:00
|
|
|
import org.whispersystems.textsecure.directory.DirectoryDescriptor;
|
|
|
|
import org.whispersystems.textsecure.directory.NumberFilter;
|
2013-07-10 23:22:58 +00:00
|
|
|
import org.whispersystems.textsecure.push.PushServiceSocket;
|
2013-07-10 02:48:33 +00:00
|
|
|
import org.whispersystems.textsecure.util.Util;
|
2013-03-26 04:26:03 +00:00
|
|
|
|
2013-07-19 00:42:45 +00:00
|
|
|
import java.io.File;
|
2013-03-26 04:26:03 +00:00
|
|
|
import java.io.IOException;
|
2013-08-15 15:25:30 +00:00
|
|
|
import java.util.List;
|
2013-03-26 04:26:03 +00:00
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
import java.util.concurrent.Executors;
|
|
|
|
|
|
|
|
/**
|
2013-07-08 23:29:28 +00:00
|
|
|
* The RegisterationService handles the process of PushService registration and verification.
|
|
|
|
* If it receives an intent with a REGISTER_NUMBER_ACTION, it does the following through
|
|
|
|
* an executor:
|
2013-03-26 04:26:03 +00:00
|
|
|
*
|
|
|
|
* 1) Generate secrets.
|
|
|
|
* 2) Register the specified number and those secrets with the server.
|
|
|
|
* 3) Wait for a challenge SMS.
|
|
|
|
* 4) Verify the challenge with the server.
|
|
|
|
* 5) Start the GCM registration process.
|
|
|
|
* 6) Retrieve the current directory.
|
|
|
|
*
|
|
|
|
* The RegistrationService broadcasts its state throughout this process, and also makes its
|
|
|
|
* state available through service binding. This enables a View to display progress.
|
|
|
|
*
|
|
|
|
* @author Moxie Marlinspike
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
public class RegistrationService extends Service {
|
|
|
|
|
2013-07-08 23:29:28 +00:00
|
|
|
public static final String REGISTER_NUMBER_ACTION = "org.thoughtcrime.securesms.RegistrationService.REGISTER_NUMBER";
|
|
|
|
public static final String VOICE_REQUESTED_ACTION = "org.thoughtcrime.securesms.RegistrationService.VOICE_REQUESTED";
|
|
|
|
public static final String VOICE_REGISTER_ACTION = "org.thoughtcrime.securesms.RegistrationService.VOICE_REGISTER";
|
|
|
|
|
2013-03-26 04:26:03 +00:00
|
|
|
public static final String NOTIFICATION_TITLE = "org.thoughtcrime.securesms.NOTIFICATION_TITLE";
|
|
|
|
public static final String NOTIFICATION_TEXT = "org.thoughtcrime.securesms.NOTIFICATION_TEXT";
|
|
|
|
public static final String CHALLENGE_EVENT = "org.thoughtcrime.securesms.CHALLENGE_EVENT";
|
|
|
|
public static final String REGISTRATION_EVENT = "org.thoughtcrime.securesms.REGISTRATION_EVENT";
|
|
|
|
public static final String GCM_REGISTRATION_EVENT = "org.thoughtcrime.securesms.GCM_REGISTRATION_EVENT";
|
|
|
|
|
|
|
|
public static final String CHALLENGE_EXTRA = "CAAChallenge";
|
|
|
|
public static final String GCM_REGISTRATION_ID = "GCMRegistrationId";
|
|
|
|
|
|
|
|
private static final long REGISTRATION_TIMEOUT_MILLIS = 120000;
|
2013-08-15 15:25:30 +00:00
|
|
|
private static final Object GENERATING_PREKEYS_SEMAPHOR = new Object();
|
2013-03-26 04:26:03 +00:00
|
|
|
|
|
|
|
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
|
|
|
private final Binder binder = new RegistrationServiceBinder();
|
|
|
|
|
|
|
|
private volatile RegistrationState registrationState = new RegistrationState(RegistrationState.STATE_IDLE);
|
|
|
|
|
|
|
|
private volatile Handler registrationStateHandler;
|
|
|
|
private volatile ChallengeReceiver challengeReceiver;
|
|
|
|
private volatile GcmRegistrationReceiver gcmRegistrationReceiver;
|
|
|
|
private String challenge;
|
|
|
|
private String gcmRegistrationId;
|
|
|
|
private long verificationStartTime;
|
2013-08-15 15:25:30 +00:00
|
|
|
private boolean generatingPreKeys;
|
2013-03-26 04:26:03 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public int onStartCommand(final Intent intent, int flags, int startId) {
|
2013-07-08 23:29:28 +00:00
|
|
|
if (intent != null) {
|
2013-03-26 04:26:03 +00:00
|
|
|
executor.execute(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2013-08-15 15:25:30 +00:00
|
|
|
if (intent.getAction().equals(REGISTER_NUMBER_ACTION)) handleSmsRegistrationIntent(intent);
|
2013-07-08 23:29:28 +00:00
|
|
|
else if (intent.getAction().equals(VOICE_REQUESTED_ACTION)) handleVoiceRequestedIntent(intent);
|
2013-08-15 15:25:30 +00:00
|
|
|
else if (intent.getAction().equals(VOICE_REGISTER_ACTION)) handleVoiceRegistrationIntent(intent);
|
2013-03-26 04:26:03 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return START_NOT_STICKY;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
|
|
|
executor.shutdown();
|
|
|
|
shutdown();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public IBinder onBind(Intent intent) {
|
|
|
|
return binder;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void shutdown() {
|
|
|
|
shutdownChallengeListener();
|
|
|
|
markAsVerifying(false);
|
|
|
|
registrationState = new RegistrationState(RegistrationState.STATE_IDLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized int getSecondsRemaining() {
|
|
|
|
long millisPassed;
|
|
|
|
|
|
|
|
if (verificationStartTime == 0) millisPassed = 0;
|
|
|
|
else millisPassed = System.currentTimeMillis() - verificationStartTime;
|
|
|
|
|
|
|
|
return Math.max((int)(REGISTRATION_TIMEOUT_MILLIS - millisPassed) / 1000, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public RegistrationState getRegistrationState() {
|
|
|
|
return registrationState;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void initializeChallengeListener() {
|
|
|
|
this.challenge = null;
|
|
|
|
challengeReceiver = new ChallengeReceiver();
|
|
|
|
IntentFilter filter = new IntentFilter(CHALLENGE_EVENT);
|
|
|
|
registerReceiver(challengeReceiver, filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void initializeGcmRegistrationListener() {
|
|
|
|
this.gcmRegistrationId = null;
|
|
|
|
gcmRegistrationReceiver = new GcmRegistrationReceiver();
|
|
|
|
IntentFilter filter = new IntentFilter(GCM_REGISTRATION_EVENT);
|
|
|
|
registerReceiver(gcmRegistrationReceiver, filter);
|
|
|
|
}
|
|
|
|
|
2013-08-15 15:25:30 +00:00
|
|
|
private void initializePreKeyGenerator(final MasterSecret masterSecret) {
|
|
|
|
synchronized (GENERATING_PREKEYS_SEMAPHOR) {
|
|
|
|
if (generatingPreKeys) return;
|
|
|
|
else generatingPreKeys = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
new Thread() {
|
|
|
|
public void run() {
|
|
|
|
if (PreKeyUtil.getPreKeys(RegistrationService.this, masterSecret).size() < PreKeyUtil.BATCH_SIZE) {
|
|
|
|
PreKeyUtil.generatePreKeys(RegistrationService.this, masterSecret);
|
|
|
|
}
|
|
|
|
|
|
|
|
synchronized (GENERATING_PREKEYS_SEMAPHOR) {
|
|
|
|
generatingPreKeys = false;
|
|
|
|
GENERATING_PREKEYS_SEMAPHOR.notifyAll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.start();
|
|
|
|
}
|
|
|
|
|
2013-04-01 02:16:06 +00:00
|
|
|
private synchronized void shutdownChallengeListener() {
|
2013-03-26 04:26:03 +00:00
|
|
|
if (challengeReceiver != null) {
|
|
|
|
unregisterReceiver(challengeReceiver);
|
|
|
|
challengeReceiver = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-01 02:16:06 +00:00
|
|
|
private synchronized void shutdownGcmRegistrationListener() {
|
2013-03-26 04:26:03 +00:00
|
|
|
if (gcmRegistrationReceiver != null) {
|
|
|
|
unregisterReceiver(gcmRegistrationReceiver);
|
|
|
|
gcmRegistrationReceiver = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-08 23:29:28 +00:00
|
|
|
private void handleVoiceRequestedIntent(Intent intent) {
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_VOICE_REQUESTED,
|
|
|
|
intent.getStringExtra("e164number"),
|
|
|
|
intent.getStringExtra("password")));
|
|
|
|
}
|
|
|
|
|
2013-08-15 15:25:30 +00:00
|
|
|
private void handleVoiceRegistrationIntent(Intent intent) {
|
2013-07-08 23:29:28 +00:00
|
|
|
markAsVerifying(true);
|
|
|
|
|
2013-08-15 15:25:30 +00:00
|
|
|
String number = intent.getStringExtra("e164number");
|
|
|
|
String password = intent.getStringExtra("password" );
|
|
|
|
MasterSecret masterSecret = intent.getParcelableExtra("master_secret");
|
2013-07-08 23:29:28 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
initializeGcmRegistrationListener();
|
2013-08-15 15:25:30 +00:00
|
|
|
initializePreKeyGenerator(masterSecret);
|
2013-07-08 23:29:28 +00:00
|
|
|
|
|
|
|
PushServiceSocket socket = new PushServiceSocket(this, number, password);
|
|
|
|
|
2013-08-15 15:25:30 +00:00
|
|
|
handleCommonRegistration(masterSecret, socket, number);
|
2013-07-08 23:29:28 +00:00
|
|
|
|
|
|
|
markAsVerified(number, password);
|
|
|
|
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_COMPLETE, number));
|
|
|
|
broadcastComplete(true);
|
|
|
|
} catch (UnsupportedOperationException uoe) {
|
|
|
|
Log.w("RegistrationService", uoe);
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_GCM_UNSUPPORTED, number));
|
|
|
|
broadcastComplete(false);
|
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w("RegistrationService", e);
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_NETWORK_ERROR, number));
|
|
|
|
broadcastComplete(false);
|
|
|
|
} catch (GcmRegistrationTimeoutException e) {
|
|
|
|
Log.w("RegistrationService", e);
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_GCM_TIMEOUT));
|
|
|
|
broadcastComplete(false);
|
|
|
|
} finally {
|
|
|
|
shutdownGcmRegistrationListener();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-15 15:25:30 +00:00
|
|
|
private void handleSmsRegistrationIntent(Intent intent) {
|
2013-03-26 04:26:03 +00:00
|
|
|
markAsVerifying(true);
|
|
|
|
|
2013-08-15 15:25:30 +00:00
|
|
|
String number = intent.getStringExtra("e164number");
|
|
|
|
MasterSecret masterSecret = intent.getParcelableExtra("master_secret");
|
2013-03-26 04:26:03 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
String password = Util.getSecret(18);
|
|
|
|
initializeChallengeListener();
|
|
|
|
initializeGcmRegistrationListener();
|
2013-08-15 15:25:30 +00:00
|
|
|
initializePreKeyGenerator(masterSecret);
|
2013-03-26 04:26:03 +00:00
|
|
|
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_CONNECTING, number));
|
2013-07-08 23:29:28 +00:00
|
|
|
PushServiceSocket socket = new PushServiceSocket(this, number, password);
|
|
|
|
socket.createAccount(false);
|
2013-03-26 04:26:03 +00:00
|
|
|
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_VERIFYING, number));
|
|
|
|
String challenge = waitForChallenge();
|
2013-07-08 23:29:28 +00:00
|
|
|
socket.verifyAccount(challenge);
|
2013-03-26 04:26:03 +00:00
|
|
|
|
2013-08-15 15:25:30 +00:00
|
|
|
handleCommonRegistration(masterSecret, socket, number);
|
2013-03-26 04:26:03 +00:00
|
|
|
markAsVerified(number, password);
|
|
|
|
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_COMPLETE, number));
|
|
|
|
broadcastComplete(true);
|
|
|
|
} catch (UnsupportedOperationException uoe) {
|
|
|
|
Log.w("RegistrationService", uoe);
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_GCM_UNSUPPORTED, number));
|
|
|
|
broadcastComplete(false);
|
|
|
|
} catch (AccountVerificationTimeoutException avte) {
|
|
|
|
Log.w("RegistrationService", avte);
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_TIMEOUT, number));
|
|
|
|
broadcastComplete(false);
|
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w("RegistrationService", e);
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_NETWORK_ERROR, number));
|
|
|
|
broadcastComplete(false);
|
|
|
|
} catch (GcmRegistrationTimeoutException e) {
|
|
|
|
Log.w("RegistrationService", e);
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_GCM_TIMEOUT));
|
|
|
|
broadcastComplete(false);
|
|
|
|
} finally {
|
|
|
|
shutdownChallengeListener();
|
|
|
|
shutdownGcmRegistrationListener();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-15 15:25:30 +00:00
|
|
|
private void handleCommonRegistration(MasterSecret masterSecret, PushServiceSocket socket, String number)
|
|
|
|
throws GcmRegistrationTimeoutException, IOException
|
|
|
|
{
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_GENERATING_KEYS, number));
|
2013-08-18 02:06:04 +00:00
|
|
|
IdentityKey identityKey = IdentityKeyUtil.getIdentityKey(this);
|
|
|
|
List<PreKeyRecord> records = waitForPreKeys(masterSecret);
|
|
|
|
socket.registerPreKeys(identityKey, records);
|
2013-08-15 15:25:30 +00:00
|
|
|
|
|
|
|
setState(new RegistrationState(RegistrationState.STATE_GCM_REGISTERING, number));
|
|
|
|
GCMRegistrar.register(this, GcmIntentService.GCM_SENDER_ID);
|
|
|
|
String gcmRegistrationId = waitForGcmRegistrationId();
|
|
|
|
|
|
|
|
socket.registerGcmId(gcmRegistrationId);
|
|
|
|
Pair<DirectoryDescriptor, File> directory = socket.retrieveDirectory();
|
|
|
|
NumberFilter.getInstance(this).update(directory.first, directory.second);
|
|
|
|
}
|
|
|
|
|
2013-03-26 04:26:03 +00:00
|
|
|
private synchronized String waitForChallenge() throws AccountVerificationTimeoutException {
|
|
|
|
this.verificationStartTime = System.currentTimeMillis();
|
|
|
|
|
|
|
|
if (this.challenge == null) {
|
|
|
|
try {
|
|
|
|
wait(REGISTRATION_TIMEOUT_MILLIS);
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
throw new IllegalArgumentException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.challenge == null)
|
|
|
|
throw new AccountVerificationTimeoutException();
|
|
|
|
|
|
|
|
return this.challenge;
|
|
|
|
}
|
|
|
|
|
|
|
|
private synchronized String waitForGcmRegistrationId() throws GcmRegistrationTimeoutException {
|
|
|
|
if (this.gcmRegistrationId == null) {
|
|
|
|
try {
|
|
|
|
wait(10 * 60 * 1000);
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
throw new IllegalArgumentException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.gcmRegistrationId == null)
|
|
|
|
throw new GcmRegistrationTimeoutException();
|
|
|
|
|
|
|
|
return this.gcmRegistrationId;
|
|
|
|
}
|
|
|
|
|
2013-08-15 15:25:30 +00:00
|
|
|
private List<PreKeyRecord> waitForPreKeys(MasterSecret masterSecret) {
|
|
|
|
synchronized (GENERATING_PREKEYS_SEMAPHOR) {
|
|
|
|
while (generatingPreKeys) {
|
|
|
|
try {
|
|
|
|
GENERATING_PREKEYS_SEMAPHOR.wait();
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
throw new AssertionError(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return PreKeyUtil.getPreKeys(this, masterSecret);
|
|
|
|
}
|
|
|
|
|
2013-03-26 04:26:03 +00:00
|
|
|
private synchronized void challengeReceived(String challenge) {
|
|
|
|
this.challenge = challenge;
|
|
|
|
notifyAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
private synchronized void gcmRegistrationReceived(String gcmRegistrationId) {
|
|
|
|
this.gcmRegistrationId = gcmRegistrationId;
|
|
|
|
notifyAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void markAsVerifying(boolean verifying) {
|
2013-07-11 21:58:40 +00:00
|
|
|
TextSecurePreferences.setVerifying(this, verifying);
|
2013-03-26 04:26:03 +00:00
|
|
|
|
2013-07-11 21:58:40 +00:00
|
|
|
if (verifying) {
|
|
|
|
TextSecurePreferences.setPushRegistered(this, false);
|
|
|
|
}
|
2013-03-26 04:26:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void markAsVerified(String number, String password) {
|
2013-07-11 21:58:40 +00:00
|
|
|
TextSecurePreferences.setVerifying(this, false);
|
|
|
|
TextSecurePreferences.setPushRegistered(this, true);
|
|
|
|
TextSecurePreferences.setLocalNumber(this, number);
|
|
|
|
TextSecurePreferences.setPushServerPassword(this, password);
|
2013-03-26 04:26:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void setState(RegistrationState state) {
|
|
|
|
this.registrationState = state;
|
|
|
|
|
|
|
|
if (registrationStateHandler != null) {
|
2013-07-08 23:29:28 +00:00
|
|
|
registrationStateHandler.obtainMessage(state.state, state).sendToTarget();
|
2013-03-26 04:26:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void broadcastComplete(boolean success) {
|
|
|
|
Intent intent = new Intent();
|
|
|
|
intent.setAction(REGISTRATION_EVENT);
|
|
|
|
|
|
|
|
if (success) {
|
2013-07-11 00:54:38 +00:00
|
|
|
intent.putExtra(NOTIFICATION_TITLE, getString(R.string.RegistrationService_registration_complete));
|
|
|
|
intent.putExtra(NOTIFICATION_TEXT, getString(R.string.RegistrationService_textsecure_registration_has_successfully_completed));
|
2013-03-26 04:26:03 +00:00
|
|
|
} else {
|
2013-07-11 00:54:38 +00:00
|
|
|
intent.putExtra(NOTIFICATION_TITLE, getString(R.string.RegistrationService_registration_error));
|
|
|
|
intent.putExtra(NOTIFICATION_TEXT, getString(R.string.RegistrationService_textsecure_registration_has_encountered_a_problem));
|
2013-03-26 04:26:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.sendOrderedBroadcast(intent, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setRegistrationStateHandler(Handler registrationStateHandler) {
|
|
|
|
this.registrationStateHandler = registrationStateHandler;
|
|
|
|
}
|
|
|
|
|
|
|
|
public class RegistrationServiceBinder extends Binder {
|
|
|
|
public RegistrationService getService() {
|
|
|
|
return RegistrationService.this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class GcmRegistrationReceiver extends BroadcastReceiver {
|
|
|
|
public void onReceive(Context context, Intent intent) {
|
|
|
|
Log.w("RegistrationService", "Got gcm registration broadcast...");
|
|
|
|
gcmRegistrationReceived(intent.getStringExtra(GCM_REGISTRATION_ID));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class ChallengeReceiver extends BroadcastReceiver {
|
|
|
|
@Override
|
|
|
|
public void onReceive(Context context, Intent intent) {
|
|
|
|
Log.w("RegistrationService", "Got a challenge broadcast...");
|
|
|
|
challengeReceived(intent.getStringExtra(CHALLENGE_EXTRA));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class RegistrationState {
|
|
|
|
|
2013-07-08 23:29:28 +00:00
|
|
|
public static final int STATE_IDLE = 0;
|
|
|
|
public static final int STATE_CONNECTING = 1;
|
|
|
|
public static final int STATE_VERIFYING = 2;
|
|
|
|
public static final int STATE_TIMER = 3;
|
|
|
|
public static final int STATE_COMPLETE = 4;
|
|
|
|
public static final int STATE_TIMEOUT = 5;
|
|
|
|
public static final int STATE_NETWORK_ERROR = 6;
|
2013-03-26 04:26:03 +00:00
|
|
|
|
2013-07-08 23:29:28 +00:00
|
|
|
public static final int STATE_GCM_UNSUPPORTED = 8;
|
|
|
|
public static final int STATE_GCM_REGISTERING = 9;
|
|
|
|
public static final int STATE_GCM_TIMEOUT = 10;
|
2013-03-26 04:26:03 +00:00
|
|
|
|
2013-07-08 23:29:28 +00:00
|
|
|
public static final int STATE_VOICE_REQUESTED = 12;
|
2013-08-15 15:25:30 +00:00
|
|
|
public static final int STATE_GENERATING_KEYS = 13;
|
2013-04-01 02:16:06 +00:00
|
|
|
|
2013-03-26 04:26:03 +00:00
|
|
|
public final int state;
|
|
|
|
public final String number;
|
2013-07-08 23:29:28 +00:00
|
|
|
public final String password;
|
2013-03-26 04:26:03 +00:00
|
|
|
|
|
|
|
public RegistrationState(int state) {
|
|
|
|
this(state, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public RegistrationState(int state, String number) {
|
2013-07-08 23:29:28 +00:00
|
|
|
this(state, number, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public RegistrationState(int state, String number, String password) {
|
|
|
|
this.state = state;
|
|
|
|
this.number = number;
|
|
|
|
this.password = password;
|
2013-03-26 04:26:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|