diff --git a/res/drawable/ic_bounce_keys.xml b/res/drawable/ic_bounce_keys.xml
new file mode 100644
index 00000000000..424a5fc4a95
--- /dev/null
+++ b/res/drawable/ic_bounce_keys.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
diff --git a/res/drawable/ic_slow_keys.xml b/res/drawable/ic_slow_keys.xml
new file mode 100644
index 00000000000..b28d0ae1012
--- /dev/null
+++ b/res/drawable/ic_slow_keys.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
diff --git a/res/drawable/ic_sticky_keys.xml b/res/drawable/ic_sticky_keys.xml
new file mode 100644
index 00000000000..c07da15942c
--- /dev/null
+++ b/res/drawable/ic_sticky_keys.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 76c7106fae3..a4761d3ec8b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4328,16 +4328,16 @@
Keep it on screen while physical keyboard is active
Bounce keys
-
- Enable Bounce keys for physical keyboard accessibility
+
+ The keyboard ignores quickly repeated presses of the same key within %1$d ms
Slow keys
-
- Enable Slow keys for physical keyboard accessibility
+
+ Adjusts the time it takes for a key press to activate to %1$d ms
Sticky keys
-
- Enable Sticky keys for physical keyboard accessibility
+
+ Press one key at a time for shortcuts instead of holding keys down together
Keyboard shortcuts
@@ -4601,6 +4601,8 @@
Change font size
Screen reader
+
+ Physical keyboard options
Captions
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index 0f4065b5369..ad8bfc396ba 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -105,6 +105,37 @@
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 16414f8846e..fe89bf203b4 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -23,12 +23,14 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ServiceInfo;
+import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.view.InputDevice;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.NonNull;
@@ -42,6 +44,7 @@ import com.android.internal.content.PackageMonitor;
import com.android.settings.R;
import com.android.settings.accessibility.AccessibilityUtil.AccessibilityServiceFragmentType;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.inputmethod.PhysicalKeyboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.RestrictedPreference;
@@ -56,7 +59,8 @@ import java.util.Map;
/** Activity with the accessibility settings. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
-public class AccessibilitySettings extends DashboardFragment {
+public class AccessibilitySettings extends DashboardFragment implements
+ InputManager.InputDeviceListener {
private static final String TAG = "AccessibilitySettings";
@@ -67,12 +71,14 @@ public class AccessibilitySettings extends DashboardFragment {
private static final String CATEGORY_SPEECH = "speech_category";
private static final String CATEGORY_DISPLAY = "display_category";
private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
+ private static final String CATEGORY_KEYBOARD_OPTIONS = "physical_keyboard_options_category";
@VisibleForTesting
static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category";
private static final String[] CATEGORIES = new String[]{
CATEGORY_SCREEN_READER, CATEGORY_CAPTIONS, CATEGORY_AUDIO, CATEGORY_DISPLAY,
- CATEGORY_SPEECH, CATEGORY_INTERACTION_CONTROL, CATEGORY_DOWNLOADED_SERVICES
+ CATEGORY_SPEECH, CATEGORY_INTERACTION_CONTROL,
+ CATEGORY_KEYBOARD_OPTIONS, CATEGORY_DOWNLOADED_SERVICES
};
// Extras passed to sub-fragments.
@@ -169,6 +175,9 @@ public class AccessibilitySettings extends DashboardFragment {
// Observe changes from accessibility selection menu
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
+ shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_STICKY_KEYS);
+ shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SLOW_KEYS);
+ shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS);
mSettingsContentObserver = new AccessibilitySettingsContentObserver(mHandler);
mSettingsContentObserver.registerKeysToObserverCallback(shortcutFeatureKeys,
key -> onContentChanged());
@@ -197,6 +206,7 @@ public class AccessibilitySettings extends DashboardFragment {
initializeAllPreferences();
updateAllPreferences();
registerContentMonitors();
+ registerInputDeviceListener();
}
@Override
@@ -224,6 +234,7 @@ public class AccessibilitySettings extends DashboardFragment {
@Override
public void onDestroy() {
unregisterContentMonitors();
+ unRegisterInputDeviceListener();
super.onDestroy();
}
@@ -313,9 +324,9 @@ public class AccessibilitySettings extends DashboardFragment {
@VisibleForTesting
void updateAllPreferences() {
- updateSystemPreferences();
updateServicePreferences();
updatePreferencesState();
+ updateSystemPreferences();
}
private void registerContentMonitors() {
@@ -326,6 +337,22 @@ public class AccessibilitySettings extends DashboardFragment {
mSettingsContentObserver.register(getContentResolver());
}
+ private void registerInputDeviceListener() {
+ InputManager mIm = getSystemService(InputManager.class);
+ if (mIm == null) {
+ return;
+ }
+ mIm.registerInputDeviceListener(this, null);
+ }
+
+ private void unRegisterInputDeviceListener() {
+ InputManager mIm = getSystemService(InputManager.class);
+ if (mIm == null) {
+ return;
+ }
+ mIm.unregisterInputDeviceListener(this);
+ }
+
private void unregisterContentMonitors() {
mSettingsPackageMonitor.unregister();
mSettingsContentObserver.unregister(getContentResolver());
@@ -405,6 +432,7 @@ public class AccessibilitySettings extends DashboardFragment {
// Hide category if it is empty.
updatePreferenceCategoryVisibility(CATEGORY_SCREEN_READER);
updatePreferenceCategoryVisibility(CATEGORY_SPEECH);
+ updatePreferenceCategoryVisibility(CATEGORY_KEYBOARD_OPTIONS);
}
private List getInstalledAccessibilityList(Context context) {
@@ -499,7 +527,7 @@ public class AccessibilitySettings extends DashboardFragment {
* Updates preferences related to system configurations.
*/
protected void updateSystemPreferences() {
- // Do nothing.
+ updateKeyboardPreferencesVisibility();
}
private void updatePreferencesState() {
@@ -509,6 +537,53 @@ public class AccessibilitySettings extends DashboardFragment {
findPreference(controller.getPreferenceKey())));
}
+ private void updateKeyboardPreferencesVisibility() {
+ if (!mCategoryToPrefCategoryMap.containsKey(CATEGORY_KEYBOARD_OPTIONS)) {
+ return;
+ }
+ boolean isVisible = isAnyHardKeyboardsExist()
+ && isAnyKeyboardPreferenceAvailable();
+ mCategoryToPrefCategoryMap.get(CATEGORY_KEYBOARD_OPTIONS).setVisible(
+ isVisible);
+ if (isVisible) {
+ //set summary here.
+ findPreference(KeyboardBounceKeyPreferenceController.PREF_KEY).setSummary(
+ getContext().getString(R.string.bounce_keys_summary,
+ PhysicalKeyboardFragment.BOUNCE_KEYS_THRESHOLD));
+ findPreference(KeyboardSlowKeyPreferenceController.PREF_KEY).setSummary(
+ getContext().getString(R.string.slow_keys_summary,
+ PhysicalKeyboardFragment.SLOW_KEYS_THRESHOLD));
+ }
+ }
+
+ private boolean isAnyHardKeyboardsExist() {
+ for (int deviceId : InputDevice.getDeviceIds()) {
+ final InputDevice device = InputDevice.getDevice(deviceId);
+ if (device != null && !device.isVirtual() && device.isFullKeyboard()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isAnyKeyboardPreferenceAvailable() {
+ for (List controllerList : getPreferenceControllers()) {
+ for (AbstractPreferenceController controller : controllerList) {
+ if (controller.getPreferenceKey().equals(
+ KeyboardBounceKeyPreferenceController.PREF_KEY)
+ || controller.getPreferenceKey().equals(
+ KeyboardSlowKeyPreferenceController.PREF_KEY)
+ || controller.getPreferenceKey().equals(
+ KeyboardStickyKeyPreferenceController.PREF_KEY)) {
+ if (controller.isAvailable()) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.accessibility_settings) {
@Override
@@ -519,4 +594,15 @@ public class AccessibilitySettings extends DashboardFragment {
context);
}
};
+
+ @Override
+ public void onInputDeviceAdded(int deviceId) {}
+
+ @Override
+ public void onInputDeviceRemoved(int deviceId) {}
+
+ @Override
+ public void onInputDeviceChanged(int deviceId) {
+ mHandler.postDelayed(mUpdateRunnable, DELAY_UPDATE_SERVICES_MILLIS);
+ }
}
diff --git a/src/com/android/settings/accessibility/KeyboardBounceKeyPreferenceController.java b/src/com/android/settings/accessibility/KeyboardBounceKeyPreferenceController.java
new file mode 100644
index 00000000000..6d988ac13be
--- /dev/null
+++ b/src/com/android/settings/accessibility/KeyboardBounceKeyPreferenceController.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 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.accessibility;
+
+
+import android.content.Context;
+import android.hardware.input.InputSettings;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settings.inputmethod.PhysicalKeyboardFragment;
+
+/**
+ * A toggle preference controller for keyboard bounce key.
+ */
+public class KeyboardBounceKeyPreferenceController extends TogglePreferenceController {
+
+ static final String PREF_KEY = "toggle_keyboard_bounce_keys";
+
+ public KeyboardBounceKeyPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return InputSettings.isAccessibilityBounceKeysFeatureEnabled()
+ ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public boolean isChecked() {
+ return InputSettings.isAccessibilityBounceKeysEnabled(mContext);
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ InputSettings.setAccessibilityBounceKeysThreshold(mContext,
+ isChecked ? PhysicalKeyboardFragment.BOUNCE_KEYS_THRESHOLD
+ : 0);
+ return true;
+ }
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_accessibility;
+ }
+}
diff --git a/src/com/android/settings/accessibility/KeyboardSlowKeyPreferenceController.java b/src/com/android/settings/accessibility/KeyboardSlowKeyPreferenceController.java
new file mode 100644
index 00000000000..8bd231680ee
--- /dev/null
+++ b/src/com/android/settings/accessibility/KeyboardSlowKeyPreferenceController.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 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.accessibility;
+
+
+import android.content.Context;
+import android.hardware.input.InputSettings;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settings.inputmethod.PhysicalKeyboardFragment;
+
+/**
+ * A toggle preference controller for keyboard slow key.
+ */
+public class KeyboardSlowKeyPreferenceController extends TogglePreferenceController {
+
+ static final String PREF_KEY = "toggle_keyboard_slow_keys";
+
+ public KeyboardSlowKeyPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return InputSettings.isAccessibilitySlowKeysFeatureFlagEnabled()
+ ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public boolean isChecked() {
+ return InputSettings.isAccessibilitySlowKeysEnabled(mContext);
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ InputSettings.setAccessibilitySlowKeysThreshold(mContext,
+ isChecked ? PhysicalKeyboardFragment.SLOW_KEYS_THRESHOLD
+ : 0);
+ return true;
+ }
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_accessibility;
+ }
+}
diff --git a/src/com/android/settings/accessibility/KeyboardStickyKeyPreferenceController.java b/src/com/android/settings/accessibility/KeyboardStickyKeyPreferenceController.java
new file mode 100644
index 00000000000..ee5559df084
--- /dev/null
+++ b/src/com/android/settings/accessibility/KeyboardStickyKeyPreferenceController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 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.accessibility;
+
+
+import android.content.Context;
+import android.hardware.input.InputSettings;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+/**
+ * A toggle preference controller for keyboard sticky key.
+ */
+public class KeyboardStickyKeyPreferenceController extends TogglePreferenceController {
+
+ static final String PREF_KEY = "toggle_keyboard_sticky_keys";
+
+ public KeyboardStickyKeyPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return InputSettings.isAccessibilityStickyKeysFeatureEnabled()
+ ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public boolean isChecked() {
+ return InputSettings.isAccessibilityStickyKeysEnabled(mContext);
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ InputSettings.setAccessibilityStickyKeysEnabled(mContext, isChecked);
+ return true;
+ }
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_accessibility;
+ }
+}
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
index b06edb2957b..f2ac5508d80 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
@@ -61,6 +61,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+// TODO(b/327638540): Update implementation of preference here and reuse key preferences and
+// controllers between here and A11y Setting page.
@SearchIndexable
public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
implements InputManager.InputDeviceListener,
@@ -83,6 +85,8 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
Secure.ACCESSIBILITY_SLOW_KEYS);
private static final Uri sAccessibilityStickyKeysUri = Secure.getUriFor(
Secure.ACCESSIBILITY_STICKY_KEYS);
+ public static final int BOUNCE_KEYS_THRESHOLD = 500;
+ public static final int SLOW_KEYS_THRESHOLD = 500;
@NonNull
private final ArrayList mLastHardKeyboards = new ArrayList<>();
@@ -132,8 +136,12 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
mKeyboardA11yCategory = Objects.requireNonNull(findPreference(KEYBOARD_A11Y_CATEGORY));
mAccessibilityBounceKeys = Objects.requireNonNull(
mKeyboardA11yCategory.findPreference(ACCESSIBILITY_BOUNCE_KEYS));
+ mAccessibilityBounceKeys.setSummary(
+ getContext().getString(R.string.bounce_keys_summary, BOUNCE_KEYS_THRESHOLD));
mAccessibilitySlowKeys = Objects.requireNonNull(
mKeyboardA11yCategory.findPreference(ACCESSIBILITY_SLOW_KEYS));
+ mAccessibilitySlowKeys.setSummary(
+ getContext().getString(R.string.slow_keys_summary, SLOW_KEYS_THRESHOLD));
mAccessibilityStickyKeys = Objects.requireNonNull(
mKeyboardA11yCategory.findPreference(ACCESSIBILITY_STICKY_KEYS));
diff --git a/tests/robotests/src/com/android/settings/accessibility/KeyboardBounceKeyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/KeyboardBounceKeyPreferenceControllerTest.java
new file mode 100644
index 00000000000..96beb43dd1c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/KeyboardBounceKeyPreferenceControllerTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 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.accessibility;
+
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.core.BasePreferenceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+
+@RunWith(RobolectricTestRunner.class)
+public class KeyboardBounceKeyPreferenceControllerTest {
+
+ private static final String KEY_ACCESSIBILITY_BOUNCE_KEYS =
+ Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS;
+ private static final int UNKNOWN = -1;
+
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext));
+ private final KeyboardBounceKeyPreferenceController mController =
+ new KeyboardBounceKeyPreferenceController(mContext,
+ KeyboardBounceKeyPreferenceController.PREF_KEY);
+
+ @Before
+ public void setUp() {
+ final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+ mSwitchPreference.setKey(KeyboardBounceKeyPreferenceController.PREF_KEY);
+ screen.addPreference(mSwitchPreference);
+ mController.displayPreference(screen);
+ }
+
+ @Test
+ public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void isChecked_disableBounceKey_onResumeShouldReturnFalse() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS, OFF);
+
+ mController.updateState(mSwitchPreference);
+
+ assertThat(mController.isChecked()).isFalse();
+ assertThat(mSwitchPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isChecked_enableBounceKey_onResumeShouldReturnTrue() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS, ON);
+
+ mController.updateState(mSwitchPreference);
+
+ assertThat(mController.isChecked()).isTrue();
+ assertThat(mSwitchPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void performClick_enableBounceKey_shouldReturnTrue() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS, OFF);
+
+ mController.updateState(mSwitchPreference);
+
+ mSwitchPreference.performClick();
+
+ verify(mSwitchPreference).setChecked(true);
+ assertThat(mController.isChecked()).isTrue();
+ assertThat(mSwitchPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void performClick_disableBounceKey_shouldReturnFalse() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS, ON);
+
+ mController.updateState(mSwitchPreference);
+
+ mSwitchPreference.performClick();
+
+ verify(mSwitchPreference).setChecked(false);
+ assertThat(mController.isChecked()).isFalse();
+ assertThat(mSwitchPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void setChecked_setFalse_shouldDisableBounceKey() {
+ mController.setChecked(false);
+
+ assertThat(Settings.Secure.getInt(
+ mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS, UNKNOWN)).isEqualTo(
+ OFF);
+ }
+
+ @Test
+ public void setChecked_setTrue_shouldEnableBounceKey() {
+ mController.setChecked(true);
+
+ assertThat(Settings.Secure.getInt(
+ mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS,
+ UNKNOWN)).isNotEqualTo(OFF);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/KeyboardSlowKeyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/KeyboardSlowKeyPreferenceControllerTest.java
new file mode 100644
index 00000000000..321b69fa834
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/KeyboardSlowKeyPreferenceControllerTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 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.accessibility;
+
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.core.BasePreferenceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+
+@RunWith(RobolectricTestRunner.class)
+public class KeyboardSlowKeyPreferenceControllerTest {
+
+ private static final String KEY_ACCESSIBILITY_SLOW_KEYS =
+ Settings.Secure.ACCESSIBILITY_SLOW_KEYS;
+ private static final int UNKNOWN = -1;
+
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext));
+ private final KeyboardSlowKeyPreferenceController mController =
+ new KeyboardSlowKeyPreferenceController(mContext,
+ KeyboardSlowKeyPreferenceController.PREF_KEY);
+
+ @Before
+ public void setUp() {
+ final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+ mSwitchPreference.setKey(KeyboardSlowKeyPreferenceController.PREF_KEY);
+ screen.addPreference(mSwitchPreference);
+ mController.displayPreference(screen);
+ }
+
+ @Test
+ public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void isChecked_disableSlowKey_onResumeShouldReturnFalse() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, OFF);
+
+ mController.updateState(mSwitchPreference);
+
+ assertThat(mController.isChecked()).isFalse();
+ assertThat(mSwitchPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isChecked_enableSlowKey_onResumeShouldReturnTrue() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, ON);
+
+ mController.updateState(mSwitchPreference);
+
+ assertThat(mController.isChecked()).isTrue();
+ assertThat(mSwitchPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void performClick_enableSlowKey_shouldReturnTrue() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, OFF);
+
+ mController.updateState(mSwitchPreference);
+
+ mSwitchPreference.performClick();
+
+ verify(mSwitchPreference).setChecked(true);
+ assertThat(mController.isChecked()).isTrue();
+ assertThat(mSwitchPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void performClick_disableSlowKey_shouldReturnFalse() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, ON);
+
+ mController.updateState(mSwitchPreference);
+
+ mSwitchPreference.performClick();
+
+ verify(mSwitchPreference).setChecked(false);
+ assertThat(mController.isChecked()).isFalse();
+ assertThat(mSwitchPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void setChecked_setFalse_shouldDisableSlowKey() {
+ mController.setChecked(false);
+
+ assertThat(Settings.Secure.getInt(
+ mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, UNKNOWN)).isEqualTo(
+ OFF);
+ }
+
+ @Test
+ public void setChecked_setTrue_shouldEnableSlowKey() {
+ mController.setChecked(true);
+
+ assertThat(Settings.Secure.getInt(
+ mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, UNKNOWN)).isNotEqualTo(
+ OFF);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/KeyboardStickyKeyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/KeyboardStickyKeyPreferenceControllerTest.java
new file mode 100644
index 00000000000..31d46b76eab
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/KeyboardStickyKeyPreferenceControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2024 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.accessibility;
+
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.core.BasePreferenceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+
+@RunWith(RobolectricTestRunner.class)
+public class KeyboardStickyKeyPreferenceControllerTest {
+
+ private static final String KEY_ACCESSIBILITY_STICKY_KEYS =
+ Settings.Secure.ACCESSIBILITY_STICKY_KEYS;
+ private static final int UNKNOWN = -1;
+
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext));
+ private final KeyboardStickyKeyPreferenceController mController =
+ new KeyboardStickyKeyPreferenceController(mContext,
+ KeyboardStickyKeyPreferenceController.PREF_KEY);
+
+ @Before
+ public void setUp() {
+ final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+ mSwitchPreference.setKey(KeyboardStickyKeyPreferenceController.PREF_KEY);
+ screen.addPreference(mSwitchPreference);
+ mController.displayPreference(screen);
+ }
+
+ @Test
+ public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void isChecked_disableStickyKey_onResumeShouldReturnFalse() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, OFF);
+
+ mController.updateState(mSwitchPreference);
+
+ assertThat(mController.isChecked()).isFalse();
+ assertThat(mSwitchPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isChecked_enableStickyKey_onResumeShouldReturnTrue() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, ON);
+
+ mController.updateState(mSwitchPreference);
+
+ assertThat(mController.isChecked()).isTrue();
+ assertThat(mSwitchPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void performClick_enableStickyKey_shouldReturnTrue() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, OFF);
+
+ mController.updateState(mSwitchPreference);
+
+ mSwitchPreference.performClick();
+
+ verify(mSwitchPreference).setChecked(true);
+ assertThat(mController.isChecked()).isTrue();
+ assertThat(mSwitchPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void performClick_disableStickyKey_shouldReturnFalse() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, ON);
+
+ mController.updateState(mSwitchPreference);
+
+ mSwitchPreference.performClick();
+
+ verify(mSwitchPreference).setChecked(false);
+ assertThat(mController.isChecked()).isFalse();
+ assertThat(mSwitchPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void setChecked_setFalse_shouldDisableStickyKey() {
+ mController.setChecked(false);
+
+ assertThat(Settings.Secure.getInt(
+ mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, UNKNOWN)).isEqualTo(OFF);
+ }
+
+ @Test
+ public void setChecked_setTrue_shouldEnableStickyKey() {
+ mController.setChecked(true);
+
+ assertThat(Settings.Secure.getInt(
+ mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, UNKNOWN)).isEqualTo(ON);
+ }
+}