Skip to content

Commit 28f54f3

Browse files
Merge pull request #12068 from nextcloud/bugfix/app-not-switching-to-next-fields-after-entering-pin-number
Bugfix Disable focus change via tap
2 parents 4b5a488 + 6a9f51b commit 28f54f3

4 files changed

Lines changed: 94 additions & 66 deletions

File tree

app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java

Lines changed: 35 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import android.text.TextWatcher;
3131
import android.view.KeyEvent;
3232
import android.view.View;
33-
import android.view.View.OnClickListener;
3433
import android.view.Window;
3534
import android.view.inputmethod.InputMethodManager;
3635
import android.widget.EditText;
@@ -42,6 +41,7 @@
4241
import com.owncloud.android.authentication.PassCodeManager;
4342
import com.owncloud.android.databinding.PasscodelockBinding;
4443
import com.owncloud.android.lib.common.utils.Log_OC;
44+
import com.owncloud.android.ui.components.PassCodeEditText;
4545
import com.owncloud.android.utils.theme.ViewThemeUtils;
4646

4747
import java.util.Arrays;
@@ -74,7 +74,7 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable {
7474
@Inject PassCodeManager passCodeManager;
7575
@Inject ViewThemeUtils viewThemeUtils;
7676
private PasscodelockBinding binding;
77-
private final EditText[] passCodeEditTexts = new EditText[4];
77+
private final PassCodeEditText[] passCodeEditTexts = new PassCodeEditText[4];
7878
private String[] passCodeDigits = {"", "", "", ""};
7979
private boolean confirmingPassCode;
8080
private boolean changed = true; // to control that only one blocks jump
@@ -91,7 +91,6 @@ protected void onCreate(Bundle savedInstanceState) {
9191
binding = PasscodelockBinding.inflate(getLayoutInflater());
9292
setContentView(binding.getRoot());
9393

94-
9594
viewThemeUtils.platform.colorTextButtons(binding.cancel);
9695

9796
passCodeEditTexts[0] = binding.txt0;
@@ -105,7 +104,6 @@ protected void onCreate(Bundle savedInstanceState) {
105104

106105
passCodeEditTexts[0].requestFocus();
107106

108-
109107
Window window = getWindow();
110108
if (window != null) {
111109
window.setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
@@ -125,7 +123,7 @@ protected void onCreate(Bundle savedInstanceState) {
125123
passCodeDigits = savedInstanceState.getStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS);
126124
}
127125
if (confirmingPassCode) {
128-
// the app was in the passcodeconfirmation
126+
// the app was in the passcode confirmation
129127
requestPassCodeConfirmation();
130128
} else {
131129
// pass code preference has just been activated in SettingsActivity;
@@ -158,12 +156,7 @@ protected void onCreate(Bundle savedInstanceState) {
158156
protected void setCancelButtonEnabled(boolean enabled) {
159157
if (enabled) {
160158
binding.cancel.setVisibility(View.VISIBLE);
161-
binding.cancel.setOnClickListener(new OnClickListener() {
162-
@Override
163-
public void onClick(View v) {
164-
finish();
165-
}
166-
});
159+
binding.cancel.setOnClickListener(v -> finish());
167160
} else {
168161
binding.cancel.setVisibility(View.INVISIBLE);
169162
binding.cancel.setOnClickListener(null);
@@ -179,20 +172,18 @@ public PasscodelockBinding getBinding() {
179172
* Binds the appropriate listeners to the input boxes receiving each digit of the pass code.
180173
*/
181174
protected void setTextListeners() {
182-
passCodeEditTexts[0].addTextChangedListener(new PassCodeDigitTextWatcher(0, false));
183-
passCodeEditTexts[1].addTextChangedListener(new PassCodeDigitTextWatcher(1, false));
184-
passCodeEditTexts[2].addTextChangedListener(new PassCodeDigitTextWatcher(2, false));
185-
passCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true));
186-
187-
setOnKeyListener(1);
188-
setOnKeyListener(2);
189-
setOnKeyListener(3);
175+
for (int i = 0; i < passCodeEditTexts.length; i++) {
176+
final PassCodeEditText editText = passCodeEditTexts[i];
177+
boolean isLast = (i == 3);
190178

191-
passCodeEditTexts[1].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(1));
192-
193-
passCodeEditTexts[2].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(2));
179+
editText.addTextChangedListener(new PassCodeDigitTextWatcher(i, isLast));
180+
if (i > 0) {
181+
setOnKeyListener(i);
182+
}
194183

195-
passCodeEditTexts[3].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(3));
184+
int finalIndex = i;
185+
editText.setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(finalIndex));
186+
}
196187
}
197188

198189
private void onPassCodeEditTextFocusChange(final int passCodeIndex) {
@@ -265,9 +256,7 @@ private void processFullPassCode() {
265256
savePassCodeAndExit();
266257

267258
} else {
268-
showErrorAndRestart(
269-
R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE
270-
);
259+
showErrorAndRestart(R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE);
271260
}
272261
}
273262
}
@@ -279,13 +268,11 @@ private void hideSoftKeyboard() {
279268
(InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
280269
inputMethodManager.hideSoftInputFromWindow(
281270
focusedView.getWindowToken(),
282-
0
283-
);
271+
0);
284272
}
285273
}
286274

287-
private void showErrorAndRestart(int errorMessage, int headerMessage,
288-
int explanationVisibility) {
275+
private void showErrorAndRestart(int errorMessage, int headerMessage, int explanationVisibility) {
289276
Arrays.fill(passCodeDigits, null);
290277
Snackbar.make(findViewById(android.R.id.content), getString(errorMessage), Snackbar.LENGTH_LONG).show();
291278
binding.header.setText(headerMessage); // TODO check if really needed
@@ -312,8 +299,6 @@ protected void requestPassCodeConfirmation() {
312299
* @return 'True' if entered pass code equals to the saved one.
313300
*/
314301
protected boolean checkPassCode() {
315-
316-
317302
String[] savedPassCodeDigits = preferences.getPassCode();
318303

319304
boolean result = true;
@@ -331,11 +316,13 @@ protected boolean checkPassCode() {
331316
protected boolean confirmPassCode() {
332317
confirmingPassCode = false;
333318

334-
boolean result = true;
335-
for (int i = 0; i < passCodeEditTexts.length && result; i++) {
336-
result = passCodeEditTexts[i].getText().toString().equals(passCodeDigits[i]);
319+
for (int i = 0; i < passCodeEditTexts.length; i++) {
320+
Editable passCodeText = passCodeEditTexts[i].getText();
321+
if (passCodeText == null || !passCodeText.toString().equals(passCodeDigits[i])) {
322+
return false;
323+
}
337324
}
338-
return result;
325+
return true;
339326
}
340327

341328
/**
@@ -401,7 +388,7 @@ private void showDelay() {
401388
@Override
402389
public void run() {
403390
try {
404-
Thread.sleep(delay * 1000);
391+
Thread.sleep(delay * 1000L);
405392

406393
runOnUiThread(() -> {
407394
binding.explanation.setVisibility(View.INVISIBLE);
@@ -418,7 +405,6 @@ public void run() {
418405
}
419406
}
420407

421-
422408
@Override
423409
public void onSaveInstanceState(@NonNull Bundle outState) {
424410
super.onSaveInstanceState(outState);
@@ -440,6 +426,7 @@ private class PassCodeDigitTextWatcher implements TextWatcher {
440426
PassCodeDigitTextWatcher(int index, boolean lastOne) {
441427
mIndex = index;
442428
mLastOne = lastOne;
429+
443430
if (mIndex < 0) {
444431
throw new IllegalArgumentException(
445432
"Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() +
@@ -463,12 +450,17 @@ private int next() {
463450
public void afterTextChanged(Editable s) {
464451
if (s.length() > 0) {
465452
if (!confirmingPassCode) {
466-
passCodeDigits[mIndex] = passCodeEditTexts[mIndex].getText().toString();
453+
Editable passCodeText = passCodeEditTexts[mIndex].getText();
454+
455+
if (passCodeText != null) {
456+
passCodeDigits[mIndex] = passCodeText.toString();
457+
}
467458
}
468-
passCodeEditTexts[next()].requestFocus();
469459

470460
if (mLastOne) {
471461
processFullPassCode();
462+
} else {
463+
passCodeEditTexts[next()].requestFocus();
472464
}
473465

474466
} else {
@@ -477,13 +469,10 @@ public void afterTextChanged(Editable s) {
477469
}
478470

479471
@Override
480-
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
481-
// nothing to do
482-
}
472+
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
483473

484474
@Override
485-
public void onTextChanged(CharSequence s, int start, int before, int count) {
486-
// nothing to do
487-
}
475+
public void onTextChanged(CharSequence s, int start, int before, int count) {}
488476
}
477+
489478
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Nextcloud Android client application
3+
*
4+
* @author Alper Ozturk
5+
* Copyright (C) 2023 Alper Ozturk
6+
* Copyright (C) 2023 Nextcloud GmbH
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as published by
10+
* the Free Software Foundation, either version 3 of the License, or
11+
* (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
20+
*/
21+
package com.owncloud.android.ui.components
22+
23+
import android.annotation.SuppressLint
24+
import android.content.Context
25+
import android.util.AttributeSet
26+
import android.view.KeyEvent
27+
import android.view.MotionEvent
28+
import android.view.View
29+
import androidx.appcompat.widget.AppCompatEditText
30+
31+
@SuppressLint("ClickableViewAccessibility")
32+
class PassCodeEditText(context: Context, attrs: AttributeSet?) : AppCompatEditText(context, attrs) {
33+
34+
init {
35+
disableFocusChangeViaTap()
36+
}
37+
38+
private fun disableFocusChangeViaTap() {
39+
setSelectAllOnFocus(false)
40+
setTextIsSelectable(false)
41+
setOnTouchListener { _: View?, _: MotionEvent? -> true }
42+
}
43+
44+
override fun onKeyPreIme(keyCode: Int, event: KeyEvent): Boolean {
45+
val isBackButtonPressed = (event.keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP)
46+
if (isBackButtonPressed) {
47+
// Override default behaviour and prevent dismissing the keyboard
48+
return true
49+
}
50+
return super.dispatchKeyEvent(event)
51+
}
52+
}

app/src/main/res/layout/passcodelock.xml

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -69,41 +69,26 @@
6969
android:layout_height="wrap_content"
7070
android:gravity="center_horizontal">
7171

72-
<com.google.android.material.textfield.TextInputEditText
72+
<com.owncloud.android.ui.components.PassCodeEditText
7373
android:id="@+id/txt0"
7474
style="@style/PassCodeStyle"
75-
android:cursorVisible="false"
76-
android:focusable="true"
77-
android:hint="@string/hidden_character"
78-
android:imeOptions="flagNoExtractUi"
7975
android:importantForAutofill="no"
8076
tools:text="123">
77+
</com.owncloud.android.ui.components.PassCodeEditText>
8178

82-
<requestFocus />
83-
</com.google.android.material.textfield.TextInputEditText>
84-
85-
<com.google.android.material.textfield.TextInputEditText
79+
<com.owncloud.android.ui.components.PassCodeEditText
8680
android:id="@+id/txt1"
8781
style="@style/PassCodeStyle"
88-
android:cursorVisible="false"
89-
android:hint="@string/hidden_character"
90-
android:imeOptions="flagNoExtractUi"
9182
android:importantForAutofill="no" />
9283

93-
<com.google.android.material.textfield.TextInputEditText
84+
<com.owncloud.android.ui.components.PassCodeEditText
9485
android:id="@+id/txt2"
9586
style="@style/PassCodeStyle"
96-
android:cursorVisible="false"
97-
android:hint="@string/hidden_character"
98-
android:imeOptions="flagNoExtractUi"
9987
android:importantForAutofill="no" />
10088

101-
<com.google.android.material.textfield.TextInputEditText
89+
<com.owncloud.android.ui.components.PassCodeEditText
10290
android:id="@+id/txt3"
10391
style="@style/PassCodeStyle"
104-
android:cursorVisible="false"
105-
android:hint="@string/hidden_character"
106-
android:imeOptions="flagNoExtractUi"
10792
android:importantForAutofill="no" />
10893
</LinearLayout>
10994

app/src/main/res/values/styles.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,11 @@
324324
</style>
325325

326326
<style name="PassCodeStyle">
327+
<item name="android:hint">@string/hidden_character</item>
327328
<item name="android:layout_width">50dp</item>
328329
<item name="android:layout_height">50dp</item>
329330
<item name="android:gravity">center</item>
331+
<item name="android:cursorVisible">false</item>
330332
<item name="android:layout_margin">10dp</item>
331333
<item name="android:inputType">numberDecimal</item>
332334
<item name="android:numeric">decimal</item>

0 commit comments

Comments
 (0)