diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 17f78577a..755d5cc6a 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -30,6 +30,16 @@
android:logo="@drawable/logo"
android:label="@string/app_name" >
+
+
+
+
= EXPIRY_DATE) {
+ if(LOG.isLoggable(INFO)) LOG.info("Expired");
+ Intent i = new Intent(this, ExpiredActivity.class);
+ i.setFlags(FLAG_ACTIVITY_NO_ANIMATION);
+ startActivity(i);
+ finish();
+ } else if(databaseConfig.getEncryptionKey() == null) {
+ if(LOG.isLoggable(INFO)) LOG.info("No password");
+ Intent i = new Intent(this, PasswordActivity.class);
+ i.setFlags(FLAG_ACTIVITY_NO_ANIMATION);
+ startActivityForResult(i, PASSWORD_REQUEST_CODE);
+ } else {
+ startAndBindService();
+ }
+ }
+
+ @Override
+ public void onActivityResult(int request, int result, Intent data) {
+ if(request == PASSWORD_REQUEST_CODE) {
+ if(result == RESULT_OK) startAndBindService();
+ else finish();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unbindService();
+ }
+
+ protected void startAndBindService() {
+ startService(new Intent(BriarService.class.getName()));
+ bound = bindService(new Intent(BriarService.class.getName()),
+ serviceConnection, 0);
+ }
+
+ protected void unbindService() {
+ if(bound) unbindService(serviceConnection);
+ }
+
+ protected void quit() {
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ // Wait for the service to finish starting up
+ IBinder binder = serviceConnection.waitForBinder();
+ BriarService service = ((BriarBinder) binder).getService();
+ service.waitForStartup();
+ // Shut down the service and wait for it to shut down
+ if(LOG.isLoggable(INFO)) LOG.info("Shutting down service");
+ service.shutdown();
+ service.waitForShutdown();
+ } catch(InterruptedException e) {
+ if(LOG.isLoggable(INFO))
+ LOG.info("Interrupted while waiting for service");
+ }
+ // Finish the activity and kill the JVM
+ runOnUiThread(new Runnable() {
+ public void run() {
+ finish();
+ if(LOG.isLoggable(INFO)) LOG.info("Exiting");
+ System.exit(0);
+ }
+ });
+ }
+ }.start();
+ }
+}
diff --git a/briar-android/src/org/briarproject/android/BriarService.java b/briar-android/src/org/briarproject/android/BriarService.java
index 5b827bfd5..f84ab4247 100644
--- a/briar-android/src/org/briarproject/android/BriarService.java
+++ b/briar-android/src/org/briarproject/android/BriarService.java
@@ -19,8 +19,10 @@ import org.briarproject.api.db.DatabaseConfig;
import org.briarproject.api.lifecycle.LifecycleManager;
import roboguice.service.RoboService;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
@@ -29,7 +31,9 @@ import android.support.v4.app.NotificationCompat;
public class BriarService extends RoboService {
- private static final int NOTIFICATION_ID = 1;
+ private static final int ONGOING_NOTIFICATION_ID = 1;
+ private static final int FAILURE_NOTIFICATION_ID = 2;
+
private static final Logger LOG =
Logger.getLogger(BriarService.class.getName());
@@ -64,7 +68,7 @@ public class BriarService extends RoboService {
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
FLAG_ACTIVITY_SINGLE_TOP);
b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0));
- startForeground(NOTIFICATION_ID, b.build());
+ startForeground(ONGOING_NOTIFICATION_ID, b.build());
// Start the services in a background thread
new Thread() {
@Override
@@ -73,18 +77,23 @@ public class BriarService extends RoboService {
started = true;
} else {
if(LOG.isLoggable(INFO)) LOG.info("Startup failed");
- Intent i = new Intent(BriarService.this,
- HomeScreenActivity.class);
- i.setFlags(FLAG_ACTIVITY_NEW_TASK |
- FLAG_ACTIVITY_CLEAR_TOP);
- i.putExtra("briar.STARTUP_FAILED", true);
- startActivity(i);
+ showStartupFailureNotification();
stopSelf();
}
}
}.start();
}
+ private void showStartupFailureNotification() {
+ NotificationCompat.Builder b = new NotificationCompat.Builder(this);
+ b.setSmallIcon(android.R.drawable.stat_notify_error);
+ b.setContentTitle(getText(R.string.startup_failed_notification_title));
+ b.setContentText(getText(R.string.startup_failed_notification_text));
+ Object o = getSystemService(Context.NOTIFICATION_SERVICE);
+ NotificationManager nm = (NotificationManager) o;
+ nm.notify(FAILURE_NOTIFICATION_ID, b.build());
+ }
+
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(LOG.isLoggable(INFO)) LOG.info("Started");
diff --git a/briar-android/src/org/briarproject/android/ExpiredActivity.java b/briar-android/src/org/briarproject/android/ExpiredActivity.java
new file mode 100644
index 000000000..453775393
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/ExpiredActivity.java
@@ -0,0 +1,35 @@
+package org.briarproject.android;
+
+import static android.view.Gravity.CENTER;
+import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
+
+import org.briarproject.R;
+import org.briarproject.android.util.LayoutUtils;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class ExpiredActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle state) {
+ super.onCreate(state);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setLayoutParams(MATCH_MATCH);
+ layout.setGravity(CENTER);
+
+ int pad = LayoutUtils.getPadding(this);
+
+ TextView warning = new TextView(this);
+ warning.setGravity(CENTER);
+ warning.setTextSize(18);
+ warning.setPadding(pad, pad, pad, pad);
+ warning.setText(R.string.expiry_warning);
+ layout.addView(warning);
+
+ setContentView(layout);
+ }
+}
diff --git a/briar-android/src/org/briarproject/android/HomeScreenActivity.java b/briar-android/src/org/briarproject/android/HomeScreenActivity.java
index d8a16c696..c299c986a 100644
--- a/briar-android/src/org/briarproject/android/HomeScreenActivity.java
+++ b/briar-android/src/org/briarproject/android/HomeScreenActivity.java
@@ -1,19 +1,11 @@
package org.briarproject.android;
-import static android.text.InputType.TYPE_CLASS_TEXT;
-import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
import static android.view.Gravity.CENTER;
-import static android.view.Gravity.CENTER_HORIZONTAL;
-import static android.view.View.GONE;
-import static android.view.View.VISIBLE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
-import static android.widget.LinearLayout.VERTICAL;
import static android.widget.Toast.LENGTH_SHORT;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
-import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP;
import java.util.ArrayList;
import java.util.List;
@@ -23,70 +15,38 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import org.briarproject.R;
-import org.briarproject.android.BriarService.BriarBinder;
-import org.briarproject.android.BriarService.BriarServiceConnection;
import org.briarproject.android.contact.ContactListActivity;
import org.briarproject.android.groups.GroupListActivity;
-import org.briarproject.android.util.FixedVerticalSpace;
import org.briarproject.android.util.LayoutUtils;
import org.briarproject.api.LocalAuthor;
import org.briarproject.api.android.DatabaseUiExecutor;
import org.briarproject.api.android.ReferenceManager;
-import org.briarproject.api.crypto.CryptoComponent;
-import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.db.DatabaseComponent;
-import org.briarproject.api.db.DatabaseConfig;
import org.briarproject.api.db.DbException;
import org.briarproject.api.lifecycle.LifecycleManager;
-import org.briarproject.util.StringUtils;
-import roboguice.activity.RoboActivity;
-import android.app.NotificationManager;
-import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.os.Bundle;
-import android.os.IBinder;
-import android.support.v4.app.NotificationCompat;
-import android.text.Editable;
-import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
import android.widget.BaseAdapter;
import android.widget.Button;
-import android.widget.EditText;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
-public class HomeScreenActivity extends RoboActivity {
-
- // This build expires on 7 February 2014
- private static final long EXPIRY_DATE = 1391731200 * 1000L;
+public class HomeScreenActivity extends BriarActivity {
private static final Logger LOG =
Logger.getLogger(HomeScreenActivity.class.getName());
- private final BriarServiceConnection serviceConnection =
- new BriarServiceConnection();
-
@Inject private ReferenceManager referenceManager;
- @Inject private DatabaseConfig databaseConfig;
@Inject @DatabaseUiExecutor private Executor dbUiExecutor;
- @Inject @CryptoExecutor private Executor cryptoExecutor;
- private boolean bound = false;
- private TextView enterPassword = null;
- private Button continueButton = null;
- private ProgressBar progress = null;
// Fields that are accessed from background threads must be volatile
- @Inject private volatile CryptoComponent crypto;
@Inject private volatile DatabaseComponent db;
@Inject private volatile LifecycleManager lifecycleManager;
@@ -95,17 +55,11 @@ public class HomeScreenActivity extends RoboActivity {
super.onCreate(state);
if(LOG.isLoggable(INFO)) LOG.info("Created");
Intent i = getIntent();
- boolean failed = i.getBooleanExtra("briar.STARTUP_FAILED", false);
long handle = i.getLongExtra("briar.LOCAL_AUTHOR_HANDLE", -1);
- if(failed) {
- // LifecycleManager failed to start all necessary services
- showStartupFailureNotification();
- finish();
- if(LOG.isLoggable(INFO)) LOG.info("Exiting");
- System.exit(0);
- } else if(System.currentTimeMillis() >= EXPIRY_DATE) {
- showExpiryWarning();
- } else if(handle != -1) {
+ if(handle == -1) {
+ // The activity has been launched before
+ showButtons();
+ } else {
// The activity was launched from the setup wizard
LocalAuthor a = referenceManager.removeReference(handle,
LocalAuthor.class);
@@ -117,219 +71,9 @@ public class HomeScreenActivity extends RoboActivity {
showSpinner();
storeLocalAuthor(a);
}
- startService(new Intent(BriarService.class.getName()));
- bindService();
- } else if(databaseConfig.getEncryptionKey() == null) {
- // The activity was launched from the splash screen
- showPasswordPrompt();
- } else {
- // The activity has been launched before
- showButtons();
- bindService();
}
}
- private void showStartupFailureNotification() {
- NotificationCompat.Builder b = new NotificationCompat.Builder(this);
- b.setSmallIcon(android.R.drawable.stat_notify_error);
- b.setContentTitle(getText(R.string.startup_failed_notification_title));
- b.setContentText(getText(R.string.startup_failed_notification_text));
- Object o = getSystemService(Context.NOTIFICATION_SERVICE);
- NotificationManager nm = (NotificationManager) o;
- nm.notify(0, b.build());
- }
-
- private void showSpinner() {
- LinearLayout layout = new LinearLayout(this);
- layout.setLayoutParams(MATCH_MATCH);
- layout.setGravity(CENTER);
-
- ProgressBar progress = new ProgressBar(this);
- progress.setIndeterminate(true);
- layout.addView(progress);
-
- setContentView(layout);
- }
-
- private void bindService() {
- bound = bindService(new Intent(BriarService.class.getName()),
- serviceConnection, 0);
- }
-
- private void quit() {
- new Thread() {
- @Override
- public void run() {
- try {
- // Wait for the service to finish starting up
- IBinder binder = serviceConnection.waitForBinder();
- BriarService service = ((BriarBinder) binder).getService();
- service.waitForStartup();
- // Shut down the service and wait for it to shut down
- if(LOG.isLoggable(INFO)) LOG.info("Shutting down service");
- service.shutdown();
- service.waitForShutdown();
- } catch(InterruptedException e) {
- if(LOG.isLoggable(INFO))
- LOG.info("Interrupted while waiting for service");
- }
- // Finish the activity and kill the JVM
- runOnUiThread(new Runnable() {
- public void run() {
- finish();
- if(LOG.isLoggable(INFO)) LOG.info("Exiting");
- System.exit(0);
- }
- });
- }
- }.start();
- }
-
- private void storeLocalAuthor(final LocalAuthor a) {
- dbUiExecutor.execute(new Runnable() {
- public void run() {
- try {
- lifecycleManager.waitForDatabase();
- long now = System.currentTimeMillis();
- db.addLocalAuthor(a);
- long duration = System.currentTimeMillis() - now;
- if(LOG.isLoggable(INFO))
- LOG.info("Storing author took " + duration + " ms");
- runOnUiThread(new Runnable() {
- public void run() {
- showButtons();
- }
- });
- } catch(DbException e) {
- if(LOG.isLoggable(WARNING))
- LOG.log(WARNING, e.toString(), e);
- } catch(InterruptedException e) {
- if(LOG.isLoggable(INFO))
- LOG.info("Interrupted while waiting for database");
- Thread.currentThread().interrupt();
- }
- }
- });
- }
-
- private void showPasswordPrompt() {
- SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE);
- String hex = prefs.getString("key", null);
- if(hex == null) throw new IllegalStateException();
- final byte[] encrypted = StringUtils.fromHexString(hex);
-
- LinearLayout layout = new LinearLayout(this);
- layout.setLayoutParams(MATCH_MATCH);
- layout.setOrientation(VERTICAL);
- layout.setGravity(CENTER_HORIZONTAL);
-
- int pad = LayoutUtils.getPadding(this);
-
- enterPassword = new TextView(this);
- enterPassword.setGravity(CENTER);
- enterPassword.setTextSize(18);
- enterPassword.setPadding(pad, pad, pad, 0);
- enterPassword.setText(R.string.enter_password);
- layout.addView(enterPassword);
-
- final EditText passwordEntry = new EditText(this);
- passwordEntry.setId(1);
- passwordEntry.setMaxLines(1);
- int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
- passwordEntry.setInputType(inputType);
- passwordEntry.setOnEditorActionListener(new OnEditorActionListener() {
- public boolean onEditorAction(TextView v, int action, KeyEvent e) {
- validatePassword(encrypted, passwordEntry.getText());
- return true;
- }
- });
- layout.addView(passwordEntry);
-
- // Adjusting the padding of buttons and EditTexts has the wrong results
- layout.addView(new FixedVerticalSpace(this));
-
- continueButton = new Button(this);
- continueButton.setLayoutParams(WRAP_WRAP);
- continueButton.setText(R.string.continue_button);
- continueButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- validatePassword(encrypted, passwordEntry.getText());
- }
- });
- layout.addView(continueButton);
-
- progress = new ProgressBar(this);
- progress.setLayoutParams(WRAP_WRAP);
- progress.setIndeterminate(true);
- progress.setVisibility(GONE);
- layout.addView(progress);
- setContentView(layout);
- }
-
- private void validatePassword(final byte[] encrypted, Editable e) {
- if(enterPassword == null || continueButton == null || progress == null)
- return;
- // Hide the soft keyboard
- Object o = getSystemService(INPUT_METHOD_SERVICE);
- ((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
- // Replace the button with a progress bar
- continueButton.setVisibility(GONE);
- progress.setVisibility(VISIBLE);
- // Decrypt the database key in a background thread
- int length = e.length();
- final char[] password = new char[length];
- e.getChars(0, length, password, 0);
- e.delete(0, length);
- cryptoExecutor.execute(new Runnable() {
- public void run() {
- byte[] key = crypto.decryptWithPassword(encrypted, password);
- if(key == null) {
- tryAgain();
- } else {
- databaseConfig.setEncryptionKey(key);
- showButtonsAndStartService();
- }
- }
- });
- }
-
- private void tryAgain() {
- runOnUiThread(new Runnable() {
- public void run() {
- enterPassword.setText(R.string.try_again);
- continueButton.setVisibility(VISIBLE);
- progress.setVisibility(GONE);
- }
- });
- }
-
- private void showButtonsAndStartService() {
- runOnUiThread(new Runnable() {
- public void run() {
- showButtons();
- startService(new Intent(BriarService.class.getName()));
- bindService();
- }
- });
- }
-
- private void showExpiryWarning() {
- LinearLayout layout = new LinearLayout(this);
- layout.setLayoutParams(MATCH_MATCH);
- layout.setGravity(CENTER);
-
- int pad = LayoutUtils.getPadding(this);
-
- TextView warning = new TextView(this);
- warning.setGravity(CENTER);
- warning.setTextSize(18);
- warning.setPadding(pad, pad, pad, pad);
- warning.setText(R.string.expiry_warning);
- layout.addView(warning);
-
- setContentView(layout);
- }
-
private void showButtons() {
ListView.LayoutParams matchMatch =
new ListView.LayoutParams(MATCH_PARENT, MATCH_PARENT);
@@ -423,9 +167,42 @@ public class HomeScreenActivity extends RoboActivity {
setContentView(grid);
}
- @Override
- public void onDestroy() {
- super.onDestroy();
- if(bound) unbindService(serviceConnection);
+ private void showSpinner() {
+ LinearLayout layout = new LinearLayout(this);
+ layout.setLayoutParams(MATCH_MATCH);
+ layout.setGravity(CENTER);
+
+ ProgressBar progress = new ProgressBar(this);
+ progress.setIndeterminate(true);
+ layout.addView(progress);
+
+ setContentView(layout);
+ }
+
+ private void storeLocalAuthor(final LocalAuthor a) {
+ dbUiExecutor.execute(new Runnable() {
+ public void run() {
+ try {
+ lifecycleManager.waitForDatabase();
+ long now = System.currentTimeMillis();
+ db.addLocalAuthor(a);
+ long duration = System.currentTimeMillis() - now;
+ if(LOG.isLoggable(INFO))
+ LOG.info("Storing author took " + duration + " ms");
+ runOnUiThread(new Runnable() {
+ public void run() {
+ showButtons();
+ }
+ });
+ } catch(DbException e) {
+ if(LOG.isLoggable(WARNING))
+ LOG.log(WARNING, e.toString(), e);
+ } catch(InterruptedException e) {
+ if(LOG.isLoggable(INFO))
+ LOG.info("Interrupted while waiting for database");
+ Thread.currentThread().interrupt();
+ }
+ }
+ });
}
}
diff --git a/briar-android/src/org/briarproject/android/PasswordActivity.java b/briar-android/src/org/briarproject/android/PasswordActivity.java
new file mode 100644
index 000000000..485cc19cd
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/PasswordActivity.java
@@ -0,0 +1,154 @@
+package org.briarproject.android;
+
+import static android.text.InputType.TYPE_CLASS_TEXT;
+import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
+import static android.view.Gravity.CENTER;
+import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
+import static android.widget.LinearLayout.VERTICAL;
+import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
+import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+import org.briarproject.R;
+import org.briarproject.android.util.FixedVerticalSpace;
+import org.briarproject.android.util.LayoutUtils;
+import org.briarproject.api.crypto.CryptoComponent;
+import org.briarproject.api.crypto.CryptoExecutor;
+import org.briarproject.api.db.DatabaseConfig;
+import org.briarproject.util.StringUtils;
+
+import roboguice.activity.RoboActivity;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.text.Editable;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+public class PasswordActivity extends RoboActivity {
+
+ @Inject private DatabaseConfig databaseConfig;
+ @Inject @CryptoExecutor private Executor cryptoExecutor;
+ private TextView enterPassword = null;
+ private Button continueButton = null;
+ private ProgressBar progress = null;
+
+ // Fields that are accessed from background threads must be volatile
+ @Inject private volatile CryptoComponent crypto;
+
+ @Override
+ public void onCreate(Bundle state) {
+ super.onCreate(state);
+
+ SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE);
+ String hex = prefs.getString("key", null);
+ if(hex == null) throw new IllegalStateException();
+ final byte[] encrypted = StringUtils.fromHexString(hex);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setLayoutParams(MATCH_MATCH);
+ layout.setOrientation(VERTICAL);
+ layout.setGravity(CENTER_HORIZONTAL);
+
+ int pad = LayoutUtils.getPadding(this);
+
+ enterPassword = new TextView(this);
+ enterPassword.setGravity(CENTER);
+ enterPassword.setTextSize(18);
+ enterPassword.setPadding(pad, pad, pad, 0);
+ enterPassword.setText(R.string.enter_password);
+ layout.addView(enterPassword);
+
+ final EditText passwordEntry = new EditText(this);
+ passwordEntry.setId(1);
+ passwordEntry.setMaxLines(1);
+ int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
+ passwordEntry.setInputType(inputType);
+ passwordEntry.setOnEditorActionListener(new OnEditorActionListener() {
+ public boolean onEditorAction(TextView v, int action, KeyEvent e) {
+ validatePassword(encrypted, passwordEntry.getText());
+ return true;
+ }
+ });
+ layout.addView(passwordEntry);
+
+ // Adjusting the padding of buttons and EditTexts has the wrong results
+ layout.addView(new FixedVerticalSpace(this));
+
+ continueButton = new Button(this);
+ continueButton.setLayoutParams(WRAP_WRAP);
+ continueButton.setText(R.string.continue_button);
+ continueButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ validatePassword(encrypted, passwordEntry.getText());
+ }
+ });
+ layout.addView(continueButton);
+
+ progress = new ProgressBar(this);
+ progress.setLayoutParams(WRAP_WRAP);
+ progress.setIndeterminate(true);
+ progress.setVisibility(GONE);
+ layout.addView(progress);
+ setContentView(layout);
+ }
+
+ private void validatePassword(final byte[] encrypted, Editable e) {
+ if(enterPassword == null || continueButton == null || progress == null)
+ return;
+ // Hide the soft keyboard
+ Object o = getSystemService(INPUT_METHOD_SERVICE);
+ ((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
+ // Replace the button with a progress bar
+ continueButton.setVisibility(GONE);
+ progress.setVisibility(VISIBLE);
+ // Decrypt the database key in a background thread
+ int length = e.length();
+ final char[] password = new char[length];
+ e.getChars(0, length, password, 0);
+ e.delete(0, length);
+ cryptoExecutor.execute(new Runnable() {
+ public void run() {
+ byte[] key = crypto.decryptWithPassword(encrypted, password);
+ if(key == null) {
+ tryAgain();
+ } else {
+ databaseConfig.setEncryptionKey(key);
+ returnOk();
+ }
+ }
+ });
+ }
+
+ private void tryAgain() {
+ runOnUiThread(new Runnable() {
+ public void run() {
+ enterPassword.setText(R.string.try_again);
+ continueButton.setVisibility(VISIBLE);
+ progress.setVisibility(GONE);
+ }
+ });
+ }
+
+ private void returnOk() {
+ runOnUiThread(new Runnable() {
+ public void run() {
+ setResult(RESULT_OK);
+ finish();
+ }
+ });
+ }
+}