/* Copyright (C) 2022-2024 José Rebelo This file is part of Gadgetbridge. Gadgetbridge 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. Gadgetbridge 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 nodomain.freeyourgadget.gadgetbridge.capabilities.password; import android.content.Context; import android.text.Editable; import android.text.InputFilter; import android.text.InputType; import android.text.Spanned; import android.text.TextWatcher; import android.widget.EditText; import androidx.annotation.NonNull; import androidx.preference.EditTextPreference; import java.util.ArrayList; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler; public class PasswordCapabilityImpl { public static final String PREF_PASSWORD = "pref_password"; public static final String PREF_PASSWORD_ENABLED = "pref_password_enabled"; public enum Mode { NONE, NUMBERS_4_DIGITS_0_TO_9, NUMBERS_4_DIGITS_1_TO_4, NUMBERS_6, } public void registerPreferences(final Context context, final Mode mode, final DeviceSpecificSettingsHandler handler) { if (mode == Mode.NONE) { return; } final EditTextPreference password = handler.findPreference(PREF_PASSWORD); if (password == null) { return; } handler.addPreferenceHandlerFor(PREF_PASSWORD); handler.addPreferenceHandlerFor(PREF_PASSWORD_ENABLED); switch (mode) { case NUMBERS_6: password.setSummary(R.string.prefs_password_6_digits_0_to_9_summary); break; case NUMBERS_4_DIGITS_0_TO_9: password.setSummary(R.string.prefs_password_4_digits_0_to_9_summary); break; case NUMBERS_4_DIGITS_1_TO_4: password.setSummary(R.string.prefs_password_4_digits_1_to_4_summary); break; default: break; } password.setOnBindEditTextListener(new EditTextPreference.OnBindEditTextListener() { @Override public void onBindEditText(@NonNull final EditText editText) { final int expectedLength; final List inputFilters = new ArrayList<>(); switch (mode) { case NUMBERS_6: password.setSummary(R.string.prefs_password_6_digits_0_to_9_summary); editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD); expectedLength = 6; break; case NUMBERS_4_DIGITS_0_TO_9: password.setSummary(R.string.prefs_password_4_digits_0_to_9_summary); editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD); expectedLength = 4; break; case NUMBERS_4_DIGITS_1_TO_4: password.setSummary(R.string.prefs_password_4_digits_1_to_4_summary); editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD); expectedLength = 4; inputFilters.add(new InputFilter_Digits_1to4()); break; default: editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); expectedLength = -1; break; } if (expectedLength != -1) { inputFilters.add(new InputFilter.LengthFilter(expectedLength)); } editText.setSelection(editText.getText().length()); editText.setFilters(inputFilters.toArray(new InputFilter[0])); editText.addTextChangedListener(new ExpectedLengthTextWatcher(editText, expectedLength)); } }); } private static class InputFilter_Digits_1to4 implements InputFilter { @Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { for (int i = start; i < end; i++) { if (!Character.isDigit(source.charAt(i))) { return ""; } if (source.charAt(i) < '1' || source.charAt(i) > '4') { return ""; } } return null; } } private static class ExpectedLengthTextWatcher implements TextWatcher { private final EditText editText; private final int expectedLength; private ExpectedLengthTextWatcher(final EditText editText, final int expectedLength) { this.editText = editText; this.expectedLength = expectedLength; } @Override public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) { } @Override public void onTextChanged(final CharSequence s, final int start, final int before, final int count) { } @Override public void afterTextChanged(final Editable editable) { editText.getRootView().findViewById(android.R.id.button1) .setEnabled(expectedLength == -1 || editable.length() == expectedLength); } } }