Loading res/layout/dialog_a11y_bounce_key.xml→res/layout/dialog_keyboard_a11y_input_setting_keys.xml +16 −18 Original line number Diff line number Diff line Loading @@ -22,47 +22,45 @@ android:orientation="vertical"> <TextView android:id="@+id/bounce_key_dialog_title" android:id="@+id/input_setting_keys_dialog_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:textSize="20sp" android:gravity="center_horizontal" android:text="@string/bounce_keys_dialog_title" android:textColor="?android:attr/textColorPrimary" android:fontFamily="@*android:string/config_headlineFontFamilyMedium" /> <TextView android:id="@+id/bounce_key_dialog_subtitle" android:id="@+id/input_setting_keys_dialog_subtitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="26dp" android:layout_marginTop="8dp" android:textSize="16sp" android:gravity="center" android:text="@string/bounce_keys_dialog_subtitle" android:textColor="?android:attr/textColorSecondary" /> <RadioGroup android:id="@+id/bounce_key_value_group" android:id="@+id/input_setting_keys_value_group" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="20dp" android:layout_marginTop="16dp"> <RadioButton android:id="@+id/bounce_key_value_200" android:text="@string/bounce_keys_dialog_option_200" android:id="@+id/input_setting_keys_value_200" android:text="@string/input_setting_keys_dialog_option_200" android:paddingStart="12dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="start|center_vertical" android:background="@null"/> <RadioButton android:id="@+id/bounce_key_value_400" android:text="@string/bounce_keys_dialog_option_400" android:id="@+id/input_setting_keys_value_400" android:text="@string/input_setting_keys_dialog_option_400" android:paddingStart="12dp" android:layout_width="match_parent" android:layout_height="wrap_content" Loading @@ -70,8 +68,8 @@ android:layout_marginTop="12dp" android:background="@null"/> <RadioButton android:id="@+id/bounce_key_value_600" android:text="@string/bounce_keys_dialog_option_600" android:id="@+id/input_setting_keys_value_600" android:text="@string/input_setting_keys_dialog_option_600" android:paddingStart="12dp" android:layout_width="match_parent" android:layout_height="wrap_content" Loading @@ -85,14 +83,14 @@ android:layout_height="wrap_content" android:layout_marginVertical="12dp"> <RadioButton android:id="@+id/bounce_key_value_custom" android:id="@+id/input_setting_keys_value_custom" android:paddingStart="12dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:background="@null"/> <LinearLayout android:id="@+id/custom_value_option" android:id="@+id/input_setting_keys_custom_value_option" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" Loading @@ -100,15 +98,15 @@ android:gravity="center_vertical" android:paddingEnd="16dp"> <TextView android:id="@+id/bounce_key_value_custom_title" android:text="Custom" android:id="@+id/input_setting_keys_value_custom_title" android:text="@string/input_setting_keys_custom_title" android:textColor="?android:attr/textColorPrimary" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical"/> <TextView android:id="@+id/bounce_key_value_custom_value" android:text="custom value" android:id="@+id/input_setting_keys_value_custom_value" android:text="@string/input_setting_keys_custom_value" android:textColor="?android:attr/textColorPrimary" android:layout_width="match_parent" android:layout_height="wrap_content" Loading @@ -116,7 +114,7 @@ android:layout_marginTop="8dp" android:visibility="gone"/> <SeekBar android:id="@+id/bounce_key_value_custom_slider" android:id="@+id/input_setting_keys_value_custom_slider" android:paddingStart="8dp" android:paddingEnd="36dp" android:min="1" Loading res/values/strings.xml +11 −6 Original line number Diff line number Diff line Loading @@ -4525,12 +4525,17 @@ <string name="bounce_keys_dialog_title">Bounce key threshold</string> <!-- Subtitle for the 'Bounce keys' threshold dialog. [CHAR LIMIT=300] --> <string name="bounce_keys_dialog_subtitle">Choose the duration of time your keyboard ignores repeated key presses</string> <!-- Option title for the 'Bounce keys' threshold dialog for 200 millisecond. [CHAR LIMIT=35] --> <string name="bounce_keys_dialog_option_200">0.2s</string> <!-- Option title for the 'Bounce keys' threshold dialog for 400 millisecond. [CHAR LIMIT=35] --> <string name="bounce_keys_dialog_option_400">0.4s</string> <!-- Option title for the 'Bounce keys' threshold dialog for 600 millisecond. [CHAR LIMIT=35] --> <string name="bounce_keys_dialog_option_600">0.6s</string> <!-- Option title for the input setting keys threshold dialog for 200 millisecond. [CHAR LIMIT=35] --> <string name="input_setting_keys_dialog_option_200">0.2s</string> <!-- Option title for the input setting keys threshold dialog for 400 millisecond. [CHAR LIMIT=35] --> <string name="input_setting_keys_dialog_option_400">0.4s</string> <!-- Option title for the input setting keys threshold dialog for 600 millisecond. [CHAR LIMIT=35] --> <string name="input_setting_keys_dialog_option_600">0.6s</string> <!-- Option title for the input setting keys threshold dialog for custom value. [CHAR LIMIT=35] --> <string name="input_setting_keys_custom_title">Custom</string> <!-- Option subtitle for the input setting keys threshold dialog for custom value. [CHAR LIMIT=35] --> <string name="input_setting_keys_custom_value">custom value</string> <!-- Title for the 'Slow keys' preference switch. [CHAR LIMIT=35] --> <string name="slow_keys">Slow keys</string> <!-- Summary text for the 'Slow keys' preference sub-screen. [CHAR LIMIT=300] --> res/xml/physical_keyboard_a11y_settings.xml +7 −7 Original line number Diff line number Diff line Loading @@ -19,35 +19,35 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/keyboard_a11y_settings" android:key="physical_keyboard_a11y"> android:key="physical_keyboard_a11y_page"> <PreferenceCategory android:key="keyboard_a11y_category" android:key="keyboard_a11y_page_category" android:title="@string/keyboard_a11y_category"> <SwitchPreferenceCompat android:key="accessibility_sticky_keys" android:key="keyboard_a11y_page_sticky_keys" android:title="@string/sticky_keys" android:summary="@string/sticky_keys_summary" android:defaultValue="false" settings:controller="com.android.settings.inputmethod.KeyboardAccessibilityStickyKeysController"/> <com.android.settingslib.PrimarySwitchPreference android:key="accessibility_bounce_keys" android:key="keyboard_a11y_page_bounce_keys" android:title="@string/bounce_keys" android:summary="@string/bounce_keys_summary" android:defaultValue="false" settings:controller="com.android.settings.inputmethod.KeyboardAccessibilityBounceKeysController"/> <SwitchPreferenceCompat android:key="accessibility_slow_keys" <com.android.settingslib.PrimarySwitchPreference android:key="keyboard_a11y_page_slow_keys" android:title="@string/slow_keys" android:defaultValue="false" android:summary="@string/slow_keys_summary" settings:controller="com.android.settings.inputmethod.KeyboardAccessibilitySlowKeysController" /> <SwitchPreferenceCompat android:key="accessibility_mouse_keys" android:key="keyboard_a11y_page_mouse_keys" android:title="@string/mouse_keys" android:summary="@string/mouse_keys_summary" android:defaultValue="false" Loading src/com/android/settings/inputmethod/InputSettingPreferenceController.java +127 −0 Original line number Diff line number Diff line Loading @@ -25,20 +25,31 @@ 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.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 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; private final ContentObserver mContentObserver = new ContentObserver(new Handler(true)) { @Override Loading @@ -48,11 +59,19 @@ public abstract class InputSettingPreferenceController extends TogglePreferenceC } } }; protected AlertDialog mAlertDialog; protected abstract void onInputSettingUpdated(); protected abstract Uri getSettingUri(); protected void updateInputSettingKeysValue(int thresholdTimeMillis) { } protected int getInputSettingKeysValue() { return 0; } public InputSettingPreferenceController(@NonNull Context context, @NonNull String preferenceKey) { super(context, preferenceKey); Loading Loading @@ -100,4 +119,112 @@ 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); }) .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 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/KeyboardAccessibilityBounceKeysController.java +9 −101 Original line number Diff line number Diff line Loading @@ -21,15 +21,9 @@ import android.hardware.input.InputSettings; import android.net.Uri; import android.provider.Settings; import android.text.TextUtils; 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.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.lifecycle.LifecycleObserver; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; Loading @@ -37,23 +31,19 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settingslib.PrimarySwitchPreference; import java.util.concurrent.TimeUnit; public class KeyboardAccessibilityBounceKeysController extends InputSettingPreferenceController implements LifecycleObserver { private static final int CUSTOM_PROGRESS_INTERVAL = 100; private static final long MILLISECOND_IN_SECONDS = TimeUnit.SECONDS.toMillis(1); public static final int BOUNCE_KEYS_THRESHOLD = 500; private AlertDialog mAlertDialog; @Nullable private PrimarySwitchPreference mPrimaryPreference; public KeyboardAccessibilityBounceKeysController(@NonNull Context context, @NonNull String key) { super(context, key); constructDialog(context); constructDialog(context, R.string.bounce_keys_dialog_title, R.string.bounce_keys_dialog_subtitle); } @Override Loading Loading @@ -87,8 +77,7 @@ public class KeyboardAccessibilityBounceKeysController extends @Override public boolean setChecked(boolean isChecked) { InputSettings.setAccessibilityBounceKeysThreshold(mContext, isChecked ? BOUNCE_KEYS_THRESHOLD : 0); updateInputSettingKeysValue(isChecked ? BOUNCE_KEYS_THRESHOLD : 0); return true; } Loading @@ -106,94 +95,13 @@ public class KeyboardAccessibilityBounceKeysController extends Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS); } private void constructDialog(Context context) { mAlertDialog = new AlertDialog.Builder(context) .setView(R.layout.dialog_a11y_bounce_key) .setPositiveButton(android.R.string.ok, (dialog, which) -> { RadioGroup radioGroup = mAlertDialog.findViewById(R.id.bounce_key_value_group); SeekBar seekbar = mAlertDialog.findViewById( R.id.bounce_key_value_custom_slider); RadioButton customRadioButton = mAlertDialog.findViewById( R.id.bounce_key_value_custom); int threshold; if (customRadioButton.isChecked()) { threshold = seekbar.getProgress() * CUSTOM_PROGRESS_INTERVAL; } else { int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId(); threshold = checkedRadioButtonId == R.id.bounce_key_value_600 ? 600 : checkedRadioButtonId == R.id.bounce_key_value_400 ? 400 : checkedRadioButtonId == R.id.bounce_key_value_200 ? 200 : 0; } InputSettings.setAccessibilityBounceKeysThreshold(context, threshold); }) .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()) .create(); mAlertDialog.setOnShowListener(dialog -> { RadioGroup cannedValueRadioGroup = mAlertDialog.findViewById( R.id.bounce_key_value_group); RadioButton customRadioButton = mAlertDialog.findViewById(R.id.bounce_key_value_custom); TextView customValueTextView = mAlertDialog.findViewById( R.id.bounce_key_value_custom_value); SeekBar customProgressBar = mAlertDialog.findViewById( R.id.bounce_key_value_custom_slider); customProgressBar.incrementProgressBy(CUSTOM_PROGRESS_INTERVAL); customProgressBar.setProgress(1); View customValueView = mAlertDialog.findViewById(R.id.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)); protected void updateInputSettingKeysValue(int thresholdTimeMillis) { InputSettings.setAccessibilityBounceKeysThreshold(mContext, thresholdTimeMillis); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton, customValueTextView, customProgressBar); }); } 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 bounceKeysThreshold = InputSettings.getAccessibilityBounceKeysThreshold(mContext); switch (bounceKeysThreshold) { case 600 -> cannedValueRadioGroup.check(R.id.bounce_key_value_600); case 400 -> cannedValueRadioGroup.check(R.id.bounce_key_value_400); case 0, 200 -> cannedValueRadioGroup.check(R.id.bounce_key_value_200); default -> { customValueTextView.setText( String.valueOf( (double) bounceKeysThreshold / MILLISECOND_IN_SECONDS)); customProgressBar.setProgress(bounceKeysThreshold / CUSTOM_PROGRESS_INTERVAL); customRadioButton.setChecked(true); } } protected int getInputSettingKeysValue() { return InputSettings.getAccessibilityBounceKeysThreshold(mContext); } } Loading
res/layout/dialog_a11y_bounce_key.xml→res/layout/dialog_keyboard_a11y_input_setting_keys.xml +16 −18 Original line number Diff line number Diff line Loading @@ -22,47 +22,45 @@ android:orientation="vertical"> <TextView android:id="@+id/bounce_key_dialog_title" android:id="@+id/input_setting_keys_dialog_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:textSize="20sp" android:gravity="center_horizontal" android:text="@string/bounce_keys_dialog_title" android:textColor="?android:attr/textColorPrimary" android:fontFamily="@*android:string/config_headlineFontFamilyMedium" /> <TextView android:id="@+id/bounce_key_dialog_subtitle" android:id="@+id/input_setting_keys_dialog_subtitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="26dp" android:layout_marginTop="8dp" android:textSize="16sp" android:gravity="center" android:text="@string/bounce_keys_dialog_subtitle" android:textColor="?android:attr/textColorSecondary" /> <RadioGroup android:id="@+id/bounce_key_value_group" android:id="@+id/input_setting_keys_value_group" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="20dp" android:layout_marginTop="16dp"> <RadioButton android:id="@+id/bounce_key_value_200" android:text="@string/bounce_keys_dialog_option_200" android:id="@+id/input_setting_keys_value_200" android:text="@string/input_setting_keys_dialog_option_200" android:paddingStart="12dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="start|center_vertical" android:background="@null"/> <RadioButton android:id="@+id/bounce_key_value_400" android:text="@string/bounce_keys_dialog_option_400" android:id="@+id/input_setting_keys_value_400" android:text="@string/input_setting_keys_dialog_option_400" android:paddingStart="12dp" android:layout_width="match_parent" android:layout_height="wrap_content" Loading @@ -70,8 +68,8 @@ android:layout_marginTop="12dp" android:background="@null"/> <RadioButton android:id="@+id/bounce_key_value_600" android:text="@string/bounce_keys_dialog_option_600" android:id="@+id/input_setting_keys_value_600" android:text="@string/input_setting_keys_dialog_option_600" android:paddingStart="12dp" android:layout_width="match_parent" android:layout_height="wrap_content" Loading @@ -85,14 +83,14 @@ android:layout_height="wrap_content" android:layout_marginVertical="12dp"> <RadioButton android:id="@+id/bounce_key_value_custom" android:id="@+id/input_setting_keys_value_custom" android:paddingStart="12dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:background="@null"/> <LinearLayout android:id="@+id/custom_value_option" android:id="@+id/input_setting_keys_custom_value_option" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" Loading @@ -100,15 +98,15 @@ android:gravity="center_vertical" android:paddingEnd="16dp"> <TextView android:id="@+id/bounce_key_value_custom_title" android:text="Custom" android:id="@+id/input_setting_keys_value_custom_title" android:text="@string/input_setting_keys_custom_title" android:textColor="?android:attr/textColorPrimary" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical"/> <TextView android:id="@+id/bounce_key_value_custom_value" android:text="custom value" android:id="@+id/input_setting_keys_value_custom_value" android:text="@string/input_setting_keys_custom_value" android:textColor="?android:attr/textColorPrimary" android:layout_width="match_parent" android:layout_height="wrap_content" Loading @@ -116,7 +114,7 @@ android:layout_marginTop="8dp" android:visibility="gone"/> <SeekBar android:id="@+id/bounce_key_value_custom_slider" android:id="@+id/input_setting_keys_value_custom_slider" android:paddingStart="8dp" android:paddingEnd="36dp" android:min="1" Loading
res/values/strings.xml +11 −6 Original line number Diff line number Diff line Loading @@ -4525,12 +4525,17 @@ <string name="bounce_keys_dialog_title">Bounce key threshold</string> <!-- Subtitle for the 'Bounce keys' threshold dialog. [CHAR LIMIT=300] --> <string name="bounce_keys_dialog_subtitle">Choose the duration of time your keyboard ignores repeated key presses</string> <!-- Option title for the 'Bounce keys' threshold dialog for 200 millisecond. [CHAR LIMIT=35] --> <string name="bounce_keys_dialog_option_200">0.2s</string> <!-- Option title for the 'Bounce keys' threshold dialog for 400 millisecond. [CHAR LIMIT=35] --> <string name="bounce_keys_dialog_option_400">0.4s</string> <!-- Option title for the 'Bounce keys' threshold dialog for 600 millisecond. [CHAR LIMIT=35] --> <string name="bounce_keys_dialog_option_600">0.6s</string> <!-- Option title for the input setting keys threshold dialog for 200 millisecond. [CHAR LIMIT=35] --> <string name="input_setting_keys_dialog_option_200">0.2s</string> <!-- Option title for the input setting keys threshold dialog for 400 millisecond. [CHAR LIMIT=35] --> <string name="input_setting_keys_dialog_option_400">0.4s</string> <!-- Option title for the input setting keys threshold dialog for 600 millisecond. [CHAR LIMIT=35] --> <string name="input_setting_keys_dialog_option_600">0.6s</string> <!-- Option title for the input setting keys threshold dialog for custom value. [CHAR LIMIT=35] --> <string name="input_setting_keys_custom_title">Custom</string> <!-- Option subtitle for the input setting keys threshold dialog for custom value. [CHAR LIMIT=35] --> <string name="input_setting_keys_custom_value">custom value</string> <!-- Title for the 'Slow keys' preference switch. [CHAR LIMIT=35] --> <string name="slow_keys">Slow keys</string> <!-- Summary text for the 'Slow keys' preference sub-screen. [CHAR LIMIT=300] -->
res/xml/physical_keyboard_a11y_settings.xml +7 −7 Original line number Diff line number Diff line Loading @@ -19,35 +19,35 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/keyboard_a11y_settings" android:key="physical_keyboard_a11y"> android:key="physical_keyboard_a11y_page"> <PreferenceCategory android:key="keyboard_a11y_category" android:key="keyboard_a11y_page_category" android:title="@string/keyboard_a11y_category"> <SwitchPreferenceCompat android:key="accessibility_sticky_keys" android:key="keyboard_a11y_page_sticky_keys" android:title="@string/sticky_keys" android:summary="@string/sticky_keys_summary" android:defaultValue="false" settings:controller="com.android.settings.inputmethod.KeyboardAccessibilityStickyKeysController"/> <com.android.settingslib.PrimarySwitchPreference android:key="accessibility_bounce_keys" android:key="keyboard_a11y_page_bounce_keys" android:title="@string/bounce_keys" android:summary="@string/bounce_keys_summary" android:defaultValue="false" settings:controller="com.android.settings.inputmethod.KeyboardAccessibilityBounceKeysController"/> <SwitchPreferenceCompat android:key="accessibility_slow_keys" <com.android.settingslib.PrimarySwitchPreference android:key="keyboard_a11y_page_slow_keys" android:title="@string/slow_keys" android:defaultValue="false" android:summary="@string/slow_keys_summary" settings:controller="com.android.settings.inputmethod.KeyboardAccessibilitySlowKeysController" /> <SwitchPreferenceCompat android:key="accessibility_mouse_keys" android:key="keyboard_a11y_page_mouse_keys" android:title="@string/mouse_keys" android:summary="@string/mouse_keys_summary" android:defaultValue="false" Loading
src/com/android/settings/inputmethod/InputSettingPreferenceController.java +127 −0 Original line number Diff line number Diff line Loading @@ -25,20 +25,31 @@ 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.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 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; private final ContentObserver mContentObserver = new ContentObserver(new Handler(true)) { @Override Loading @@ -48,11 +59,19 @@ public abstract class InputSettingPreferenceController extends TogglePreferenceC } } }; protected AlertDialog mAlertDialog; protected abstract void onInputSettingUpdated(); protected abstract Uri getSettingUri(); protected void updateInputSettingKeysValue(int thresholdTimeMillis) { } protected int getInputSettingKeysValue() { return 0; } public InputSettingPreferenceController(@NonNull Context context, @NonNull String preferenceKey) { super(context, preferenceKey); Loading Loading @@ -100,4 +119,112 @@ 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); }) .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 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/KeyboardAccessibilityBounceKeysController.java +9 −101 Original line number Diff line number Diff line Loading @@ -21,15 +21,9 @@ import android.hardware.input.InputSettings; import android.net.Uri; import android.provider.Settings; import android.text.TextUtils; 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.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.lifecycle.LifecycleObserver; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; Loading @@ -37,23 +31,19 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settingslib.PrimarySwitchPreference; import java.util.concurrent.TimeUnit; public class KeyboardAccessibilityBounceKeysController extends InputSettingPreferenceController implements LifecycleObserver { private static final int CUSTOM_PROGRESS_INTERVAL = 100; private static final long MILLISECOND_IN_SECONDS = TimeUnit.SECONDS.toMillis(1); public static final int BOUNCE_KEYS_THRESHOLD = 500; private AlertDialog mAlertDialog; @Nullable private PrimarySwitchPreference mPrimaryPreference; public KeyboardAccessibilityBounceKeysController(@NonNull Context context, @NonNull String key) { super(context, key); constructDialog(context); constructDialog(context, R.string.bounce_keys_dialog_title, R.string.bounce_keys_dialog_subtitle); } @Override Loading Loading @@ -87,8 +77,7 @@ public class KeyboardAccessibilityBounceKeysController extends @Override public boolean setChecked(boolean isChecked) { InputSettings.setAccessibilityBounceKeysThreshold(mContext, isChecked ? BOUNCE_KEYS_THRESHOLD : 0); updateInputSettingKeysValue(isChecked ? BOUNCE_KEYS_THRESHOLD : 0); return true; } Loading @@ -106,94 +95,13 @@ public class KeyboardAccessibilityBounceKeysController extends Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS); } private void constructDialog(Context context) { mAlertDialog = new AlertDialog.Builder(context) .setView(R.layout.dialog_a11y_bounce_key) .setPositiveButton(android.R.string.ok, (dialog, which) -> { RadioGroup radioGroup = mAlertDialog.findViewById(R.id.bounce_key_value_group); SeekBar seekbar = mAlertDialog.findViewById( R.id.bounce_key_value_custom_slider); RadioButton customRadioButton = mAlertDialog.findViewById( R.id.bounce_key_value_custom); int threshold; if (customRadioButton.isChecked()) { threshold = seekbar.getProgress() * CUSTOM_PROGRESS_INTERVAL; } else { int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId(); threshold = checkedRadioButtonId == R.id.bounce_key_value_600 ? 600 : checkedRadioButtonId == R.id.bounce_key_value_400 ? 400 : checkedRadioButtonId == R.id.bounce_key_value_200 ? 200 : 0; } InputSettings.setAccessibilityBounceKeysThreshold(context, threshold); }) .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()) .create(); mAlertDialog.setOnShowListener(dialog -> { RadioGroup cannedValueRadioGroup = mAlertDialog.findViewById( R.id.bounce_key_value_group); RadioButton customRadioButton = mAlertDialog.findViewById(R.id.bounce_key_value_custom); TextView customValueTextView = mAlertDialog.findViewById( R.id.bounce_key_value_custom_value); SeekBar customProgressBar = mAlertDialog.findViewById( R.id.bounce_key_value_custom_slider); customProgressBar.incrementProgressBy(CUSTOM_PROGRESS_INTERVAL); customProgressBar.setProgress(1); View customValueView = mAlertDialog.findViewById(R.id.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)); protected void updateInputSettingKeysValue(int thresholdTimeMillis) { InputSettings.setAccessibilityBounceKeysThreshold(mContext, thresholdTimeMillis); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton, customValueTextView, customProgressBar); }); } 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 bounceKeysThreshold = InputSettings.getAccessibilityBounceKeysThreshold(mContext); switch (bounceKeysThreshold) { case 600 -> cannedValueRadioGroup.check(R.id.bounce_key_value_600); case 400 -> cannedValueRadioGroup.check(R.id.bounce_key_value_400); case 0, 200 -> cannedValueRadioGroup.check(R.id.bounce_key_value_200); default -> { customValueTextView.setText( String.valueOf( (double) bounceKeysThreshold / MILLISECOND_IN_SECONDS)); customProgressBar.setProgress(bounceKeysThreshold / CUSTOM_PROGRESS_INTERVAL); customRadioButton.setChecked(true); } } protected int getInputSettingKeysValue() { return InputSettings.getAccessibilityBounceKeysThreshold(mContext); } }