diff --git a/res/layout/dialog_a11y_bounce_key.xml b/res/layout/dialog_keyboard_a11y_input_setting_keys.xml similarity index 80% rename from res/layout/dialog_a11y_bounce_key.xml rename to res/layout/dialog_keyboard_a11y_input_setting_keys.xml index da3ebde933d..dfa3c46603d 100644 --- a/res/layout/dialog_a11y_bounce_key.xml +++ b/res/layout/dialog_keyboard_a11y_input_setting_keys.xml @@ -22,47 +22,45 @@ android:orientation="vertical"> Bounce key threshold Choose the duration of time your keyboard ignores repeated key presses - - 0.2s - - 0.4s - - 0.6s + + 0.2s + + 0.4s + + 0.6s + + Custom + + custom value + Slow keys diff --git a/res/xml/physical_keyboard_a11y_settings.xml b/res/xml/physical_keyboard_a11y_settings.xml index 62479f91502..3bfe1993d5b 100644 --- a/res/xml/physical_keyboard_a11y_settings.xml +++ b/res/xml/physical_keyboard_a11y_settings.xml @@ -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"> - { + 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); + } + } + } } diff --git a/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java b/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java index 1652f00d1e2..6bd836feb08 100644 --- a/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java +++ b/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java @@ -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; @@ -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 @@ -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; } @@ -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)); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - }); - initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton, customValueTextView, - customProgressBar); - }); + @Override + protected void updateInputSettingKeysValue(int thresholdTimeMillis) { + InputSettings.setAccessibilityBounceKeysThreshold(mContext, thresholdTimeMillis); } - 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); - } - } + @Override + protected int getInputSettingKeysValue() { + return InputSettings.getAccessibilityBounceKeysThreshold(mContext); } } diff --git a/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysController.java b/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysController.java index d8602df9c3e..857623a6839 100644 --- a/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysController.java +++ b/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysController.java @@ -20,27 +20,34 @@ import android.content.Context; import android.hardware.input.InputSettings; import android.net.Uri; import android.provider.Settings; +import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.lifecycle.LifecycleObserver; +import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import androidx.preference.TwoStatePreference; + +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 TwoStatePreference mTwoStatePreference; + @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 public void displayPreference(@NonNull PreferenceScreen screen) { super.displayPreference(screen); - mTwoStatePreference = screen.findPreference(getPreferenceKey()); + mPrimarySwitchPreference = screen.findPreference(getPreferenceKey()); } @Override @@ -50,8 +57,7 @@ public class KeyboardAccessibilitySlowKeysController extends @Override public boolean setChecked(boolean isChecked) { - InputSettings.setAccessibilitySlowKeysThreshold(mContext, - isChecked ? SLOW_KEYS_THRESHOLD : 0); + updateInputSettingKeysValue(isChecked ? SLOW_KEYS_THRESHOLD : 0); return true; } @@ -64,8 +70,8 @@ public class KeyboardAccessibilitySlowKeysController extends @Override protected void onInputSettingUpdated() { - if (mTwoStatePreference != null) { - mTwoStatePreference.setChecked( + if (mPrimarySwitchPreference != null) { + mPrimarySwitchPreference.setChecked( InputSettings.isAccessibilitySlowKeysEnabled(mContext)); } } @@ -75,4 +81,25 @@ public class KeyboardAccessibilitySlowKeysController extends return Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_SLOW_KEYS); } + + @Override + public boolean handlePreferenceTreeClick(@NonNull Preference preference) { + if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { + return false; + } + if (mAlertDialog != null) { + mAlertDialog.show(); + } + return true; + } + + @Override + protected void updateInputSettingKeysValue(int thresholdTimeMillis) { + InputSettings.setAccessibilitySlowKeysThreshold(mContext, thresholdTimeMillis); + } + + @Override + protected int getInputSettingKeysValue() { + return InputSettings.getAccessibilitySlowKeysThreshold(mContext); + } } diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysControllerTest.java index d16f6975d0e..b385b2f32a5 100644 --- a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysControllerTest.java +++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysControllerTest.java @@ -57,7 +57,7 @@ public class KeyboardAccessibilityBounceKeysControllerTest { public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); - private static final String PREFERENCE_KEY = "accessibility_bounce_keys"; + private static final String PREFERENCE_KEY = "keyboard_a11y_page_bounce_keys"; @Mock private Preference mPreference; private Context mContext; @@ -116,8 +116,8 @@ public class KeyboardAccessibilityBounceKeysControllerTest { public void handlePreferenceTreeClick_performClickOn200_updatesBounceKeysThreshold() { mKeyboardAccessibilityBounceKeysController.handlePreferenceTreeClick(mPreference); AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); - RadioGroup radioGroup = alertDialog.findViewById(R.id.bounce_key_value_group); - radioGroup.check(R.id.bounce_key_value_200); + RadioGroup radioGroup = alertDialog.findViewById(R.id.input_setting_keys_value_group); + radioGroup.check(R.id.input_setting_keys_value_200); alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick(); ShadowLooper.idleMainLooper(); diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityMouseKeysControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityMouseKeysControllerTest.java index 59224970b56..fdb4ab96bc4 100644 --- a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityMouseKeysControllerTest.java +++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityMouseKeysControllerTest.java @@ -50,7 +50,7 @@ public class KeyboardAccessibilityMouseKeysControllerTest { mContext = RuntimeEnvironment.application; mKeyboardAccessibilityMouseKeysController = new KeyboardAccessibilityMouseKeysController( mContext, - "accessibility_mouse_keys"); + "keyboard_a11y_page_mouse_keys"); } @Test diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysControllerTest.java index 5f6908aae25..9f82b759cdc 100644 --- a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysControllerTest.java +++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysControllerTest.java @@ -18,39 +18,59 @@ package com.android.settings.inputmethod; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + import android.content.Context; import android.hardware.input.InputSettings; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; +import android.widget.RadioGroup; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.Preference; + +import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.keyboard.Flags; +import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowLooper; @RunWith(RobolectricTestRunner.class) @Config(shadows = { com.android.settings.testutils.shadow.ShadowFragment.class, + ShadowAlertDialogCompat.class, }) public class KeyboardAccessibilitySlowKeysControllerTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule(); + private static final String PREFERENCE_KEY = "keyboard_a11y_page_slow_keys"; + @Mock + private Preference mPreference; private Context mContext; private KeyboardAccessibilitySlowKeysController mKeyboardAccessibilitySlowKeysController; @Before public void setUp() { mContext = RuntimeEnvironment.application; + mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat); mKeyboardAccessibilitySlowKeysController = new KeyboardAccessibilitySlowKeysController( mContext, - "accessibility_slow_keys"); + PREFERENCE_KEY); + when(mPreference.getKey()).thenReturn(PREFERENCE_KEY); } @Test @@ -82,4 +102,28 @@ public class KeyboardAccessibilitySlowKeysControllerTest { assertThat(isEnabled).isFalse(); } + + @Test + public void handlePreferenceTreeClick_dialogShows() { + mKeyboardAccessibilitySlowKeysController.handlePreferenceTreeClick(mPreference); + + AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + + assertThat(alertDialog.isShowing()).isTrue(); + } + + @Test + public void handlePreferenceTreeClick_performClickOn200_updatesSlowKeysThreshold() { + mKeyboardAccessibilitySlowKeysController.handlePreferenceTreeClick(mPreference); + AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + RadioGroup radioGroup = alertDialog.findViewById(R.id.input_setting_keys_value_group); + radioGroup.check(R.id.input_setting_keys_value_200); + + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick(); + ShadowLooper.idleMainLooper(); + + assertThat(alertDialog.isShowing()).isFalse(); + int threshold = InputSettings.getAccessibilitySlowKeysThreshold(mContext); + assertThat(threshold).isEqualTo(200); + } } diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityStickyKeysControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityStickyKeysControllerTest.java index 06cb5585456..4631f571697 100644 --- a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityStickyKeysControllerTest.java +++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityStickyKeysControllerTest.java @@ -50,7 +50,7 @@ public class KeyboardAccessibilityStickyKeysControllerTest { mContext = RuntimeEnvironment.application; mKeyboardAccessibilityStickyKeysController = new KeyboardAccessibilityStickyKeysController( mContext, - "accessibility_sticky_keys"); + "keyboard_a11y_page_sticky_keys"); } @Test