diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Activities/AuthenticateActivity.java b/app/src/main/java/org/shadowice/flocke/andotp/Activities/AuthenticateActivity.java index 7041a977..ea35edaa 100644 --- a/app/src/main/java/org/shadowice/flocke/andotp/Activities/AuthenticateActivity.java +++ b/app/src/main/java/org/shadowice/flocke/andotp/Activities/AuthenticateActivity.java @@ -56,6 +56,7 @@ import org.shadowice.flocke.andotp.R; import org.shadowice.flocke.andotp.Tasks.AuthenticationTask; import org.shadowice.flocke.andotp.Tasks.AuthenticationTask.Result; import org.shadowice.flocke.andotp.Utilities.Constants; +import org.shadowice.flocke.andotp.Utilities.EditorActionHelper; import static org.shadowice.flocke.andotp.Utilities.Constants.AuthMethod; @@ -237,7 +238,7 @@ public class AuthenticateActivity extends BaseActivity @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_DONE) { + if (EditorActionHelper.isActionDoneOrKeyboardEnter(actionId, event)) { startAuthTask(v.getText().toString()); return true; } diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Activities/IntroScreenActivity.java b/app/src/main/java/org/shadowice/flocke/andotp/Activities/IntroScreenActivity.java index f09ad458..793b2b20 100644 --- a/app/src/main/java/org/shadowice/flocke/andotp/Activities/IntroScreenActivity.java +++ b/app/src/main/java/org/shadowice/flocke/andotp/Activities/IntroScreenActivity.java @@ -32,6 +32,7 @@ import android.text.InputType; import android.text.TextWatcher; import android.text.method.PasswordTransformationMethod; import android.util.SparseArray; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -57,6 +58,7 @@ import com.heinrichreimersoftware.materialintro.slide.SimpleSlide; import org.shadowice.flocke.andotp.R; import org.shadowice.flocke.andotp.Utilities.ConfirmedPasswordTransformationHelper; import org.shadowice.flocke.andotp.Utilities.Constants; +import org.shadowice.flocke.andotp.Utilities.EditorActionHelper; import org.shadowice.flocke.andotp.Utilities.Settings; import org.shadowice.flocke.andotp.Utilities.UIHelper; @@ -266,7 +268,7 @@ public class IntroScreenActivity extends IntroActivity { } } - public static class AuthenticationFragment extends SlideFragment { + public static class AuthenticationFragment extends SlideFragment implements TextView.OnEditorActionListener { private Constants.EncryptionType encryptionType = Constants.EncryptionType.KEYSTORE; private int slidePos = -1; @@ -488,11 +490,27 @@ public class IntroScreenActivity extends IntroActivity { passwordInput.addTextChangedListener(textWatcher); passwordConfirm.addTextChangedListener(textWatcher); + passwordConfirm.setOnEditorActionListener(this); + selection.setSelection(selectionMapping.indexOfValue(Constants.AuthMethod.PASSWORD)); return root; } + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (EditorActionHelper.isActionDoneOrKeyboardEnter(actionId, event)) { + nextSlide(); + return true; + } else if (EditorActionHelper.isActionUpKeyboardEnter(event)) { + // Ignore action up after keyboard enter. Otherwise the go-back button would be selected + // after pressing enter with an invalid password. + return true; + } + + return false; + } + @Override public boolean canGoForward() { Constants.AuthMethod authMethod = selectionMapping.get(selection.getSelectedItemPosition()); diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Dialogs/PasswordEntryDialog.java b/app/src/main/java/org/shadowice/flocke/andotp/Dialogs/PasswordEntryDialog.java index dd0b535a..41eeb1bf 100644 --- a/app/src/main/java/org/shadowice/flocke/andotp/Dialogs/PasswordEntryDialog.java +++ b/app/src/main/java/org/shadowice/flocke/andotp/Dialogs/PasswordEntryDialog.java @@ -10,16 +10,19 @@ import android.os.Build; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; +import android.view.KeyEvent; import android.view.View; import android.widget.Button; import android.widget.EditText; +import android.widget.TextView; import org.shadowice.flocke.andotp.R; import org.shadowice.flocke.andotp.Utilities.ConfirmedPasswordTransformationHelper; +import org.shadowice.flocke.andotp.Utilities.EditorActionHelper; import org.shadowice.flocke.andotp.Utilities.Tools; public class PasswordEntryDialog extends AppCompatDialog - implements View.OnClickListener, TextWatcher { + implements View.OnClickListener, TextWatcher, TextView.OnEditorActionListener { public enum Mode { ENTER, UPDATE } @@ -69,8 +72,10 @@ public class PasswordEntryDialog extends AppCompatDialog passwordConfirm.setVisibility(View.VISIBLE); passwordInput.addTextChangedListener(this); passwordConfirm.addTextChangedListener(this); + passwordConfirm.setOnEditorActionListener(this); } else if (this.dialogMode == Mode.ENTER) { passwordConfirm.setVisibility(View.GONE); + passwordInput.setOnEditorActionListener(this); } } @@ -85,6 +90,20 @@ public class PasswordEntryDialog extends AppCompatDialog public void afterTextChanged(Editable s) {} public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (EditorActionHelper.isActionDoneOrKeyboardEnter(actionId, event)) { + if (okButton.isEnabled()) okButton.performClick(); + return true; + } else if (EditorActionHelper.isActionUpKeyboardEnter(event)) { + // Ignore action up after keyboard enter. Otherwise the cancel button would be selected + // after pressing enter with an invalid password. + return true; + } + + return false; + } + // View.OnClickListener public void onClick(View view) { if (view.getId() == R.id.buttonOk) { diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Preferences/CredentialsPreference.java b/app/src/main/java/org/shadowice/flocke/andotp/Preferences/CredentialsPreference.java index 0976a253..b53445de 100644 --- a/app/src/main/java/org/shadowice/flocke/andotp/Preferences/CredentialsPreference.java +++ b/app/src/main/java/org/shadowice/flocke/andotp/Preferences/CredentialsPreference.java @@ -31,6 +31,7 @@ import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; import android.util.AttributeSet; +import android.view.KeyEvent; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; @@ -47,6 +48,7 @@ import com.google.android.material.textfield.TextInputLayout; import org.shadowice.flocke.andotp.R; import org.shadowice.flocke.andotp.Utilities.ConfirmedPasswordTransformationHelper; import org.shadowice.flocke.andotp.Utilities.Constants; +import org.shadowice.flocke.andotp.Utilities.EditorActionHelper; import org.shadowice.flocke.andotp.Utilities.Settings; import org.shadowice.flocke.andotp.Utilities.UIHelper; @@ -59,7 +61,7 @@ import static org.shadowice.flocke.andotp.Utilities.Constants.AuthMethod; import static org.shadowice.flocke.andotp.Utilities.Constants.EncryptionType; public class CredentialsPreference extends DialogPreference - implements AdapterView.OnItemClickListener, View.OnClickListener, TextWatcher { + implements AdapterView.OnItemClickListener, View.OnClickListener, TextWatcher, TextView.OnEditorActionListener { public static final AuthMethod DEFAULT_VALUE = AuthMethod.NONE; public interface EncryptionChangeCallback { @@ -143,6 +145,7 @@ public class CredentialsPreference extends DialogPreference passwordInput.addTextChangedListener(this); passwordConfirm.addTextChangedListener(this); + passwordConfirm.setOnEditorActionListener(this); Button btnCancel = view.findViewById(R.id.btnCancel); btnSave = view.findViewById(R.id.btnSave); @@ -290,6 +293,20 @@ public class CredentialsPreference extends DialogPreference passwordConfirm.setText(null); } + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (EditorActionHelper.isActionDoneOrKeyboardEnter(actionId, event)) { + if (btnSave.isEnabled()) btnSave.performClick(); + return true; + } else if (EditorActionHelper.isActionUpKeyboardEnter(event)) { + // Ignore action up after keyboard enter. Otherwise the cancel button would be selected + // after pressing enter with an invalid password. + return true; + } + + return false; + } + // Needed stub functions @Override public void afterTextChanged(Editable s) {} diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Utilities/EditorActionHelper.java b/app/src/main/java/org/shadowice/flocke/andotp/Utilities/EditorActionHelper.java new file mode 100644 index 00000000..509a7cd2 --- /dev/null +++ b/app/src/main/java/org/shadowice/flocke/andotp/Utilities/EditorActionHelper.java @@ -0,0 +1,23 @@ +package org.shadowice.flocke.andotp.Utilities; + +import android.view.KeyEvent; +import android.view.inputmethod.EditorInfo; + +import static android.view.KeyEvent.ACTION_DOWN; +import static android.view.KeyEvent.ACTION_UP; +import static android.view.KeyEvent.KEYCODE_ENTER; +import static android.view.KeyEvent.KEYCODE_NUMPAD_ENTER; + +public class EditorActionHelper { + + private EditorActionHelper() { /* not allowed */ } + + public static boolean isActionDoneOrKeyboardEnter(int actionId, KeyEvent event) { + return actionId == EditorInfo.IME_ACTION_DONE + || event.getAction() == ACTION_DOWN && (event.getKeyCode() == KEYCODE_ENTER || event.getKeyCode() == KEYCODE_NUMPAD_ENTER); + } + + public static boolean isActionUpKeyboardEnter(KeyEvent event) { + return event.getAction() == ACTION_UP && (event.getKeyCode() == KEYCODE_ENTER || event.getKeyCode() == KEYCODE_NUMPAD_ENTER); + } +}