From e870ef303df2b502332a126feb0dce27b3436346 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 19 Oct 2023 14:51:07 +0200 Subject: [PATCH 01/10] Use New TextWatcher Signed-off-by: alperozturk --- .../android/ui/activity/PassCodeActivity.java | 181 +++++++++--------- app/src/main/res/values/styles.xml | 1 - 2 files changed, 93 insertions(+), 89 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java index 3fe049ef391e..b4b07a63f655 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java @@ -26,11 +26,9 @@ import android.content.Intent; import android.os.Bundle; import android.text.Editable; -import android.text.TextUtils; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.View; -import android.view.View.OnClickListener; import android.view.Window; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; @@ -77,7 +75,6 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { private final EditText[] passCodeEditTexts = new EditText[4]; private String[] passCodeDigits = {"", "", "", ""}; private boolean confirmingPassCode; - private boolean changed = true; // to control that only one blocks jump /** * Initializes the activity. @@ -158,12 +155,7 @@ protected void onCreate(Bundle savedInstanceState) { protected void setCancelButtonEnabled(boolean enabled) { if (enabled) { binding.cancel.setVisibility(View.VISIBLE); - binding.cancel.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); + binding.cancel.setOnClickListener(v -> finish()); } else { binding.cancel.setVisibility(View.INVISIBLE); binding.cancel.setOnClickListener(null); @@ -179,46 +171,16 @@ public PasscodelockBinding getBinding() { * Binds the appropriate listeners to the input boxes receiving each digit of the pass code. */ protected void setTextListeners() { - passCodeEditTexts[0].addTextChangedListener(new PassCodeDigitTextWatcher(0, false)); - passCodeEditTexts[1].addTextChangedListener(new PassCodeDigitTextWatcher(1, false)); - passCodeEditTexts[2].addTextChangedListener(new PassCodeDigitTextWatcher(2, false)); - passCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true)); - - setOnKeyListener(1); - setOnKeyListener(2); - setOnKeyListener(3); - - passCodeEditTexts[1].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(1)); - passCodeEditTexts[2].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(2)); + passCodeEditTexts[0].addTextChangedListener(new PinTextWatcher(0)); + passCodeEditTexts[1].addTextChangedListener(new PinTextWatcher(1)); + passCodeEditTexts[2].addTextChangedListener(new PinTextWatcher(2)); + passCodeEditTexts[3].addTextChangedListener(new PinTextWatcher(3)); - passCodeEditTexts[3].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(3)); - } - - private void onPassCodeEditTextFocusChange(final int passCodeIndex) { - for (int i = 0; i < passCodeIndex; i++) { - if (TextUtils.isEmpty(passCodeEditTexts[i].getText())) { - passCodeEditTexts[i].requestFocus(); - break; - } - } - } - - private void setOnKeyListener(final int passCodeIndex) { - passCodeEditTexts[passCodeIndex].setOnKeyListener((v, keyCode, event) -> { - if (keyCode == KeyEvent.KEYCODE_DEL && changed) { - passCodeEditTexts[passCodeIndex - 1].requestFocus(); - if (!confirmingPassCode) { - passCodeDigits[passCodeIndex - 1] = ""; - } - passCodeEditTexts[passCodeIndex - 1].setText(""); - changed = false; - - } else if (!changed) { - changed = true; - } - return false; - }); + passCodeEditTexts[0].setOnKeyListener(new PinOnKeyListener(0)); + passCodeEditTexts[1].setOnKeyListener(new PinOnKeyListener(1)); + passCodeEditTexts[2].setOnKeyListener(new PinOnKeyListener(2)); + passCodeEditTexts[3].setOnKeyListener(new PinOnKeyListener(3)); } /** @@ -401,7 +363,7 @@ private void showDelay() { @Override public void run() { try { - Thread.sleep(delay * 1000); + Thread.sleep(delay * 1000L); runOnUiThread(() -> { binding.explanation.setVisibility(View.INVISIBLE); @@ -426,64 +388,107 @@ public void onSaveInstanceState(@NonNull Bundle outState) { outState.putStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS, passCodeDigits); } - private class PassCodeDigitTextWatcher implements TextWatcher { - - private int mIndex = -1; - private boolean mLastOne; - - /** - * Constructor - * - * @param index Position in the pass code of the input field that will be bound to this watcher. - * @param lastOne 'True' means that watcher corresponds to the last position of the pass code. - */ - PassCodeDigitTextWatcher(int index, boolean lastOne) { - mIndex = index; - mLastOne = lastOne; - if (mIndex < 0) { - throw new IllegalArgumentException( - "Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() + - " constructor" - ); - } + private class PinTextWatcher implements TextWatcher { + + private final int currentIndex; + private boolean isFirst = false, isLast = false; + private String newTypedString = ""; + + PinTextWatcher(int currentIndex) { + this.currentIndex = currentIndex; + + if (currentIndex == 0) + this.isFirst = true; + else if (currentIndex == passCodeEditTexts.length - 1) + this.isLast = true; } - private int next() { - return mLastOne ? 0 : mIndex + 1; + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + newTypedString = s.subSequence(start, start + count).toString().trim(); } - /** - * Performs several actions when the user types a digit in an input field: - saves the input digit to the state - * of the activity; this will allow retyping the pass code to confirm it. - moves the focus automatically to the - * next field - for the last field, triggers the processing of the full pass code - * - * @param s Changed text - */ @Override public void afterTextChanged(Editable s) { - if (s.length() > 0) { + String text = newTypedString; + + if (text.length() > 1) { + text = String.valueOf(text.charAt(0)); + + passCodeEditTexts[currentIndex].removeTextChangedListener(this); + passCodeEditTexts[currentIndex].setText(text); + passCodeEditTexts[currentIndex].setSelection(text.length()); + passCodeEditTexts[currentIndex].addTextChangedListener(this); + if (!confirmingPassCode) { - passCodeDigits[mIndex] = passCodeEditTexts[mIndex].getText().toString(); + passCodeDigits[currentIndex] = passCodeEditTexts[currentIndex].getText().toString(); + } + + if (text.length() == 1) { + moveToNext(); + } else if (text.length() == 0) { + moveToPrevious(); } - passCodeEditTexts[next()].requestFocus(); - if (mLastOne) { + if (isLast) { processFullPassCode(); } + } + } - } else { - Log_OC.d(TAG, "Text box " + mIndex + " was cleaned"); + private void moveToNext() { + if (!isLast) + passCodeEditTexts[currentIndex + 1].requestFocus(); + + if (isAllEditTextsFilled() && isLast) { // isLast is optional + passCodeEditTexts[currentIndex].clearFocus(); + hideKeyboard(); } } - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // nothing to do + private void moveToPrevious() { + if (!isFirst) + passCodeEditTexts[currentIndex - 1].requestFocus(); + } + + private boolean isAllEditTextsFilled() { + for (EditText editText : passCodeEditTexts) + if (editText.getText().toString().trim().length() == 0) + return false; + return true; + } + + private void hideKeyboard() { + if (getCurrentFocus() != null) { + InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); + } + } + + } + + private class PinOnKeyListener implements View.OnKeyListener { + + private final int currentIndex; + + PinOnKeyListener(int currentIndex) { + this.currentIndex = currentIndex; } @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - // nothing to do + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) { + if (passCodeEditTexts[currentIndex].getText().toString().isEmpty() && currentIndex != 0) { + passCodeEditTexts[currentIndex - 1].requestFocus(); + } + } + return false; } + } } diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 400b7bb7d326..ac5b9103f49b 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -331,7 +331,6 @@ numberDecimal decimal 1234567890 - 1 true 1 @color/text_color From 8d821bf188197bc0fc4544b4db8db00fa54a058b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 19 Oct 2023 15:39:41 +0200 Subject: [PATCH 02/10] Revert Signed-off-by: alperozturk --- .../android/ui/activity/PassCodeActivity.java | 181 +++++++++--------- app/src/main/res/values/styles.xml | 1 + 2 files changed, 89 insertions(+), 93 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java index b4b07a63f655..3fe049ef391e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java @@ -26,9 +26,11 @@ import android.content.Intent; import android.os.Bundle; import android.text.Editable; +import android.text.TextUtils; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.View; +import android.view.View.OnClickListener; import android.view.Window; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; @@ -75,6 +77,7 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { private final EditText[] passCodeEditTexts = new EditText[4]; private String[] passCodeDigits = {"", "", "", ""}; private boolean confirmingPassCode; + private boolean changed = true; // to control that only one blocks jump /** * Initializes the activity. @@ -155,7 +158,12 @@ protected void onCreate(Bundle savedInstanceState) { protected void setCancelButtonEnabled(boolean enabled) { if (enabled) { binding.cancel.setVisibility(View.VISIBLE); - binding.cancel.setOnClickListener(v -> finish()); + binding.cancel.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); } else { binding.cancel.setVisibility(View.INVISIBLE); binding.cancel.setOnClickListener(null); @@ -171,16 +179,46 @@ public PasscodelockBinding getBinding() { * Binds the appropriate listeners to the input boxes receiving each digit of the pass code. */ protected void setTextListeners() { + passCodeEditTexts[0].addTextChangedListener(new PassCodeDigitTextWatcher(0, false)); + passCodeEditTexts[1].addTextChangedListener(new PassCodeDigitTextWatcher(1, false)); + passCodeEditTexts[2].addTextChangedListener(new PassCodeDigitTextWatcher(2, false)); + passCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true)); + + setOnKeyListener(1); + setOnKeyListener(2); + setOnKeyListener(3); + + passCodeEditTexts[1].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(1)); - passCodeEditTexts[0].addTextChangedListener(new PinTextWatcher(0)); - passCodeEditTexts[1].addTextChangedListener(new PinTextWatcher(1)); - passCodeEditTexts[2].addTextChangedListener(new PinTextWatcher(2)); - passCodeEditTexts[3].addTextChangedListener(new PinTextWatcher(3)); + passCodeEditTexts[2].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(2)); - passCodeEditTexts[0].setOnKeyListener(new PinOnKeyListener(0)); - passCodeEditTexts[1].setOnKeyListener(new PinOnKeyListener(1)); - passCodeEditTexts[2].setOnKeyListener(new PinOnKeyListener(2)); - passCodeEditTexts[3].setOnKeyListener(new PinOnKeyListener(3)); + passCodeEditTexts[3].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(3)); + } + + private void onPassCodeEditTextFocusChange(final int passCodeIndex) { + for (int i = 0; i < passCodeIndex; i++) { + if (TextUtils.isEmpty(passCodeEditTexts[i].getText())) { + passCodeEditTexts[i].requestFocus(); + break; + } + } + } + + private void setOnKeyListener(final int passCodeIndex) { + passCodeEditTexts[passCodeIndex].setOnKeyListener((v, keyCode, event) -> { + if (keyCode == KeyEvent.KEYCODE_DEL && changed) { + passCodeEditTexts[passCodeIndex - 1].requestFocus(); + if (!confirmingPassCode) { + passCodeDigits[passCodeIndex - 1] = ""; + } + passCodeEditTexts[passCodeIndex - 1].setText(""); + changed = false; + + } else if (!changed) { + changed = true; + } + return false; + }); } /** @@ -363,7 +401,7 @@ private void showDelay() { @Override public void run() { try { - Thread.sleep(delay * 1000L); + Thread.sleep(delay * 1000); runOnUiThread(() -> { binding.explanation.setVisibility(View.INVISIBLE); @@ -388,107 +426,64 @@ public void onSaveInstanceState(@NonNull Bundle outState) { outState.putStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS, passCodeDigits); } - private class PinTextWatcher implements TextWatcher { - - private final int currentIndex; - private boolean isFirst = false, isLast = false; - private String newTypedString = ""; - - PinTextWatcher(int currentIndex) { - this.currentIndex = currentIndex; - - if (currentIndex == 0) - this.isFirst = true; - else if (currentIndex == passCodeEditTexts.length - 1) - this.isLast = true; - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - + private class PassCodeDigitTextWatcher implements TextWatcher { + + private int mIndex = -1; + private boolean mLastOne; + + /** + * Constructor + * + * @param index Position in the pass code of the input field that will be bound to this watcher. + * @param lastOne 'True' means that watcher corresponds to the last position of the pass code. + */ + PassCodeDigitTextWatcher(int index, boolean lastOne) { + mIndex = index; + mLastOne = lastOne; + if (mIndex < 0) { + throw new IllegalArgumentException( + "Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() + + " constructor" + ); + } } - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - newTypedString = s.subSequence(start, start + count).toString().trim(); + private int next() { + return mLastOne ? 0 : mIndex + 1; } + /** + * Performs several actions when the user types a digit in an input field: - saves the input digit to the state + * of the activity; this will allow retyping the pass code to confirm it. - moves the focus automatically to the + * next field - for the last field, triggers the processing of the full pass code + * + * @param s Changed text + */ @Override public void afterTextChanged(Editable s) { - String text = newTypedString; - - if (text.length() > 1) { - text = String.valueOf(text.charAt(0)); - - passCodeEditTexts[currentIndex].removeTextChangedListener(this); - passCodeEditTexts[currentIndex].setText(text); - passCodeEditTexts[currentIndex].setSelection(text.length()); - passCodeEditTexts[currentIndex].addTextChangedListener(this); - + if (s.length() > 0) { if (!confirmingPassCode) { - passCodeDigits[currentIndex] = passCodeEditTexts[currentIndex].getText().toString(); - } - - if (text.length() == 1) { - moveToNext(); - } else if (text.length() == 0) { - moveToPrevious(); + passCodeDigits[mIndex] = passCodeEditTexts[mIndex].getText().toString(); } + passCodeEditTexts[next()].requestFocus(); - if (isLast) { + if (mLastOne) { processFullPassCode(); } - } - } - - private void moveToNext() { - if (!isLast) - passCodeEditTexts[currentIndex + 1].requestFocus(); - if (isAllEditTextsFilled() && isLast) { // isLast is optional - passCodeEditTexts[currentIndex].clearFocus(); - hideKeyboard(); - } - } - - private void moveToPrevious() { - if (!isFirst) - passCodeEditTexts[currentIndex - 1].requestFocus(); - } - - private boolean isAllEditTextsFilled() { - for (EditText editText : passCodeEditTexts) - if (editText.getText().toString().trim().length() == 0) - return false; - return true; - } - - private void hideKeyboard() { - if (getCurrentFocus() != null) { - InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); + } else { + Log_OC.d(TAG, "Text box " + mIndex + " was cleaned"); } } - } - - private class PinOnKeyListener implements View.OnKeyListener { - - private final int currentIndex; - - PinOnKeyListener(int currentIndex) { - this.currentIndex = currentIndex; + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // nothing to do } @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) { - if (passCodeEditTexts[currentIndex].getText().toString().isEmpty() && currentIndex != 0) { - passCodeEditTexts[currentIndex - 1].requestFocus(); - } - } - return false; + public void onTextChanged(CharSequence s, int start, int before, int count) { + // nothing to do } - } } diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ac5b9103f49b..400b7bb7d326 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -331,6 +331,7 @@ numberDecimal decimal 1234567890 + 1 true 1 @color/text_color From e2d7fbd052d7294eef8b20723562c6cd2099f680 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 19 Oct 2023 16:12:12 +0200 Subject: [PATCH 03/10] Disable manual focus change via tap Signed-off-by: alperozturk --- .../android/ui/activity/PassCodeActivity.java | 56 ++++++++----------- app/src/main/res/layout/passcodelock.xml | 3 - 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java index 3fe049ef391e..6ee490b511e9 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java @@ -23,6 +23,7 @@ */ package com.owncloud.android.ui.activity; +import android.annotation.SuppressLint; import android.content.Intent; import android.os.Bundle; import android.text.Editable; @@ -30,7 +31,6 @@ import android.text.TextWatcher; import android.view.KeyEvent; import android.view.View; -import android.view.View.OnClickListener; import android.view.Window; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; @@ -91,7 +91,6 @@ protected void onCreate(Bundle savedInstanceState) { binding = PasscodelockBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - viewThemeUtils.platform.colorTextButtons(binding.cancel); passCodeEditTexts[0] = binding.txt0; @@ -105,7 +104,6 @@ protected void onCreate(Bundle savedInstanceState) { passCodeEditTexts[0].requestFocus(); - Window window = getWindow(); if (window != null) { window.setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); @@ -125,7 +123,7 @@ protected void onCreate(Bundle savedInstanceState) { passCodeDigits = savedInstanceState.getStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS); } if (confirmingPassCode) { - // the app was in the passcodeconfirmation + // the app was in the passcode confirmation requestPassCodeConfirmation(); } else { // pass code preference has just been activated in SettingsActivity; @@ -158,12 +156,7 @@ protected void onCreate(Bundle savedInstanceState) { protected void setCancelButtonEnabled(boolean enabled) { if (enabled) { binding.cancel.setVisibility(View.VISIBLE); - binding.cancel.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); + binding.cancel.setOnClickListener(v -> finish()); } else { binding.cancel.setVisibility(View.INVISIBLE); binding.cancel.setOnClickListener(null); @@ -178,21 +171,27 @@ public PasscodelockBinding getBinding() { /** * Binds the appropriate listeners to the input boxes receiving each digit of the pass code. */ + @SuppressLint("ClickableViewAccessibility") protected void setTextListeners() { - passCodeEditTexts[0].addTextChangedListener(new PassCodeDigitTextWatcher(0, false)); - passCodeEditTexts[1].addTextChangedListener(new PassCodeDigitTextWatcher(1, false)); - passCodeEditTexts[2].addTextChangedListener(new PassCodeDigitTextWatcher(2, false)); - passCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true)); - - setOnKeyListener(1); - setOnKeyListener(2); - setOnKeyListener(3); + for (int i = 0; i < passCodeEditTexts.length; i++) { + final EditText editText = passCodeEditTexts[i]; + boolean isLast = (i == 3); - passCodeEditTexts[1].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(1)); + editText.addTextChangedListener(new PassCodeDigitTextWatcher(i, isLast)); + if (i > 0) { + setOnKeyListener(i); + } - passCodeEditTexts[2].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(2)); + int finalIndex = i; + editText.setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(finalIndex)); - passCodeEditTexts[3].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(3)); + // Disable touch event for focus change via tap gesture + editText.setSelectAllOnFocus(false); + editText.setTextIsSelectable(false); + editText.setOnTouchListener((v, event) -> { + return true; + }); + } } private void onPassCodeEditTextFocusChange(final int passCodeIndex) { @@ -284,8 +283,7 @@ private void hideSoftKeyboard() { } } - private void showErrorAndRestart(int errorMessage, int headerMessage, - int explanationVisibility) { + private void showErrorAndRestart(int errorMessage, int headerMessage, int explanationVisibility) { Arrays.fill(passCodeDigits, null); Snackbar.make(findViewById(android.R.id.content), getString(errorMessage), Snackbar.LENGTH_LONG).show(); binding.header.setText(headerMessage); // TODO check if really needed @@ -312,8 +310,6 @@ protected void requestPassCodeConfirmation() { * @return 'True' if entered pass code equals to the saved one. */ protected boolean checkPassCode() { - - String[] savedPassCodeDigits = preferences.getPassCode(); boolean result = true; @@ -401,7 +397,7 @@ private void showDelay() { @Override public void run() { try { - Thread.sleep(delay * 1000); + Thread.sleep(delay * 1000L); runOnUiThread(() -> { binding.explanation.setVisibility(View.INVISIBLE); @@ -477,13 +473,9 @@ public void afterTextChanged(Editable s) { } @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // nothing to do - } + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - // nothing to do - } + public void onTextChanged(CharSequence s, int start, int before, int count) {} } } diff --git a/app/src/main/res/layout/passcodelock.xml b/app/src/main/res/layout/passcodelock.xml index 94374e44e8a9..c6ed495a6599 100644 --- a/app/src/main/res/layout/passcodelock.xml +++ b/app/src/main/res/layout/passcodelock.xml @@ -73,13 +73,10 @@ android:id="@+id/txt0" style="@style/PassCodeStyle" android:cursorVisible="false" - android:focusable="true" android:hint="@string/hidden_character" android:imeOptions="flagNoExtractUi" android:importantForAutofill="no" tools:text="123"> - - Date: Thu, 19 Oct 2023 16:19:31 +0200 Subject: [PATCH 04/10] Update passcode style Signed-off-by: alperozturk --- .../com/owncloud/android/ui/activity/PassCodeActivity.java | 7 +++---- app/src/main/res/layout/passcodelock.xml | 4 ---- app/src/main/res/values/styles.xml | 1 + 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java index 6ee490b511e9..5745851b0469 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java @@ -185,12 +185,10 @@ protected void setTextListeners() { int finalIndex = i; editText.setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(finalIndex)); - // Disable touch event for focus change via tap gesture + // Disable focus change via tap gesture editText.setSelectAllOnFocus(false); editText.setTextIsSelectable(false); - editText.setOnTouchListener((v, event) -> { - return true; - }); + editText.setOnTouchListener((v, event) -> true); } } @@ -478,4 +476,5 @@ public void beforeTextChanged(CharSequence s, int start, int count, int after) { @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} } + } diff --git a/app/src/main/res/layout/passcodelock.xml b/app/src/main/res/layout/passcodelock.xml index c6ed495a6599..6e08fd0c1aca 100644 --- a/app/src/main/res/layout/passcodelock.xml +++ b/app/src/main/res/layout/passcodelock.xml @@ -72,7 +72,6 @@ @@ -90,7 +88,6 @@ @@ -98,7 +95,6 @@ diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 400b7bb7d326..025867e458cb 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -327,6 +327,7 @@ 50dp 50dp center + false 10dp numberDecimal decimal From 9957ce882a8f93b6296a62d512241fc6347ae510 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 20 Oct 2023 09:54:24 +0200 Subject: [PATCH 05/10] Disable default keyboard dismiss behaviour Signed-off-by: alperozturk --- .../android/ui/activity/PassCodeActivity.java | 17 +++++--- .../android/ui/components/PassCodeEditText.kt | 39 +++++++++++++++++++ app/src/main/res/layout/passcodelock.xml | 18 +++------ app/src/main/res/values/styles.xml | 1 + 4 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/com/owncloud/android/ui/components/PassCodeEditText.kt diff --git a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java index 5745851b0469..10ab5cf60f92 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java @@ -42,6 +42,7 @@ import com.owncloud.android.authentication.PassCodeManager; import com.owncloud.android.databinding.PasscodelockBinding; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.ui.components.PassCodeEditText; import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.Arrays; @@ -74,7 +75,7 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { @Inject PassCodeManager passCodeManager; @Inject ViewThemeUtils viewThemeUtils; private PasscodelockBinding binding; - private final EditText[] passCodeEditTexts = new EditText[4]; + private final PassCodeEditText[] passCodeEditTexts = new PassCodeEditText[4]; private String[] passCodeDigits = {"", "", "", ""}; private boolean confirmingPassCode; private boolean changed = true; // to control that only one blocks jump @@ -174,7 +175,7 @@ public PasscodelockBinding getBinding() { @SuppressLint("ClickableViewAccessibility") protected void setTextListeners() { for (int i = 0; i < passCodeEditTexts.length; i++) { - final EditText editText = passCodeEditTexts[i]; + final PassCodeEditText editText = passCodeEditTexts[i]; boolean isLast = (i == 3); editText.addTextChangedListener(new PassCodeDigitTextWatcher(i, isLast)); @@ -276,8 +277,7 @@ private void hideSoftKeyboard() { (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( focusedView.getWindowToken(), - 0 - ); + 0); } } @@ -412,7 +412,6 @@ public void run() { } } - @Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); @@ -434,6 +433,7 @@ private class PassCodeDigitTextWatcher implements TextWatcher { PassCodeDigitTextWatcher(int index, boolean lastOne) { mIndex = index; mLastOne = lastOne; + if (mIndex < 0) { throw new IllegalArgumentException( "Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() + @@ -457,8 +457,13 @@ private int next() { public void afterTextChanged(Editable s) { if (s.length() > 0) { if (!confirmingPassCode) { - passCodeDigits[mIndex] = passCodeEditTexts[mIndex].getText().toString(); + Editable passCodeText = passCodeEditTexts[mIndex].getText(); + + if (passCodeText != null) { + passCodeDigits[mIndex] = passCodeText.toString(); + } } + passCodeEditTexts[next()].requestFocus(); if (mLastOne) { diff --git a/app/src/main/java/com/owncloud/android/ui/components/PassCodeEditText.kt b/app/src/main/java/com/owncloud/android/ui/components/PassCodeEditText.kt new file mode 100644 index 000000000000..d699f02e07a3 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/components/PassCodeEditText.kt @@ -0,0 +1,39 @@ +/* + * Nextcloud Android client application + * + * @author Alper Ozturk + * Copyright (C) 2023 Alper Ozturk + * Copyright (C) 2023 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.ui.components + +import android.content.Context +import android.util.AttributeSet +import android.view.KeyEvent +import androidx.appcompat.widget.AppCompatEditText + +class PassCodeEditText(context: Context, attrs: AttributeSet?): AppCompatEditText(context, attrs) { + + override fun onKeyPreIme(keyCode: Int, event: KeyEvent): Boolean { + val isBackButtonPressed = (event.keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) + if (isBackButtonPressed) { + // Override default behaviour and prevent dismissing the keyboard + return true + } + return super.dispatchKeyEvent(event) + } + +} diff --git a/app/src/main/res/layout/passcodelock.xml b/app/src/main/res/layout/passcodelock.xml index 6e08fd0c1aca..81004efa37e3 100644 --- a/app/src/main/res/layout/passcodelock.xml +++ b/app/src/main/res/layout/passcodelock.xml @@ -69,34 +69,26 @@ android:layout_height="wrap_content" android:gravity="center_horizontal"> - - + - - - diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 025867e458cb..c8383be19632 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -324,6 +324,7 @@