From 8d850b290cceed25cb195c4b0a9c232701087c8a Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Wed, 5 Feb 2014 14:30:13 +0000 Subject: [PATCH] Refactored HomeScreenActivity into several smaller classes. --- briar-android/AndroidManifest.xml | 10 + .../briarproject/android/BriarActivity.java | 106 ++++++ .../briarproject/android/BriarService.java | 25 +- .../briarproject/android/ExpiredActivity.java | 35 ++ .../android/HomeScreenActivity.java | 307 +++--------------- .../android/PasswordActivity.java | 154 +++++++++ 6 files changed, 364 insertions(+), 273 deletions(-) create mode 100644 briar-android/src/org/briarproject/android/BriarActivity.java create mode 100644 briar-android/src/org/briarproject/android/ExpiredActivity.java create mode 100644 briar-android/src/org/briarproject/android/PasswordActivity.java diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml index 17f78577a7..755d5cc6a2 100644 --- a/briar-android/AndroidManifest.xml +++ b/briar-android/AndroidManifest.xml @@ -30,6 +30,16 @@ android:logo="@drawable/logo" android:label="@string/app_name" > </activity> + <activity + android:name=".android.ExpiredActivity" + android:logo="@drawable/logo" + android:label="@string/app_name" > + </activity> + <activity + android:name=".android.PasswordActivity" + android:logo="@drawable/logo" + android:label="@string/app_name" > + </activity> <activity android:name=".android.SetupActivity" android:logo="@drawable/logo" diff --git a/briar-android/src/org/briarproject/android/BriarActivity.java b/briar-android/src/org/briarproject/android/BriarActivity.java new file mode 100644 index 0000000000..583269766a --- /dev/null +++ b/briar-android/src/org/briarproject/android/BriarActivity.java @@ -0,0 +1,106 @@ +package org.briarproject.android; + +import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; +import static java.util.logging.Level.INFO; + +import java.util.logging.Logger; + +import javax.inject.Inject; + +import org.briarproject.android.BriarService.BriarBinder; +import org.briarproject.android.BriarService.BriarServiceConnection; +import org.briarproject.api.db.DatabaseConfig; + +import roboguice.activity.RoboFragmentActivity; +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; + +public class BriarActivity extends RoboFragmentActivity { + + // This build expires on 7 February 2014 + private static final long EXPIRY_DATE = 1391731200 * 1000L; + private static final int PASSWORD_REQUEST_CODE = 1; + + private static final Logger LOG = + Logger.getLogger(BriarActivity.class.getName()); + + private final BriarServiceConnection serviceConnection = + new BriarServiceConnection(); + + @Inject private DatabaseConfig databaseConfig; + private boolean bound = false; + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + if(LOG.isLoggable(INFO)) LOG.info("Created"); + if(System.currentTimeMillis() >= 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 5b827bfd5a..f84ab42477 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 0000000000..453775393d --- /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 d8a16c6961..c299c986a7 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 0000000000..485cc19cd3 --- /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(); + } + }); + } +} -- GitLab