diff --git a/briar-android/res/layout/activity_password.xml b/briar-android/res/layout/activity_password.xml new file mode 100644 index 0000000000000000000000000000000000000000..5a306a79cf1e8fc7d67f3f9d3cf315f83a999f11 --- /dev/null +++ b/briar-android/res/layout/activity_password.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingBottom="@dimen/margin_activity_vertical" + android:paddingEnd="@dimen/margin_activity_horizontal" + android:paddingStart="@dimen/margin_activity_horizontal" + android:paddingTop="@dimen/margin_activity_vertical"> + + <TextView + android:id="@+id/title_password" + style="@style/BriarTextTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:padding="@dimen/margin_large" + android:text="@string/enter_password" /> + + <EditText + android:id="@+id/edit_password" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/title_password" + android:hint="@string/password_hint" + android:imeOptions="actionDone" + android:inputType="textPassword" + android:lines="1" + android:maxLines="1" /> + + <Button + android:id="@+id/btn_sign_in" + style="@style/BriarButton.Default" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/edit_password" + android:layout_marginTop="@dimen/margin_xlarge" + android:onClick="onSignInClick" + android:text="@string/sign_in_button" /> + + <ProgressBar + android:id="@+id/progress_wheel" + style="?android:attr/progressBarStyleInverse" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignTop="@id/btn_sign_in" + android:visibility="invisible" /> + + <TextView + style="@style/BriarTextBody" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/btn_sign_in" + android:layout_centerHorizontal="true" + android:layout_marginTop="@dimen/margin_large" + android:clickable="true" + android:onClick="onForgottenPasswordClick" + android:text="@string/forgotten_password" + android:textColor="?android:attr/textColorLink" /> + +</RelativeLayout> \ No newline at end of file diff --git a/briar-android/res/values-v14/styles.xml b/briar-android/res/values-v14/styles.xml index 9fd201d23c101e862855c8b11aa02588276603a1..c1fc08f072d372b00cab63c2724370d4671ef3fc 100644 --- a/briar-android/res/values-v14/styles.xml +++ b/briar-android/res/values-v14/styles.xml @@ -9,4 +9,9 @@ <item name="android:textColor">@color/action_bar_text</item> <item name="android:background">@color/action_bar_background</item> </style> + + <style name="BriarButton.Default"> + <item name="android:textAllCaps">true</item> + </style> + </resources> \ No newline at end of file diff --git a/briar-android/res/values/color.xml b/briar-android/res/values/color.xml index 00b5d2412b0ae23a6aafb492a0935dcc6e1811fc..18e88d64c8bdc0a9de6a0259c71600308856f34b 100644 --- a/briar-android/res/values/color.xml +++ b/briar-android/res/values/color.xml @@ -14,4 +14,6 @@ <color name="no_posts">#AAAAAA</color> <color name="settings_title_text">#2D3E50</color> <color name="settings_title_underline">#2D3E50</color> + + <color name="text_link">#2D3E50</color> </resources> \ No newline at end of file diff --git a/briar-android/res/values/dimens.xml b/briar-android/res/values/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..35c316f1216ce179e2cc4f1c6120e04fda42d7b4 --- /dev/null +++ b/briar-android/res/values/dimens.xml @@ -0,0 +1,21 @@ +<resources> + + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="margin_activity_horizontal">16dp</dimen> + <dimen name="margin_activity_vertical">16dp</dimen> + + <dimen name="margin_seperator">1dp</dimen> + <dimen name="margin_tiny">2dp</dimen> + <dimen name="margin_small">4dp</dimen> + <dimen name="margin_medium">8dp</dimen> + <dimen name="margin_large">16dp</dimen> + <dimen name="margin_xlarge">32dp</dimen> + + <!-- v2 dimens --> + <dimen name="text_size_tiny">12sp</dimen> + <dimen name="text_size_small">14sp</dimen> + <dimen name="text_size_medium">16sp</dimen> + <dimen name="text_size_large">20sp</dimen> + <dimen name="text_size_xlarge">34sp</dimen> + +</resources> diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index d429004d6fda1ab03b661bf7524c71347607384c..f14644bd5e08cdf82f9e16ad609d63195b91e187 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -1,5 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <resources> + + <string name="app_name">Briar</string> <string name="crash_report_title">Briar Crash Report</string> <string name="ongoing_notification_title">Signed into Briar</string> @@ -13,6 +15,8 @@ <string name="passwords_do_not_match">Passwords do not match</string> <string name="create_account_button">Create Account</string> <string name="enter_password">Enter your password:</string> + <string name="password_hint">Password</string> + <string name="forgotten_password">I have forgotten my password</string> <string name="try_again">Wrong password, try again:</string> <string name="sign_in_button">Sign In</string> <string name="startup_failed_notification_title">Briar could not start</string> diff --git a/briar-android/res/values/styles.xml b/briar-android/res/values/styles.xml index 79b84d8b72935e8915f2aecacfcf60ca791c4ed3..4c59289224e3ce9f970a34d2881a585bde2329c2 100644 --- a/briar-android/res/values/styles.xml +++ b/briar-android/res/values/styles.xml @@ -12,4 +12,21 @@ <style name="WindowTitleBackground"> <item name="android:background">@color/action_bar_background</item> </style> + + <style name="BriarButton"> + <item name="android:textSize">@dimen/text_size_medium</item> + <item name="android:padding">@dimen/margin_large</item> + </style> + + <style name="BriarButton.Default"/> + + <style name="BriarTextTitle"> + <item name="android:textSize">@dimen/text_size_medium</item> + <item name="android:textColor">@android:color/primary_text_light</item> + </style> + + <style name="BriarTextBody"> + <item name="android:textSize">@dimen/text_size_small</item> + <item name="android:textColor">@android:color/primary_text_light</item> + </style> </resources> \ No newline at end of file diff --git a/briar-android/src/org/briarproject/android/BaseActivity.java b/briar-android/src/org/briarproject/android/BaseActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..61efc68bd7eac2d43f6d83b9133154e8fce45c6f --- /dev/null +++ b/briar-android/src/org/briarproject/android/BaseActivity.java @@ -0,0 +1,56 @@ +package org.briarproject.android; + +import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY; +import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.inputmethod.InputMethodManager; + +import roboguice.activity.RoboActivity; + +public abstract class BaseActivity extends RoboActivity { + + private final static String PREFS_DB = "db"; + private final static String KEY_DB_KEY = "key"; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE); + } + + private SharedPreferences getBriarPrefs(String prefsName) { + return getSharedPreferences(prefsName, MODE_PRIVATE); + } + + protected String getDbKeyInHex() { + return getBriarPrefs(PREFS_DB).getString(KEY_DB_KEY, null); + } + + private void clearPrefs(String prefsName) { + SharedPreferences.Editor editor = getBriarPrefs(prefsName).edit(); + editor.clear(); + editor.apply(); + } + + protected void clearDbPrefs() { + this.clearPrefs(PREFS_DB); + } + + protected void gotoAndFinish(Class classInstance, int resultCode) { + if (resultCode != Integer.MIN_VALUE) + this.setResult(resultCode); + this.startActivity(new Intent(this, classInstance)); + this.finish(); + } + + protected void hideSoftKeyboard() + { + Object o = getSystemService(INPUT_METHOD_SERVICE); + ((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0); + } +} diff --git a/briar-android/src/org/briarproject/android/BriarActivity.java b/briar-android/src/org/briarproject/android/BriarActivity.java index e098bfee7bb4ca785bd9304e0181d2d0160926df..49a02591469dc86a82f5cbd8ce8d393f88396027 100644 --- a/briar-android/src/org/briarproject/android/BriarActivity.java +++ b/briar-android/src/org/briarproject/android/BriarActivity.java @@ -25,7 +25,7 @@ import android.os.IBinder; import android.view.inputmethod.InputMethodManager; @SuppressLint("Registered") -public class BriarActivity extends RoboActivity { +public class BriarActivity extends BaseActivity { public static final int REQUEST_PASSWORD = 1; @@ -45,7 +45,6 @@ public class BriarActivity extends RoboActivity { @Override public void onCreate(Bundle state) { super.onCreate(state); - if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE); if (databaseConfig.getEncryptionKey() != null) startAndBindService(); } diff --git a/briar-android/src/org/briarproject/android/PasswordActivity.java b/briar-android/src/org/briarproject/android/PasswordActivity.java index c3437852da16ad52cb4f3ed07df8ae70c5910551..497e2eb830a2f7d789159f1076d58399b74b503b 100644 --- a/briar-android/src/org/briarproject/android/PasswordActivity.java +++ b/briar-android/src/org/briarproject/android/PasswordActivity.java @@ -1,17 +1,7 @@ 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.WindowManager.LayoutParams.FLAG_SECURE; -import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY; -import static android.widget.LinearLayout.VERTICAL; -import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS; -import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH; -import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP; import java.io.File; import java.util.concurrent.Executor; @@ -19,37 +9,32 @@ 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.crypto.SecretKey; import org.briarproject.api.db.DatabaseConfig; import org.briarproject.util.StringUtils; -import roboguice.activity.RoboActivity; -import android.content.Intent; -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.view.inputmethod.EditorInfo; 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 { +public class PasswordActivity extends BaseActivity { @Inject @CryptoExecutor private Executor cryptoExecutor; - private TextView enterPassword = null; - private EditText passwordEntry = null; - private Button signInButton = null; - private ProgressBar progress = null; + private Button mSignInButton; + private ProgressBar mProgress; + private TextView mTitle; + private EditText mPassword; + + private byte[] encrypted; // Fields that are accessed from background threads must be volatile @Inject private volatile CryptoComponent crypto; @@ -59,66 +44,42 @@ public class PasswordActivity extends RoboActivity { public void onCreate(Bundle state) { super.onCreate(state); - if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE); - - SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE); - String hex = prefs.getString("key", null); + String hex = this.getDbKeyInHex(); if (hex == null || !databaseConfig.databaseExists()) { - // Storage has been deleted - clean up and return to setup - prefs.edit().clear().commit(); - delete(databaseConfig.getDatabaseDirectory()); - setResult(RESULT_CANCELED); - startActivity(new Intent(this, SetupActivity.class)); - finish(); + this.clearDbPrefs(); return; } - 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); - layout.setPadding(pad, pad, pad, pad); - - enterPassword = new TextView(this); - enterPassword.setGravity(CENTER); - enterPassword.setTextSize(18); - enterPassword.setText(R.string.enter_password); - layout.addView(enterPassword); - - 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; + this.encrypted = StringUtils.fromHexString(hex); + + this.setContentView(R.layout.activity_password); + this.mSignInButton = (Button)findViewById(R.id.btn_sign_in); + this.mProgress = (ProgressBar)findViewById(R.id.progress_wheel); + this.mTitle = (TextView)findViewById(R.id.title_password); + this.mPassword = (EditText)findViewById(R.id.edit_password); + this.mPassword.setOnEditorActionListener(new OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_DONE) { + validatePassword(encrypted, PasswordActivity.this.mPassword.getText()); + } + return false; } }); - layout.addView(passwordEntry); + } + + @Override + protected void clearDbPrefs() { + super.clearDbPrefs(); + this.delete(databaseConfig.getDatabaseDirectory()); + this.gotoAndFinish(SetupActivity.class, RESULT_CANCELED); + } - // Adjusting the padding of buttons and EditTexts has the wrong results - layout.addView(new FixedVerticalSpace(this)); + public void onSignInClick(View v) { + this.validatePassword(this.encrypted, this.mPassword.getText()); + } - signInButton = new Button(this); - signInButton.setLayoutParams(WRAP_WRAP); - signInButton.setText(R.string.sign_in_button); - signInButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - validatePassword(encrypted, passwordEntry.getText()); - } - }); - layout.addView(signInButton); - - progress = new ProgressBar(this); - progress.setLayoutParams(WRAP_WRAP); - progress.setIndeterminate(true); - progress.setVisibility(GONE); - layout.addView(progress); - setContentView(layout); + public void onForgottenPasswordClick(View v) { + this.clearDbPrefs(); } private void delete(File f) { @@ -127,13 +88,10 @@ public class PasswordActivity extends RoboActivity { } private void validatePassword(final byte[] encrypted, Editable e) { - if (progress == null) return; // Not created yet - // Hide the soft keyboard - Object o = getSystemService(INPUT_METHOD_SERVICE); - ((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0); + this.hideSoftKeyboard(); // Replace the button with a progress bar - signInButton.setVisibility(GONE); - progress.setVisibility(VISIBLE); + this.mSignInButton.setVisibility(View.INVISIBLE); + this.mProgress.setVisibility(VISIBLE); // Decrypt the database key in a background thread final String password = e.toString(); cryptoExecutor.execute(new Runnable() { @@ -152,10 +110,9 @@ public class PasswordActivity extends RoboActivity { private void tryAgain() { runOnUiThread(new Runnable() { public void run() { - enterPassword.setText(R.string.try_again); - passwordEntry.setText(""); - signInButton.setVisibility(VISIBLE); - progress.setVisibility(GONE); + PasswordActivity.this.mTitle.setText(R.string.try_again); + PasswordActivity.this.mSignInButton.setVisibility(VISIBLE); + PasswordActivity.this.mProgress.setVisibility(GONE); } }); }