Disable keyboard suggestions when typing PIN.

Converts `PinKeyboardType` to Kotlin and introduces methods to consistently configure PIN entry fields throughout the app, including a fix to disable keyboard suggestions.
This commit is contained in:
jeffrey-signal
2025-09-10 14:20:46 -04:00
committed by GitHub
parent 179bb6e1da
commit 79ee14826d
11 changed files with 187 additions and 251 deletions

View File

@@ -3,13 +3,11 @@ package org.thoughtcrime.securesms.lock;
import android.content.Context;
import android.content.Intent;
import android.text.Editable;
import android.text.InputType;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.method.PasswordTransformationMethod;
import android.text.style.ClickableSpan;
import android.util.DisplayMetrics;
import android.view.Display;
@@ -74,15 +72,7 @@ public final class SignalPinReminderDialog {
ViewUtil.focusAndShowKeyboard(pinEditText);
switch (SignalStore.pin().getKeyboardType()) {
case NUMERIC:
pinEditText.setInputType(InputType.TYPE_CLASS_NUMBER);
break;
case ALPHA_NUMERIC:
pinEditText.setInputType(InputType.TYPE_CLASS_TEXT );
break;
}
pinEditText.setTransformationMethod(PasswordTransformationMethod.getInstance());
SignalStore.pin().getKeyboardType().applyInputTypeTo(pinEditText);
ClickableSpan clickableSpan = new ClickableSpan() {
@Override

View File

@@ -2,8 +2,6 @@ package org.thoughtcrime.securesms.lock.v2;
import android.content.Intent;
import android.os.Bundle;
import android.text.InputType;
import android.text.method.PasswordTransformationMethod;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -71,9 +69,8 @@ public abstract class BaseSvrPinFragment<ViewModel extends BaseSvrPinViewModel>
});
viewModel.getKeyboard().observe(getViewLifecycleOwner(), keyboardType -> {
updateKeyboard(keyboardType);
keyboardType.applyTo(input, keyboardToggle);
keyboardToggle.setText(resolveKeyboardToggleText(keyboardType));
keyboardToggle.setIconResource(keyboardType.getOther().getIconResource());
});
description.setOnLinkClickListener(v -> {
@@ -190,15 +187,8 @@ public abstract class BaseSvrPinFragment<ViewModel extends BaseSvrPinViewModel>
return true;
}
private void updateKeyboard(@NonNull PinKeyboardType keyboard) {
boolean isAlphaNumeric = keyboard == PinKeyboardType.ALPHA_NUMERIC;
input.setInputType(isAlphaNumeric ? InputType.TYPE_CLASS_TEXT : InputType.TYPE_CLASS_NUMBER);
input.setTransformationMethod(PasswordTransformationMethod.getInstance());
}
private @StringRes int resolveKeyboardToggleText(@NonNull PinKeyboardType keyboard) {
if (keyboard == PinKeyboardType.ALPHA_NUMERIC) {
private @StringRes int resolveKeyboardToggleText(@NonNull PinKeyboardType keyboardType) {
if (keyboardType == PinKeyboardType.ALPHA_NUMERIC) {
return R.string.BaseKbsPinFragment__create_numeric_pin;
} else {
return R.string.BaseKbsPinFragment__create_alphanumeric_pin;

View File

@@ -1,40 +0,0 @@
package org.thoughtcrime.securesms.lock.v2;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.R;
public enum PinKeyboardType {
NUMERIC("numeric"),
ALPHA_NUMERIC("alphaNumeric");
private final String code;
PinKeyboardType(String code) {
this.code = code;
}
public PinKeyboardType getOther() {
if (this == NUMERIC) return ALPHA_NUMERIC;
else return NUMERIC;
}
public String getCode() {
return code;
}
public static PinKeyboardType fromCode(@Nullable String code) {
for (PinKeyboardType type : PinKeyboardType.values()) {
if (type.code.equals(code)) {
return type;
}
}
return NUMERIC;
}
public int getIconResource() {
if (this == ALPHA_NUMERIC) return R.drawable.ic_keyboard_24;
else return R.drawable.ic_number_pad_conversation_filter_24;
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.lock.v2
import android.text.InputType
import android.text.method.PasswordTransformationMethod
import android.widget.EditText
import com.google.android.material.button.MaterialButton
import org.thoughtcrime.securesms.R
/**
* The available keyboard input types for Signal PIN entry.
*/
enum class PinKeyboardType(val code: String) {
NUMERIC("numeric"),
ALPHA_NUMERIC("alphaNumeric");
companion object {
/**
* Gets the PinKeyboardType that is associated with a string code representation.
*/
@JvmStatic
fun fromCode(code: String?): PinKeyboardType = entries.firstOrNull { it.code == code } ?: NUMERIC
/**
* Gets the keyboard type that is associated with an [EditText]'s current input type.
*/
@JvmStatic
fun fromEditText(editText: EditText): PinKeyboardType = when {
(editText.inputType and InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_NUMBER -> NUMERIC
else -> ALPHA_NUMERIC
}
}
private val inputType: Int by lazy {
when (this) {
NUMERIC -> InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD
ALPHA_NUMERIC -> InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
}
}
private val toggleIconResource: Int by lazy {
when (this) {
NUMERIC -> R.drawable.ic_number_pad_conversation_filter_24
ALPHA_NUMERIC -> R.drawable.ic_keyboard_24
}
}
/**
* Gets the opposite keyboard type to the current one.
*/
val other: PinKeyboardType
get() {
return when (this) {
NUMERIC -> ALPHA_NUMERIC
ALPHA_NUMERIC -> NUMERIC
}
}
/**
* Configures an [EditText] and toggle button for this keyboard type.
*/
fun applyTo(pinEditText: EditText, toggleTypeButton: MaterialButton) {
applyInputTypeTo(pinEditText)
applyToggleIconTo(toggleTypeButton)
}
/**
* Configures an [EditText] for this keyboard type.
*/
fun applyInputTypeTo(editText: EditText) {
val currentInputClass = editText.inputType and InputType.TYPE_MASK_CLASS
val desiredInputClass = this.inputType and InputType.TYPE_MASK_CLASS
if (currentInputClass != desiredInputClass) {
editText.getText().clear()
}
editText.inputType = this.inputType
editText.transformationMethod = PasswordTransformationMethod.getInstance()
}
private fun applyToggleIconTo(toggleTypeButton: MaterialButton) {
toggleTypeButton.setIconResource(this.other.toggleIconResource)
}
}