Loading src/com/android/settings/inputmethod/InputSettingPreferenceController.java +8 −127 Original line number Diff line number Diff line Loading @@ -25,36 +25,29 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; import android.os.UserHandle; import android.view.View; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.SeekBar; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; import com.android.settings.keyboard.Flags; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import java.text.NumberFormat; import java.util.concurrent.TimeUnit; /** * Abstract class for toggle controllers of Keyboard input setting related function. */ public abstract class InputSettingPreferenceController extends TogglePreferenceController implements LifecycleObserver { private static final int CUSTOM_PROGRESS_INTERVAL = 100; private static final long MILLISECOND_IN_SECONDS = TimeUnit.SECONDS.toMillis(1); private final ContentResolver mContentResolver; protected final MetricsFeatureProvider mMetricsFeatureProvider; protected FragmentManager mFragmentManager; private final ContentObserver mContentObserver = new ContentObserver(new Handler(true)) { @Override public void onChange(boolean selfChange, Uri uri) { Loading @@ -72,13 +65,6 @@ public abstract class InputSettingPreferenceController extends TogglePreferenceC protected void updateInputSettingKeysValue(int thresholdTimeMillis) { } protected int getInputSettingKeysValue() { return 0; } protected void onCustomValueUpdated(int thresholdTimeMillis) { } public InputSettingPreferenceController(@NonNull Context context, @NonNull String preferenceKey) { super(context, preferenceKey); Loading @@ -86,6 +72,10 @@ public abstract class InputSettingPreferenceController extends TogglePreferenceC mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); } public void setFragment(Fragment fragment) { mFragmentManager = fragment.getParentFragmentManager(); } @Override public void updateState(@NonNull Preference preference) { super.updateState(preference); Loading Loading @@ -127,113 +117,4 @@ public abstract class InputSettingPreferenceController extends TogglePreferenceC private void unregisterSettingsObserver() { mContentResolver.unregisterContentObserver(mContentObserver); } protected void constructDialog(Context context, int titleRes, int subtitleRes) { mAlertDialog = new AlertDialog.Builder(context) .setView(R.layout.dialog_keyboard_a11y_input_setting_keys) .setPositiveButton(android.R.string.ok, (dialog, which) -> { RadioGroup radioGroup = mAlertDialog.findViewById( R.id.input_setting_keys_value_group); SeekBar seekbar = mAlertDialog.findViewById( R.id.input_setting_keys_value_custom_slider); RadioButton customRadioButton = mAlertDialog.findViewById( R.id.input_setting_keys_value_custom); int threshold; if (customRadioButton.isChecked()) { threshold = seekbar.getProgress() * CUSTOM_PROGRESS_INTERVAL; } else { int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId(); if (checkedRadioButtonId == R.id.input_setting_keys_value_600) { threshold = 600; } else if (checkedRadioButtonId == R.id.input_setting_keys_value_400) { threshold = 400; } else if (checkedRadioButtonId == R.id.input_setting_keys_value_200) { threshold = 200; } else { threshold = 0; } } updateInputSettingKeysValue(threshold); onCustomValueUpdated(threshold); }) .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()) .create(); mAlertDialog.setOnShowListener(dialog -> { RadioGroup cannedValueRadioGroup = mAlertDialog.findViewById( R.id.input_setting_keys_value_group); RadioButton customRadioButton = mAlertDialog.findViewById( R.id.input_setting_keys_value_custom); TextView customValueTextView = mAlertDialog.findViewById( R.id.input_setting_keys_value_custom_value); SeekBar customProgressBar = mAlertDialog.findViewById( R.id.input_setting_keys_value_custom_slider); TextView titleTextView = mAlertDialog.findViewById( R.id.input_setting_keys_dialog_title); TextView subTitleTextView = mAlertDialog.findViewById( R.id.input_setting_keys_dialog_subtitle); titleTextView.setText(titleRes); subTitleTextView.setText(subtitleRes); customProgressBar.incrementProgressBy(CUSTOM_PROGRESS_INTERVAL); customProgressBar.setProgress(1); View customValueView = mAlertDialog.findViewById( R.id.input_setting_keys_custom_value_option); customValueView.setOnClickListener(l -> customRadioButton.performClick()); customRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { cannedValueRadioGroup.clearCheck(); } customValueTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE); customValueTextView.setText( progressToThresholdInSecond(customProgressBar.getProgress())); customProgressBar.setVisibility(isChecked ? View.VISIBLE : View.GONE); buttonView.setChecked(isChecked); }); cannedValueRadioGroup.setOnCheckedChangeListener( (group, checkedId) -> customRadioButton.setChecked(false)); customProgressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { customValueTextView.setText(progressToThresholdInSecond(progress)); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton, customValueTextView, customProgressBar); }); } private static String progressToThresholdInSecond(int progress) { return NumberFormat.getInstance().format((float) progress * CUSTOM_PROGRESS_INTERVAL / MILLISECOND_IN_SECONDS); } private void initStateBasedOnThreshold(RadioGroup cannedValueRadioGroup, RadioButton customRadioButton, TextView customValueTextView, SeekBar customProgressBar) { int inputSettingKeysThreshold = getInputSettingKeysValue(); switch (inputSettingKeysThreshold) { case 600 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_600); case 400 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_400); case 0, 200 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_200); default -> { customValueTextView.setText( String.valueOf( (double) inputSettingKeysThreshold / MILLISECOND_IN_SECONDS)); customProgressBar.setProgress(inputSettingKeysThreshold / CUSTOM_PROGRESS_INTERVAL); customRadioButton.setChecked(true); } } } } src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java +4 −19 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.settings.inputmethod; import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE; import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_DISABLED; import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_ENABLED; Loading @@ -32,13 +31,13 @@ import androidx.lifecycle.LifecycleObserver; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settingslib.PrimarySwitchPreference; public class KeyboardAccessibilityBounceKeysController extends InputSettingPreferenceController implements LifecycleObserver { public static final int BOUNCE_KEYS_THRESHOLD = 500; private static final String KEY_TAG = "bounce_keys_dialog_tag"; @Nullable private PrimarySwitchPreference mPrimaryPreference; Loading @@ -46,8 +45,6 @@ public class KeyboardAccessibilityBounceKeysController extends public KeyboardAccessibilityBounceKeysController(@NonNull Context context, @NonNull String key) { super(context, key); constructDialog(context, R.string.bounce_keys_dialog_title, R.string.bounce_keys_dialog_subtitle); } @Override Loading @@ -65,12 +62,11 @@ public class KeyboardAccessibilityBounceKeysController extends @Override public boolean handlePreferenceTreeClick(@NonNull Preference preference) { if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { if (!TextUtils.equals(preference.getKey(), getPreferenceKey()) || mFragmentManager == null) { return false; } if (mAlertDialog != null) { mAlertDialog.show(); } KeyboardAccessibilityBounceKeysDialogFragment.getInstance().show(mFragmentManager, KEY_TAG); return true; } Loading @@ -87,12 +83,6 @@ public class KeyboardAccessibilityBounceKeysController extends return true; } @Override protected void onCustomValueUpdated(int thresholdTimeMillis) { mMetricsFeatureProvider.action(mContext, ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE, thresholdTimeMillis); } @Override protected void onInputSettingUpdated() { if (mPrimaryPreference != null) { Loading @@ -111,9 +101,4 @@ public class KeyboardAccessibilityBounceKeysController extends protected void updateInputSettingKeysValue(int thresholdTimeMillis) { InputSettings.setAccessibilityBounceKeysThreshold(mContext, thresholdTimeMillis); } @Override protected int getInputSettingKeysValue() { return InputSettings.getAccessibilityBounceKeysThreshold(mContext); } } src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysDialogFragment.java 0 → 100644 +54 −0 Original line number Diff line number Diff line /* * Copyright 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.inputmethod; import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE; import android.hardware.input.InputSettings; import android.os.Bundle; import com.android.settings.R; public class KeyboardAccessibilityBounceKeysDialogFragment extends KeyboardAccessibilityKeysDialogFragment { static KeyboardAccessibilityBounceKeysDialogFragment getInstance() { final KeyboardAccessibilityBounceKeysDialogFragment result = new KeyboardAccessibilityBounceKeysDialogFragment(); Bundle bundle = new Bundle(); bundle.putInt(EXTRA_TITLE_RES, R.string.bounce_keys_dialog_title); bundle.putInt(EXTRA_SUBTITLE_RES, R.string.bounce_keys_dialog_subtitle); result.setArguments(bundle); return result; } @Override protected void updateInputSettingKeysValue(int thresholdTimeMillis) { InputSettings.setAccessibilityBounceKeysThreshold(getContext(), thresholdTimeMillis); } @Override protected void onCustomValueUpdated(int thresholdTimeMillis) { mMetricsFeatureProvider.action(getContext(), ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE, thresholdTimeMillis); } @Override protected int getInputSettingKeysValue() { return InputSettings.getAccessibilityBounceKeysThreshold(getContext()); } } src/com/android/settings/inputmethod/KeyboardAccessibilityKeysDialogFragment.java 0 → 100644 +187 −0 Original line number Diff line number Diff line /* * Copyright 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.inputmethod; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.SeekBar; import android.widget.TextView; import androidx.fragment.app.DialogFragment; import com.android.settings.R; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.jspecify.annotations.Nullable; import java.util.concurrent.TimeUnit; public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFragment { private static final int CUSTOM_PROGRESS_INTERVAL = 100; private static final long MILLISECOND_IN_SECONDS = TimeUnit.SECONDS.toMillis(1); protected static final String EXTRA_TITLE_RES = "extra_title_res"; protected static final String EXTRA_SUBTITLE_RES = "extra_subtitle_res"; protected final MetricsFeatureProvider mMetricsFeatureProvider; public KeyboardAccessibilityKeysDialogFragment() { mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); } protected void updateInputSettingKeysValue(int thresholdTimeMillis) { } protected void onCustomValueUpdated(int thresholdTimeMillis) { } protected int getInputSettingKeysValue() { return 0; } @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { super.onCreateDialog(savedInstanceState); int titleRes = getArguments().getInt(EXTRA_TITLE_RES); int subtitleRes = getArguments().getInt(EXTRA_SUBTITLE_RES); Activity activity = getActivity(); View dialoglayout = LayoutInflater.from(activity).inflate( R.layout.dialog_keyboard_a11y_input_setting_keys, null); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity); dialogBuilder.setView(dialoglayout); dialogBuilder.setPositiveButton(android.R.string.ok, (dialog, which) -> { RadioGroup radioGroup = dialoglayout.findViewById( R.id.input_setting_keys_value_group); SeekBar seekbar = dialoglayout.findViewById( R.id.input_setting_keys_value_custom_slider); RadioButton customRadioButton = dialoglayout.findViewById( R.id.input_setting_keys_value_custom); int threshold; if (customRadioButton.isChecked()) { threshold = seekbar.getProgress() * CUSTOM_PROGRESS_INTERVAL; } else { int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId(); if (checkedRadioButtonId == R.id.input_setting_keys_value_600) { threshold = 600; } else if (checkedRadioButtonId == R.id.input_setting_keys_value_400) { threshold = 400; } else if (checkedRadioButtonId == R.id.input_setting_keys_value_200) { threshold = 200; } else { threshold = 0; } } updateInputSettingKeysValue(threshold); onCustomValueUpdated(threshold); }) .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()); AlertDialog accessibilityKeyDialog = dialogBuilder.create(); accessibilityKeyDialog.setOnShowListener(dialog -> { RadioGroup cannedValueRadioGroup = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_value_group); RadioButton customRadioButton = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_value_custom); TextView customValueTextView = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_value_custom_value); SeekBar customProgressBar = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_value_custom_slider); TextView titleTextView = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_dialog_title); TextView subTitleTextView = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_dialog_subtitle); titleTextView.setText(titleRes); subTitleTextView.setText(subtitleRes); customProgressBar.incrementProgressBy(CUSTOM_PROGRESS_INTERVAL); customProgressBar.setProgress(1); View customValueView = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_custom_value_option); customValueView.setOnClickListener(l -> customRadioButton.performClick()); customRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { cannedValueRadioGroup.clearCheck(); } customValueTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE); customValueTextView.setText( progressToThresholdInSecond(customProgressBar.getProgress())); customProgressBar.setVisibility(isChecked ? View.VISIBLE : View.GONE); buttonView.setChecked(isChecked); }); cannedValueRadioGroup.setOnCheckedChangeListener( (group, checkedId) -> customRadioButton.setChecked(false)); customProgressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { customValueTextView.setText(progressToThresholdInSecond(progress)); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton, customValueTextView, customProgressBar); }); final Window window = accessibilityKeyDialog.getWindow(); window.setType(TYPE_SYSTEM_DIALOG); return accessibilityKeyDialog; } private static String progressToThresholdInSecond(int progress) { return String.valueOf((double) progress * CUSTOM_PROGRESS_INTERVAL / MILLISECOND_IN_SECONDS); } private void initStateBasedOnThreshold(RadioGroup cannedValueRadioGroup, RadioButton customRadioButton, TextView customValueTextView, SeekBar customProgressBar) { int inputSettingKeysThreshold = getInputSettingKeysValue(); switch (inputSettingKeysThreshold) { case 600 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_600); case 400 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_400); case 0, 200 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_200); default -> { customValueTextView.setText( String.valueOf( (double) inputSettingKeysThreshold / MILLISECOND_IN_SECONDS)); customProgressBar.setProgress(inputSettingKeysThreshold / CUSTOM_PROGRESS_INTERVAL); customRadioButton.setChecked(true); } } } } src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysController.java +4 −18 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.settings.inputmethod; import static android.app.settings.SettingsEnums.ACTION_SLOW_KEYS_CUSTOM_VALUE_CHANGE; import static android.app.settings.SettingsEnums.ACTION_SLOW_KEYS_DISABLED; import static android.app.settings.SettingsEnums.ACTION_SLOW_KEYS_ENABLED; Loading @@ -32,20 +31,19 @@ import androidx.lifecycle.LifecycleObserver; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settingslib.PrimarySwitchPreference; public class KeyboardAccessibilitySlowKeysController extends InputSettingPreferenceController implements LifecycleObserver { public static final int SLOW_KEYS_THRESHOLD = 500; private static final String KEY_TAG = "slow_keys_dialog_tag"; @Nullable private PrimarySwitchPreference mPrimarySwitchPreference; public KeyboardAccessibilitySlowKeysController(@NonNull Context context, @NonNull String key) { super(context, key); constructDialog(context, R.string.slow_keys, R.string.slow_keys_summary); } @Override Loading Loading @@ -90,12 +88,11 @@ public class KeyboardAccessibilitySlowKeysController extends @Override public boolean handlePreferenceTreeClick(@NonNull Preference preference) { if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { if (!TextUtils.equals(preference.getKey(), getPreferenceKey()) || mFragmentManager == null) { return false; } if (mAlertDialog != null) { mAlertDialog.show(); } KeyboardAccessibilitySlowKeysDialogFragment.getInstance().show(mFragmentManager, KEY_TAG); return true; } Loading @@ -103,15 +100,4 @@ public class KeyboardAccessibilitySlowKeysController extends protected void updateInputSettingKeysValue(int thresholdTimeMillis) { InputSettings.setAccessibilitySlowKeysThreshold(mContext, thresholdTimeMillis); } @Override protected void onCustomValueUpdated(int thresholdTimeMillis) { mMetricsFeatureProvider.action(mContext, ACTION_SLOW_KEYS_CUSTOM_VALUE_CHANGE, thresholdTimeMillis); } @Override protected int getInputSettingKeysValue() { return InputSettings.getAccessibilitySlowKeysThreshold(mContext); } } Loading
src/com/android/settings/inputmethod/InputSettingPreferenceController.java +8 −127 Original line number Diff line number Diff line Loading @@ -25,36 +25,29 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; import android.os.UserHandle; import android.view.View; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.SeekBar; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; import com.android.settings.keyboard.Flags; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import java.text.NumberFormat; import java.util.concurrent.TimeUnit; /** * Abstract class for toggle controllers of Keyboard input setting related function. */ public abstract class InputSettingPreferenceController extends TogglePreferenceController implements LifecycleObserver { private static final int CUSTOM_PROGRESS_INTERVAL = 100; private static final long MILLISECOND_IN_SECONDS = TimeUnit.SECONDS.toMillis(1); private final ContentResolver mContentResolver; protected final MetricsFeatureProvider mMetricsFeatureProvider; protected FragmentManager mFragmentManager; private final ContentObserver mContentObserver = new ContentObserver(new Handler(true)) { @Override public void onChange(boolean selfChange, Uri uri) { Loading @@ -72,13 +65,6 @@ public abstract class InputSettingPreferenceController extends TogglePreferenceC protected void updateInputSettingKeysValue(int thresholdTimeMillis) { } protected int getInputSettingKeysValue() { return 0; } protected void onCustomValueUpdated(int thresholdTimeMillis) { } public InputSettingPreferenceController(@NonNull Context context, @NonNull String preferenceKey) { super(context, preferenceKey); Loading @@ -86,6 +72,10 @@ public abstract class InputSettingPreferenceController extends TogglePreferenceC mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); } public void setFragment(Fragment fragment) { mFragmentManager = fragment.getParentFragmentManager(); } @Override public void updateState(@NonNull Preference preference) { super.updateState(preference); Loading Loading @@ -127,113 +117,4 @@ public abstract class InputSettingPreferenceController extends TogglePreferenceC private void unregisterSettingsObserver() { mContentResolver.unregisterContentObserver(mContentObserver); } protected void constructDialog(Context context, int titleRes, int subtitleRes) { mAlertDialog = new AlertDialog.Builder(context) .setView(R.layout.dialog_keyboard_a11y_input_setting_keys) .setPositiveButton(android.R.string.ok, (dialog, which) -> { RadioGroup radioGroup = mAlertDialog.findViewById( R.id.input_setting_keys_value_group); SeekBar seekbar = mAlertDialog.findViewById( R.id.input_setting_keys_value_custom_slider); RadioButton customRadioButton = mAlertDialog.findViewById( R.id.input_setting_keys_value_custom); int threshold; if (customRadioButton.isChecked()) { threshold = seekbar.getProgress() * CUSTOM_PROGRESS_INTERVAL; } else { int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId(); if (checkedRadioButtonId == R.id.input_setting_keys_value_600) { threshold = 600; } else if (checkedRadioButtonId == R.id.input_setting_keys_value_400) { threshold = 400; } else if (checkedRadioButtonId == R.id.input_setting_keys_value_200) { threshold = 200; } else { threshold = 0; } } updateInputSettingKeysValue(threshold); onCustomValueUpdated(threshold); }) .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()) .create(); mAlertDialog.setOnShowListener(dialog -> { RadioGroup cannedValueRadioGroup = mAlertDialog.findViewById( R.id.input_setting_keys_value_group); RadioButton customRadioButton = mAlertDialog.findViewById( R.id.input_setting_keys_value_custom); TextView customValueTextView = mAlertDialog.findViewById( R.id.input_setting_keys_value_custom_value); SeekBar customProgressBar = mAlertDialog.findViewById( R.id.input_setting_keys_value_custom_slider); TextView titleTextView = mAlertDialog.findViewById( R.id.input_setting_keys_dialog_title); TextView subTitleTextView = mAlertDialog.findViewById( R.id.input_setting_keys_dialog_subtitle); titleTextView.setText(titleRes); subTitleTextView.setText(subtitleRes); customProgressBar.incrementProgressBy(CUSTOM_PROGRESS_INTERVAL); customProgressBar.setProgress(1); View customValueView = mAlertDialog.findViewById( R.id.input_setting_keys_custom_value_option); customValueView.setOnClickListener(l -> customRadioButton.performClick()); customRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { cannedValueRadioGroup.clearCheck(); } customValueTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE); customValueTextView.setText( progressToThresholdInSecond(customProgressBar.getProgress())); customProgressBar.setVisibility(isChecked ? View.VISIBLE : View.GONE); buttonView.setChecked(isChecked); }); cannedValueRadioGroup.setOnCheckedChangeListener( (group, checkedId) -> customRadioButton.setChecked(false)); customProgressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { customValueTextView.setText(progressToThresholdInSecond(progress)); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton, customValueTextView, customProgressBar); }); } private static String progressToThresholdInSecond(int progress) { return NumberFormat.getInstance().format((float) progress * CUSTOM_PROGRESS_INTERVAL / MILLISECOND_IN_SECONDS); } private void initStateBasedOnThreshold(RadioGroup cannedValueRadioGroup, RadioButton customRadioButton, TextView customValueTextView, SeekBar customProgressBar) { int inputSettingKeysThreshold = getInputSettingKeysValue(); switch (inputSettingKeysThreshold) { case 600 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_600); case 400 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_400); case 0, 200 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_200); default -> { customValueTextView.setText( String.valueOf( (double) inputSettingKeysThreshold / MILLISECOND_IN_SECONDS)); customProgressBar.setProgress(inputSettingKeysThreshold / CUSTOM_PROGRESS_INTERVAL); customRadioButton.setChecked(true); } } } }
src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java +4 −19 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.settings.inputmethod; import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE; import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_DISABLED; import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_ENABLED; Loading @@ -32,13 +31,13 @@ import androidx.lifecycle.LifecycleObserver; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settingslib.PrimarySwitchPreference; public class KeyboardAccessibilityBounceKeysController extends InputSettingPreferenceController implements LifecycleObserver { public static final int BOUNCE_KEYS_THRESHOLD = 500; private static final String KEY_TAG = "bounce_keys_dialog_tag"; @Nullable private PrimarySwitchPreference mPrimaryPreference; Loading @@ -46,8 +45,6 @@ public class KeyboardAccessibilityBounceKeysController extends public KeyboardAccessibilityBounceKeysController(@NonNull Context context, @NonNull String key) { super(context, key); constructDialog(context, R.string.bounce_keys_dialog_title, R.string.bounce_keys_dialog_subtitle); } @Override Loading @@ -65,12 +62,11 @@ public class KeyboardAccessibilityBounceKeysController extends @Override public boolean handlePreferenceTreeClick(@NonNull Preference preference) { if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { if (!TextUtils.equals(preference.getKey(), getPreferenceKey()) || mFragmentManager == null) { return false; } if (mAlertDialog != null) { mAlertDialog.show(); } KeyboardAccessibilityBounceKeysDialogFragment.getInstance().show(mFragmentManager, KEY_TAG); return true; } Loading @@ -87,12 +83,6 @@ public class KeyboardAccessibilityBounceKeysController extends return true; } @Override protected void onCustomValueUpdated(int thresholdTimeMillis) { mMetricsFeatureProvider.action(mContext, ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE, thresholdTimeMillis); } @Override protected void onInputSettingUpdated() { if (mPrimaryPreference != null) { Loading @@ -111,9 +101,4 @@ public class KeyboardAccessibilityBounceKeysController extends protected void updateInputSettingKeysValue(int thresholdTimeMillis) { InputSettings.setAccessibilityBounceKeysThreshold(mContext, thresholdTimeMillis); } @Override protected int getInputSettingKeysValue() { return InputSettings.getAccessibilityBounceKeysThreshold(mContext); } }
src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysDialogFragment.java 0 → 100644 +54 −0 Original line number Diff line number Diff line /* * Copyright 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.inputmethod; import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE; import android.hardware.input.InputSettings; import android.os.Bundle; import com.android.settings.R; public class KeyboardAccessibilityBounceKeysDialogFragment extends KeyboardAccessibilityKeysDialogFragment { static KeyboardAccessibilityBounceKeysDialogFragment getInstance() { final KeyboardAccessibilityBounceKeysDialogFragment result = new KeyboardAccessibilityBounceKeysDialogFragment(); Bundle bundle = new Bundle(); bundle.putInt(EXTRA_TITLE_RES, R.string.bounce_keys_dialog_title); bundle.putInt(EXTRA_SUBTITLE_RES, R.string.bounce_keys_dialog_subtitle); result.setArguments(bundle); return result; } @Override protected void updateInputSettingKeysValue(int thresholdTimeMillis) { InputSettings.setAccessibilityBounceKeysThreshold(getContext(), thresholdTimeMillis); } @Override protected void onCustomValueUpdated(int thresholdTimeMillis) { mMetricsFeatureProvider.action(getContext(), ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE, thresholdTimeMillis); } @Override protected int getInputSettingKeysValue() { return InputSettings.getAccessibilityBounceKeysThreshold(getContext()); } }
src/com/android/settings/inputmethod/KeyboardAccessibilityKeysDialogFragment.java 0 → 100644 +187 −0 Original line number Diff line number Diff line /* * Copyright 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.inputmethod; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.SeekBar; import android.widget.TextView; import androidx.fragment.app.DialogFragment; import com.android.settings.R; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.jspecify.annotations.Nullable; import java.util.concurrent.TimeUnit; public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFragment { private static final int CUSTOM_PROGRESS_INTERVAL = 100; private static final long MILLISECOND_IN_SECONDS = TimeUnit.SECONDS.toMillis(1); protected static final String EXTRA_TITLE_RES = "extra_title_res"; protected static final String EXTRA_SUBTITLE_RES = "extra_subtitle_res"; protected final MetricsFeatureProvider mMetricsFeatureProvider; public KeyboardAccessibilityKeysDialogFragment() { mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); } protected void updateInputSettingKeysValue(int thresholdTimeMillis) { } protected void onCustomValueUpdated(int thresholdTimeMillis) { } protected int getInputSettingKeysValue() { return 0; } @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { super.onCreateDialog(savedInstanceState); int titleRes = getArguments().getInt(EXTRA_TITLE_RES); int subtitleRes = getArguments().getInt(EXTRA_SUBTITLE_RES); Activity activity = getActivity(); View dialoglayout = LayoutInflater.from(activity).inflate( R.layout.dialog_keyboard_a11y_input_setting_keys, null); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity); dialogBuilder.setView(dialoglayout); dialogBuilder.setPositiveButton(android.R.string.ok, (dialog, which) -> { RadioGroup radioGroup = dialoglayout.findViewById( R.id.input_setting_keys_value_group); SeekBar seekbar = dialoglayout.findViewById( R.id.input_setting_keys_value_custom_slider); RadioButton customRadioButton = dialoglayout.findViewById( R.id.input_setting_keys_value_custom); int threshold; if (customRadioButton.isChecked()) { threshold = seekbar.getProgress() * CUSTOM_PROGRESS_INTERVAL; } else { int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId(); if (checkedRadioButtonId == R.id.input_setting_keys_value_600) { threshold = 600; } else if (checkedRadioButtonId == R.id.input_setting_keys_value_400) { threshold = 400; } else if (checkedRadioButtonId == R.id.input_setting_keys_value_200) { threshold = 200; } else { threshold = 0; } } updateInputSettingKeysValue(threshold); onCustomValueUpdated(threshold); }) .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()); AlertDialog accessibilityKeyDialog = dialogBuilder.create(); accessibilityKeyDialog.setOnShowListener(dialog -> { RadioGroup cannedValueRadioGroup = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_value_group); RadioButton customRadioButton = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_value_custom); TextView customValueTextView = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_value_custom_value); SeekBar customProgressBar = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_value_custom_slider); TextView titleTextView = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_dialog_title); TextView subTitleTextView = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_dialog_subtitle); titleTextView.setText(titleRes); subTitleTextView.setText(subtitleRes); customProgressBar.incrementProgressBy(CUSTOM_PROGRESS_INTERVAL); customProgressBar.setProgress(1); View customValueView = accessibilityKeyDialog.findViewById( R.id.input_setting_keys_custom_value_option); customValueView.setOnClickListener(l -> customRadioButton.performClick()); customRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { cannedValueRadioGroup.clearCheck(); } customValueTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE); customValueTextView.setText( progressToThresholdInSecond(customProgressBar.getProgress())); customProgressBar.setVisibility(isChecked ? View.VISIBLE : View.GONE); buttonView.setChecked(isChecked); }); cannedValueRadioGroup.setOnCheckedChangeListener( (group, checkedId) -> customRadioButton.setChecked(false)); customProgressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { customValueTextView.setText(progressToThresholdInSecond(progress)); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton, customValueTextView, customProgressBar); }); final Window window = accessibilityKeyDialog.getWindow(); window.setType(TYPE_SYSTEM_DIALOG); return accessibilityKeyDialog; } private static String progressToThresholdInSecond(int progress) { return String.valueOf((double) progress * CUSTOM_PROGRESS_INTERVAL / MILLISECOND_IN_SECONDS); } private void initStateBasedOnThreshold(RadioGroup cannedValueRadioGroup, RadioButton customRadioButton, TextView customValueTextView, SeekBar customProgressBar) { int inputSettingKeysThreshold = getInputSettingKeysValue(); switch (inputSettingKeysThreshold) { case 600 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_600); case 400 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_400); case 0, 200 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_200); default -> { customValueTextView.setText( String.valueOf( (double) inputSettingKeysThreshold / MILLISECOND_IN_SECONDS)); customProgressBar.setProgress(inputSettingKeysThreshold / CUSTOM_PROGRESS_INTERVAL); customRadioButton.setChecked(true); } } } }
src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysController.java +4 −18 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.settings.inputmethod; import static android.app.settings.SettingsEnums.ACTION_SLOW_KEYS_CUSTOM_VALUE_CHANGE; import static android.app.settings.SettingsEnums.ACTION_SLOW_KEYS_DISABLED; import static android.app.settings.SettingsEnums.ACTION_SLOW_KEYS_ENABLED; Loading @@ -32,20 +31,19 @@ import androidx.lifecycle.LifecycleObserver; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settingslib.PrimarySwitchPreference; public class KeyboardAccessibilitySlowKeysController extends InputSettingPreferenceController implements LifecycleObserver { public static final int SLOW_KEYS_THRESHOLD = 500; private static final String KEY_TAG = "slow_keys_dialog_tag"; @Nullable private PrimarySwitchPreference mPrimarySwitchPreference; public KeyboardAccessibilitySlowKeysController(@NonNull Context context, @NonNull String key) { super(context, key); constructDialog(context, R.string.slow_keys, R.string.slow_keys_summary); } @Override Loading Loading @@ -90,12 +88,11 @@ public class KeyboardAccessibilitySlowKeysController extends @Override public boolean handlePreferenceTreeClick(@NonNull Preference preference) { if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { if (!TextUtils.equals(preference.getKey(), getPreferenceKey()) || mFragmentManager == null) { return false; } if (mAlertDialog != null) { mAlertDialog.show(); } KeyboardAccessibilitySlowKeysDialogFragment.getInstance().show(mFragmentManager, KEY_TAG); return true; } Loading @@ -103,15 +100,4 @@ public class KeyboardAccessibilitySlowKeysController extends protected void updateInputSettingKeysValue(int thresholdTimeMillis) { InputSettings.setAccessibilitySlowKeysThreshold(mContext, thresholdTimeMillis); } @Override protected void onCustomValueUpdated(int thresholdTimeMillis) { mMetricsFeatureProvider.action(mContext, ACTION_SLOW_KEYS_CUSTOM_VALUE_CHANGE, thresholdTimeMillis); } @Override protected int getInputSettingKeysValue() { return InputSettings.getAccessibilitySlowKeysThreshold(mContext); } }