diff --git a/briar-android/build.gradle b/briar-android/build.gradle index 8e043ff7f8f0fe72b9316f49b9bf33005e86b220..756b2da587dbdff195733d15cbb150513597e413 100644 --- a/briar-android/build.gradle +++ b/briar-android/build.gradle @@ -6,8 +6,9 @@ dependencies { compile fileTree(dir: '../briar-core/libs', include: '*.jar') compile project(':briar-core') compile fileTree(dir: 'libs', include: '*.jar') - compile 'com.android.support:design:23.1.1' - compile 'com.android.support:recyclerview-v7:23.1.1' + compile "com.android.support:support-v4:23.1.1" + compile "com.android.support:appcompat-v7:23.1.1" + compile "com.android.support:design:23.1.1" } android { diff --git a/briar-android/res/layout/activity_password.xml b/briar-android/res/layout/activity_password.xml index fc633e841addd3448da5b3be0ff69b8ad714d806..dff9612aad563a5cf197bf76ae9a8cd18ac9565a 100644 --- a/briar-android/res/layout/activity_password.xml +++ b/briar-android/res/layout/activity_password.xml @@ -27,7 +27,6 @@ android:hint="@string/password_hint" android:imeOptions="actionDone" android:inputType="textPassword" - android:lines="1" android:maxLines="1" /> <Button diff --git a/briar-android/res/layout/activity_setup.xml b/briar-android/res/layout/activity_setup.xml new file mode 100644 index 0000000000000000000000000000000000000000..d5ec69ba6828ffcc77f2c5a7d0a309e364300743 --- /dev/null +++ b/briar-android/res/layout/activity_setup.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="vertical" + android:paddingBottom="@dimen/margin_activity_vertical" + android:paddingEnd="@dimen/margin_activity_horizontal" + android:paddingLeft="@dimen/margin_activity_horizontal" + android:paddingRight="@dimen/margin_activity_horizontal" + android:paddingStart="@dimen/margin_activity_horizontal" + android:paddingTop="@dimen/margin_activity_vertical"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:text="@string/choose_nickname" + android:textSize="@dimen/text_size_medium"/> + + <android.support.design.widget.TextInputLayout + android:id="@+id/nickname_entry_wrapper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:errorEnabled="true"> + + <EditText + android:id="@+id/nickname_entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="text|textCapWords" + android:maxLines="1"/> + </android.support.design.widget.TextInputLayout> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:text="@string/choose_password" + android:textSize="@dimen/text_size_medium"/> + + <android.support.design.widget.TextInputLayout + android:id="@+id/password_entry_wrapper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:errorEnabled="true"> + + <EditText + android:id="@+id/password_entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="textPassword" + android:maxLines="1"/> + </android.support.design.widget.TextInputLayout> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:text="@string/confirm_password" + android:textSize="@dimen/text_size_medium"/> + + <android.support.design.widget.TextInputLayout + android:id="@+id/password_confirm_wrapper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:errorEnabled="true"> + + <EditText + android:id="@+id/password_confirm" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="textPassword" + android:imeOptions="actionDone" + android:maxLines="1"/> + </android.support.design.widget.TextInputLayout> + + <org.briarproject.android.util.StrengthMeter + android:id="@+id/strength_meter" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="invisible"/> + + <Button + android:id="@+id/create_account" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:enabled="false" + android:text="@string/create_account_button"/> + + <ProgressBar + android:id="@+id/progress_wheel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:indeterminate="true" + android:visibility="gone"/> + </LinearLayout> +</ScrollView> \ No newline at end of file diff --git a/briar-android/src/org/briarproject/android/PasswordActivity.java b/briar-android/src/org/briarproject/android/PasswordActivity.java index f0c1a5fe3d30824ded7aa768ae3a5db5adc3e089..fed1a6201a97fff1dbc528feeeddb54348742b14 100644 --- a/briar-android/src/org/briarproject/android/PasswordActivity.java +++ b/briar-android/src/org/briarproject/android/PasswordActivity.java @@ -29,7 +29,6 @@ import static android.content.Intent.ACTION_MAIN; import static android.content.Intent.CATEGORY_HOME; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; -import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE; public class PasswordActivity extends BaseActivity { @@ -63,11 +62,11 @@ public class PasswordActivity extends BaseActivity { password = (EditText) findViewById(R.id.edit_password); password.setOnEditorActionListener(new OnEditorActionListener() { @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == IME_ACTION_DONE) { - validatePassword(encrypted, password.getText()); - } - return false; + public boolean onEditorAction(TextView v, int actionId, + KeyEvent event) { + hideSoftKeyboard(); + validatePassword(encrypted, password.getText()); + return true; } }); } diff --git a/briar-android/src/org/briarproject/android/SetupActivity.java b/briar-android/src/org/briarproject/android/SetupActivity.java index d0af6bb60857f278ef6945503344a4d87791db2a..2713b9984319f0c4f32bbd07e80db1c51d79ff8f 100644 --- a/briar-android/src/org/briarproject/android/SetupActivity.java +++ b/briar-android/src/org/briarproject/android/SetupActivity.java @@ -4,20 +4,20 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; +import android.support.design.widget.TextInputLayout; +import android.text.Editable; +import android.text.TextWatcher; 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.ScrollView; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import org.briarproject.R; -import org.briarproject.android.util.LayoutUtils; +import org.briarproject.android.util.AndroidUtils; import org.briarproject.android.util.StrengthMeter; import org.briarproject.api.android.ReferenceManager; import org.briarproject.api.crypto.CryptoComponent; @@ -35,38 +35,35 @@ import java.util.logging.Logger; import javax.inject.Inject; +import roboguice.inject.InjectView; + import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; -import static android.text.InputType.TYPE_CLASS_TEXT; -import static android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS; -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.INVISIBLE; 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 java.util.logging.Level.INFO; 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 static org.briarproject.api.crypto.PasswordStrengthEstimator.WEAK; import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; public class SetupActivity extends BaseActivity implements OnClickListener, -OnEditorActionListener { + OnEditorActionListener { private static final Logger LOG = Logger.getLogger(SetupActivity.class.getName()); @Inject @CryptoExecutor private Executor cryptoExecutor; @Inject private PasswordStrengthEstimator strengthEstimator; - private EditText nicknameEntry = null; - private EditText passwordEntry = null, passwordConfirmation = null; - private StrengthMeter strengthMeter = null; - private Button createAccountButton = null; - private ProgressBar progress = null; + @InjectView(R.id.nickname_entry_wrapper) TextInputLayout nicknameEntryWrapper; + @InjectView(R.id.password_entry_wrapper) TextInputLayout passwordEntryWrapper; + @InjectView(R.id.password_confirm_wrapper) TextInputLayout passwordConfirmationWrapper; + @InjectView(R.id.nickname_entry) EditText nicknameEntry; + @InjectView(R.id.password_entry) EditText passwordEntry; + @InjectView(R.id.password_confirm) EditText passwordConfirmation; + @InjectView(R.id.strength_meter) StrengthMeter strengthMeter; + @InjectView(R.id.create_account) Button createAccountButton; + @InjectView(R.id.progress_wheel) ProgressBar progress; // Fields that are accessed from background threads must be volatile @Inject private volatile CryptoComponent crypto; @@ -77,99 +74,32 @@ OnEditorActionListener { @Override public void onCreate(Bundle state) { super.onCreate(state); + setContentView(R.layout.activity_setup); if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE); - 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); - - TextView chooseNickname = new TextView(this); - chooseNickname.setGravity(CENTER); - chooseNickname.setTextSize(18); - chooseNickname.setText(R.string.choose_nickname); - layout.addView(chooseNickname); - - nicknameEntry = new EditText(this) { + TextWatcher tw = new TextWatcher() { @Override - protected void onTextChanged(CharSequence text, int start, - int lengthBefore, int lengthAfter) { - enableOrDisableContinueButton(); + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { } - }; - nicknameEntry.setId(1); - nicknameEntry.setMaxLines(1); - int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_WORDS; - nicknameEntry.setInputType(inputType); - layout.addView(nicknameEntry); - - TextView choosePassword = new TextView(this); - choosePassword.setGravity(CENTER); - choosePassword.setTextSize(18); - choosePassword.setPadding(0, pad, 0, 0); - choosePassword.setText(R.string.choose_password); - layout.addView(choosePassword); - passwordEntry = new EditText(this) { @Override - protected void onTextChanged(CharSequence text, int start, - int lengthBefore, int lengthAfter) { + public void onTextChanged(CharSequence s, int start, int before, + int count) { enableOrDisableContinueButton(); } - }; - passwordEntry.setId(2); - passwordEntry.setMaxLines(1); - inputType = TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD; - passwordEntry.setInputType(inputType); - layout.addView(passwordEntry); - - TextView confirmPassword = new TextView(this); - confirmPassword.setGravity(CENTER); - confirmPassword.setTextSize(18); - confirmPassword.setPadding(0, pad, 0, 0); - confirmPassword.setText(R.string.confirm_password); - layout.addView(confirmPassword); - passwordConfirmation = new EditText(this) { @Override - protected void onTextChanged(CharSequence text, int start, - int lengthBefore, int lengthAfter) { - enableOrDisableContinueButton(); + public void afterTextChanged(Editable s) { } }; - passwordConfirmation.setId(3); - passwordConfirmation.setMaxLines(1); - inputType = TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD; - passwordConfirmation.setInputType(inputType); - passwordConfirmation.setOnEditorActionListener(this); - layout.addView(passwordConfirmation); - strengthMeter = new StrengthMeter(this); - strengthMeter.setPadding(pad, pad, pad, pad); - strengthMeter.setVisibility(INVISIBLE); - layout.addView(strengthMeter); - - createAccountButton = new Button(this); - createAccountButton.setLayoutParams(WRAP_WRAP); - createAccountButton.setText(R.string.create_account_button); - createAccountButton.setEnabled(false); + nicknameEntry.addTextChangedListener(tw); + passwordEntry.addTextChangedListener(tw); + passwordConfirmation.addTextChangedListener(tw); + passwordConfirmation.setOnEditorActionListener(this); createAccountButton.setOnClickListener(this); - layout.addView(createAccountButton); - - progress = new ProgressBar(this); - progress.setLayoutParams(WRAP_WRAP); - progress.setPadding(0, pad, 0, 0); - progress.setIndeterminate(true); - progress.setVisibility(GONE); - layout.addView(progress); - - ScrollView scroll = new ScrollView(this); - scroll.addView(layout); - - setContentView(scroll); } private void enableOrDisableContinueButton() { @@ -184,21 +114,22 @@ OnEditorActionListener { boolean passwordsMatch = firstPassword.equals(secondPassword); float strength = strengthEstimator.estimateStrength(firstPassword); strengthMeter.setStrength(strength); - if (nicknameLength > MAX_AUTHOR_NAME_LENGTH) - nicknameEntry.setError(getString(R.string.name_too_long)); - if (firstPassword.length() > 0 && strength < WEAK) - passwordEntry.setError(getString(R.string.password_too_weak)); - if (secondPassword.length() > 0 && !passwordsMatch) - passwordConfirmation.setError(getString(R.string.passwords_do_not_match)); + AndroidUtils.setError(nicknameEntryWrapper, + getString(R.string.name_too_long), + nicknameLength > MAX_AUTHOR_NAME_LENGTH); + AndroidUtils.setError(passwordEntryWrapper, + getString(R.string.password_too_weak), + firstPassword.length() > 0 && strength < WEAK); + AndroidUtils.setError(passwordConfirmationWrapper, + getString(R.string.passwords_do_not_match), + secondPassword.length() > 0 && !passwordsMatch); createAccountButton.setEnabled(nicknameLength > 0 && nicknameLength <= MAX_AUTHOR_NAME_LENGTH && passwordsMatch && strength >= WEAK); } public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - // Hide the soft keyboard - Object o = getSystemService(INPUT_METHOD_SERVICE); - ((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0); + hideSoftKeyboard(); return true; } diff --git a/briar-android/src/org/briarproject/android/util/AndroidUtils.java b/briar-android/src/org/briarproject/android/util/AndroidUtils.java index 5923ba7e41cfbe024ba4d125d83272a31c8a4a73..abbafafd37992976aab2302a7d31f4b60692606e 100644 --- a/briar-android/src/org/briarproject/android/util/AndroidUtils.java +++ b/briar-android/src/org/briarproject/android/util/AndroidUtils.java @@ -2,6 +2,7 @@ package org.briarproject.android.util; import android.annotation.SuppressLint; import android.os.Build; +import android.support.design.widget.TextInputLayout; import java.util.ArrayList; import java.util.Arrays; @@ -23,4 +24,12 @@ public class AndroidUtils { } return Collections.unmodifiableList(abis); } + + public static void setError(TextInputLayout til, String error, boolean condition) { + if (condition) { + if (til.getError() == null) + til.setError(error); + } else + til.setError(null); + } } diff --git a/briar-android/src/org/briarproject/android/util/StrengthMeter.java b/briar-android/src/org/briarproject/android/util/StrengthMeter.java index 8a1507b693d7c7dfee66e693598da4f9a9755c19..eee1e547396ed6d466c9afce4764c3145ede77c1 100644 --- a/briar-android/src/org/briarproject/android/util/StrengthMeter.java +++ b/briar-android/src/org/briarproject/android/util/StrengthMeter.java @@ -1,5 +1,15 @@ package org.briarproject.android.util; +import android.content.Context; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.graphics.drawable.ShapeDrawable; +import android.util.AttributeSet; +import android.widget.ProgressBar; + import static android.graphics.Color.BLACK; import static android.graphics.Paint.Style.FILL; import static android.graphics.Paint.Style.STROKE; @@ -9,14 +19,6 @@ import static org.briarproject.api.crypto.PasswordStrengthEstimator.QUITE_STRONG import static org.briarproject.api.crypto.PasswordStrengthEstimator.QUITE_WEAK; import static org.briarproject.api.crypto.PasswordStrengthEstimator.STRONG; import static org.briarproject.api.crypto.PasswordStrengthEstimator.WEAK; -import android.content.Context; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.drawable.ClipDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.graphics.drawable.ShapeDrawable; -import android.widget.ProgressBar; public class StrengthMeter extends ProgressBar { @@ -30,7 +32,11 @@ public class StrengthMeter extends ProgressBar { private final ShapeDrawable bar; public StrengthMeter(Context context) { - super(context, null, android.R.attr.progressBarStyleHorizontal); + this(context, null); + } + + public StrengthMeter(Context context, AttributeSet attrs) { + super(context, attrs, android.R.attr.progressBarStyleHorizontal); bar = new ShapeDrawable(); bar.getPaint().setColor(RED); ClipDrawable clip = new ClipDrawable(bar, LEFT, HORIZONTAL);