From 8b67c17a7b0dbfa12b8ea6a6a133fec79b7fae7c Mon Sep 17 00:00:00 2001 From: Chun-Ku Lin Date: Mon, 5 Feb 2024 23:11:56 +0000 Subject: [PATCH] Show QS shortcut option if the a11y feature provides a tile. Bug: 314852953 Test: atest com.android.settings.accessibility Test: atest com.android.settings.accessibility.shortcuts Test: manual Flag: ACONFIG android.view.accessibility.a11y_qs_shortcut STAGING Change-Id: Id7a6b3adfd4c4f3cb2b9f7fe15269b57a3d00543 --- res-product/values/drawables.xml | 2 + ...ssibility_shortcut_type_quick_settings.xml | 56 ++++++ res/values/accessibility_shortcut_keys.xml | 3 +- res/values/strings.xml | 18 +- res/xml/accessibility_edit_shortcuts.xml | 12 +- ...ccessibilityGestureNavigationTutorial.java | 28 ++- ...cessibilityShortcutPreferenceFragment.java | 12 +- .../accessibility/AccessibilityUtil.java | 111 +++++++++-- .../accessibility/PreferredShortcuts.java | 12 ++ .../ToggleFeaturePreferenceFragment.java | 11 ++ ...ScreenMagnificationPreferenceFragment.java | 91 +++++++-- .../EditShortcutsPreferenceFragment.java | 9 +- ...QuickSettingsShortcutOptionController.java | 142 ++++++++++++++ .../ShortcutOptionPreferenceController.java | 12 ++ ...areShortcutOptionPreferenceController.java | 4 + .../TripleTapShortcutOptionController.java | 6 + ...gerDoubleTapShortcutOptionController.java} | 10 +- .../VolumeKeysShortcutOptionController.java | 5 + ...sibilityGestureNavigationTutorialTest.java | 15 +- ...ibilityShortcutPreferenceFragmentTest.java | 74 ++++++- .../accessibility/AccessibilityUtilTest.java | 166 ++++++++++++++-- ...eColorInversionPreferenceFragmentTest.java | 7 + ...oggleDaltonizerPreferenceFragmentTest.java | 7 + .../ToggleFeaturePreferenceFragmentTest.java | 58 +++++- ...enMagnificationPreferenceFragmentTest.java | 148 +++++++++++--- .../EditShortcutsPreferenceFragmentTest.java | 29 ++- .../GestureShortcutOptionControllerTest.java | 6 +- ...kSettingsShortcutOptionControllerTest.java | 180 ++++++++++++++++++ ...hortcutOptionPreferenceControllerTest.java | 106 +++++++---- ...TripleTapShortcutOptionControllerTest.java | 59 +++++- ...oubleTapShortcutOptionControllerTest.java} | 77 ++++++-- ...olumeKeysShortcutOptionControllerTest.java | 49 ++++- .../testutils/AccessibilityTestUtils.java | 49 +++++ .../shadow/ShadowAccessibilityManager.java | 42 ++++ .../accessibility/PreferredShortcutsTest.java | 48 ++++- 35 files changed, 1501 insertions(+), 163 deletions(-) create mode 100644 res/drawable/accessibility_shortcut_type_quick_settings.xml create mode 100644 src/com/android/settings/accessibility/shortcuts/QuickSettingsShortcutOptionController.java rename src/com/android/settings/accessibility/shortcuts/{TwoFingersDoubleTapShortcutOptionController.java => TwoFingerDoubleTapShortcutOptionController.java} (90%) create mode 100644 tests/robotests/src/com/android/settings/accessibility/shortcuts/QuickSettingsShortcutOptionControllerTest.java rename tests/robotests/src/com/android/settings/accessibility/shortcuts/{TwoFingersDoubleTapShortcutOptionControllerTest.java => TwoFingerDoubleTapShortcutOptionControllerTest.java} (62%) create mode 100644 tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessibilityManager.java diff --git a/res-product/values/drawables.xml b/res-product/values/drawables.xml index a2d66e72cf9..9353030be9c 100644 --- a/res-product/values/drawables.xml +++ b/res-product/values/drawables.xml @@ -29,6 +29,8 @@ @drawable/accessibility_captioning_banner @drawable/accessibility_captioning_banner_tablet + @drawable/accessibility_shortcut_type_quick_settings + @drawable/accessibility_shortcut_type_hardware @drawable/accessibility_shortcut_type_hardware_tablet diff --git a/res/drawable/accessibility_shortcut_type_quick_settings.xml b/res/drawable/accessibility_shortcut_type_quick_settings.xml new file mode 100644 index 00000000000..a8013476151 --- /dev/null +++ b/res/drawable/accessibility_shortcut_type_quick_settings.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/values/accessibility_shortcut_keys.xml b/res/values/accessibility_shortcut_keys.xml index 4992a544eb0..fcf62bcd94d 100644 --- a/res/values/accessibility_shortcut_keys.xml +++ b/res/values/accessibility_shortcut_keys.xml @@ -22,6 +22,7 @@ shortcut_nav_button_pref shortcut_fab_pref shortcut_triple_tap_pref - shortcut_two_fingers_double_tap_pref + shortcut_two_finger_double_tap_pref + shortcut_quick_settings_pref advanced_shortcuts_collapsed \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 8b0cd67d331..59cb2fbf4fd 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4835,6 +4835,8 @@ Triple tap screen to open Two finger double tap screen to open + + Quick Settings shortcut Use gesture to open @@ -4849,6 +4851,8 @@ To start and stop magnification, triple-tap anywhere on your screen. To start and stop magnification, double-tap anywhere on your screen with two fingers. + + To use this feature, swipe down from the top of your screen. To use this feature, swipe up from the bottom of the screen with 2 fingers.\n\nTo switch between features, swipe up with 2 fingers and hold. @@ -4863,10 +4867,10 @@ Button settings %1$s shortcut - - Accessibility button - - Accessibility gesture + + accessibility button + + accessibility gesture Swipe up with 2 fingers @@ -4885,6 +4889,12 @@ More options Learn more about %1$s + + Quick Settings + + Swipe down from the top of your screen + + Quick Settings Hold volume keys diff --git a/res/xml/accessibility_edit_shortcuts.xml b/res/xml/accessibility_edit_shortcuts.xml index fdb5b99a641..37e25af96a8 100644 --- a/res/xml/accessibility_edit_shortcuts.xml +++ b/res/xml/accessibility_edit_shortcuts.xml @@ -25,6 +25,14 @@ settings:allowDividerAbove="false" settings:allowDividerBelow="false"/> + + + settings:controller="com.android.settings.accessibility.shortcuts.TwoFingerDoubleTapShortcutOptionController" /> createShortcutTutorialPages(@NonNull Context context, int shortcutTypes) { final List tutorialPages = new ArrayList<>(); + if (android.view.accessibility.Flags.a11yQsShortcut()) { + if ((shortcutTypes & UserShortcutType.QUICK_SETTINGS) + == UserShortcutType.QUICK_SETTINGS) { + tutorialPages.add(createQuickSettingTutorialPage(context)); + } + } if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { tutorialPages.add(createSoftwareTutorialPage(context)); } @@ -446,8 +468,8 @@ public final class AccessibilityGestureNavigationTutorial { } if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { - if ((shortcutTypes & UserShortcutType.TWOFINGERTRIPLETAP) - == UserShortcutType.TWOFINGERTRIPLETAP) { + if ((shortcutTypes & UserShortcutType.TWOFINGER_DOUBLETAP) + == UserShortcutType.TWOFINGER_DOUBLETAP) { tutorialPages.add(createTwoFingerTripleTapTutorialPage(context)); } } diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java index 09a691ed75b..8af284db15f 100644 --- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java +++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java @@ -452,7 +452,13 @@ public abstract class AccessibilityShortcutPreferenceFragment extends Restricted getComponentName().flattenToString()); final List list = new ArrayList<>(); - + if (android.view.accessibility.Flags.a11yQsShortcut()) { + if (hasShortcutType(shortcutTypes, AccessibilityUtil.UserShortcutType.QUICK_SETTINGS)) { + final CharSequence qsTitle = context.getText( + R.string.accessibility_feature_shortcut_setting_summary_quick_settings); + list.add(qsTitle); + } + } if (hasShortcutType(shortcutTypes, AccessibilityUtil.UserShortcutType.SOFTWARE)) { list.add(getSoftwareShortcutTypeSummary(context)); } @@ -538,6 +544,10 @@ public abstract class AccessibilityShortcutPreferenceFragment extends Restricted } private void showQuickSettingsTooltipIfNeeded() { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + // Don't show Quick Settings tooltip + return; + } final ComponentName tileComponentName = getTileComponentName(); if (tileComponentName == null) { // Returns if no tile service assigned. diff --git a/src/com/android/settings/accessibility/AccessibilityUtil.java b/src/com/android/settings/accessibility/AccessibilityUtil.java index 3b81bdb5110..afc7b84cbe9 100644 --- a/src/com/android/settings/accessibility/AccessibilityUtil.java +++ b/src/com/android/settings/accessibility/AccessibilityUtil.java @@ -28,6 +28,7 @@ import android.content.res.Resources; import android.graphics.Insets; import android.graphics.Rect; import android.os.Build; +import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.TypedValue; @@ -40,8 +41,11 @@ import androidx.annotation.NonNull; import androidx.annotation.StringRes; import androidx.annotation.VisibleForTesting; +import com.android.internal.accessibility.util.ShortcutUtils; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Set; import java.util.StringJoiner; /** Provides utility methods to accessibility settings only. */ @@ -87,6 +91,10 @@ public final class AccessibilityUtil { * choose accessibility shortcut as preferred shortcut. * {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly * tapping screen 3 times as preferred shortcut. + * {@code TWOFINGER_DOUBLETAP} for displaying specifying magnification to be toggled via + * quickly tapping screen 2 times with two fingers as preferred shortcut. + * {@code QUICK_SETTINGS} for displaying specifying the accessibility services or features which + * choose Quick Settings as preferred shortcut. */ @Retention(RetentionPolicy.SOURCE) @IntDef({ @@ -94,16 +102,18 @@ public final class AccessibilityUtil { UserShortcutType.SOFTWARE, UserShortcutType.HARDWARE, UserShortcutType.TRIPLETAP, - UserShortcutType.TWOFINGERTRIPLETAP, + UserShortcutType.TWOFINGER_DOUBLETAP, + UserShortcutType.QUICK_SETTINGS, }) /** Denotes the user shortcut type. */ public @interface UserShortcutType { int EMPTY = 0; - int SOFTWARE = 1; // 1 << 0 - int HARDWARE = 2; // 1 << 1 - int TRIPLETAP = 4; // 1 << 2 - int TWOFINGERTRIPLETAP = 8; // 1 << 3 + int SOFTWARE = 1; + int HARDWARE = 1 << 1; + int TRIPLETAP = 1 << 2; + int TWOFINGER_DOUBLETAP = 1 << 3; + int QUICK_SETTINGS = 1 << 4; } /** @@ -200,12 +210,26 @@ public final class AccessibilityUtil { * Opts in component name into multiple {@code shortcutTypes} colon-separated string in * Settings. * - * @param context The current context. - * @param shortcutTypes A combination of {@link UserShortcutType}. + * @param context The current context. + * @param shortcutTypes A combination of {@link UserShortcutType}. * @param componentName The component name that need to be opted in Settings. */ static void optInAllValuesToSettings(Context context, int shortcutTypes, @NonNull ComponentName componentName) { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class); + if (a11yManager != null) { + a11yManager.enableShortcutsForTargets( + /* enable= */ true, + shortcutTypes, + Set.of(componentName.flattenToString()), + UserHandle.myUserId() + ); + } + + return; + } + if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { optInValueToSettings(context, UserShortcutType.SOFTWARE, componentName); } @@ -217,13 +241,26 @@ public final class AccessibilityUtil { /** * Opts in component name into {@code shortcutType} colon-separated string in Settings. * - * @param context The current context. - * @param shortcutType The preferred shortcut type user selected. + * @param context The current context. + * @param shortcutType The preferred shortcut type user selected. * @param componentName The component name that need to be opted in Settings. */ @VisibleForTesting static void optInValueToSettings(Context context, @UserShortcutType int shortcutType, @NonNull ComponentName componentName) { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class); + if (a11yManager != null) { + a11yManager.enableShortcutsForTargets( + /* enable= */ true, + shortcutType, + Set.of(componentName.flattenToString()), + UserHandle.myUserId() + ); + } + return; + } + final String targetKey = convertKeyFromSettings(shortcutType); final String targetString = Settings.Secure.getString(context.getContentResolver(), targetKey); @@ -245,12 +282,25 @@ public final class AccessibilityUtil { * Opts out component name into multiple {@code shortcutTypes} colon-separated string in * Settings. * - * @param context The current context. + * @param context The current context. * @param shortcutTypes A combination of {@link UserShortcutType}. * @param componentName The component name that need to be opted out from Settings. */ static void optOutAllValuesFromSettings(Context context, int shortcutTypes, @NonNull ComponentName componentName) { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class); + if (a11yManager != null) { + a11yManager.enableShortcutsForTargets( + /* enable= */ false, + shortcutTypes, + Set.of(componentName.flattenToString()), + UserHandle.myUserId() + ); + } + return; + } + if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { optOutValueFromSettings(context, UserShortcutType.SOFTWARE, componentName); } @@ -262,13 +312,26 @@ public final class AccessibilityUtil { /** * Opts out component name into {@code shortcutType} colon-separated string in Settings. * - * @param context The current context. - * @param shortcutType The preferred shortcut type user selected. + * @param context The current context. + * @param shortcutType The preferred shortcut type user selected. * @param componentName The component name that need to be opted out from Settings. */ @VisibleForTesting static void optOutValueFromSettings(Context context, @UserShortcutType int shortcutType, @NonNull ComponentName componentName) { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class); + if (a11yManager != null) { + a11yManager.enableShortcutsForTargets( + /* enable= */ false, + shortcutType, + Set.of(componentName.flattenToString()), + UserHandle.myUserId() + ); + } + return; + } + final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR)); final String targetKey = convertKeyFromSettings(shortcutType); final String targetString = Settings.Secure.getString(context.getContentResolver(), @@ -307,6 +370,14 @@ public final class AccessibilityUtil { if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) { exist |= hasValueInSettings(context, UserShortcutType.HARDWARE, componentName); } + if (android.view.accessibility.Flags.a11yQsShortcut()) { + if ((shortcutTypes & UserShortcutType.QUICK_SETTINGS) + == UserShortcutType.QUICK_SETTINGS) { + exist |= hasValueInSettings(context, UserShortcutType.QUICK_SETTINGS, + componentName); + } + } + return exist; } @@ -321,6 +392,12 @@ public final class AccessibilityUtil { @VisibleForTesting static boolean hasValueInSettings(Context context, @UserShortcutType int shortcutType, @NonNull ComponentName componentName) { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + return ShortcutUtils.getShortcutTargetsFromSettings( + context, shortcutType, UserHandle.myUserId() + ).contains(componentName.flattenToString()); + } + final String targetKey = convertKeyFromSettings(shortcutType); final String targetString = Settings.Secure.getString(context.getContentResolver(), targetKey); @@ -357,6 +434,12 @@ public final class AccessibilityUtil { if (hasValuesInSettings(context, UserShortcutType.HARDWARE, componentName)) { shortcutTypes |= UserShortcutType.HARDWARE; } + if (android.view.accessibility.Flags.a11yQsShortcut()) { + if (hasValuesInSettings(context, UserShortcutType.QUICK_SETTINGS, componentName)) { + shortcutTypes |= UserShortcutType.QUICK_SETTINGS; + } + } + return shortcutTypes; } @@ -367,6 +450,10 @@ public final class AccessibilityUtil { * @return Mapping key in Settings. */ static String convertKeyFromSettings(@UserShortcutType int shortcutType) { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + return ShortcutUtils.convertToKey(shortcutType); + } + switch (shortcutType) { case UserShortcutType.SOFTWARE: return Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; diff --git a/src/com/android/settings/accessibility/PreferredShortcuts.java b/src/com/android/settings/accessibility/PreferredShortcuts.java index e76bc9b0dcb..e166f38a52f 100644 --- a/src/com/android/settings/accessibility/PreferredShortcuts.java +++ b/src/com/android/settings/accessibility/PreferredShortcuts.java @@ -21,8 +21,10 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.UserHandle; import android.util.ArrayMap; +import android.view.accessibility.Flags; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.util.ShortcutUtils; @@ -98,6 +100,11 @@ public final class PreferredShortcuts { @NonNull Context context, @NonNull Set components) { final Map> shortcutTypeToTargets = new ArrayMap<>(); for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) { + if (!Flags.a11yQsShortcut() + && shortcutType == ShortcutConstants.UserShortcutType.QUICK_SETTINGS) { + // Skip saving quick setting as preferred shortcut option when flag is not enabled + continue; + } shortcutTypeToTargets.put( shortcutType, ShortcutUtils.getShortcutTargetsFromSettings( @@ -138,6 +145,11 @@ public final class PreferredShortcuts { return context.getSharedPreferences(ACCESSIBILITY_PERF, Context.MODE_PRIVATE); } + @VisibleForTesting(otherwise = VisibleForTesting.NONE) + static void clearPreferredShortcuts(Context context) { + getSharedPreferences(context).edit().clear().apply(); + } + /** * Returns the default shortcut types for the given accessibility feature. */ diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java index e7835f83be6..6d5f5362e25 100644 --- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java @@ -711,6 +711,13 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment mComponentName.flattenToString()); final List list = new ArrayList<>(); + if (android.view.accessibility.Flags.a11yQsShortcut()) { + if (hasShortcutType(shortcutTypes, UserShortcutType.QUICK_SETTINGS)) { + final CharSequence qsTitle = context.getText( + R.string.accessibility_feature_shortcut_setting_summary_quick_settings); + list.add(qsTitle); + } + } if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) { list.add(getSoftwareShortcutTypeSummary(context)); } @@ -906,6 +913,10 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment } private void showQuickSettingsTooltipIfNeeded() { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + // Don't show Quick Settings tooltip + return; + } final ComponentName tileComponentName = getTileComponentName(); if (tileComponentName == null) { // Returns if no tile service assigned. diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java index 985d45d89c2..6ef764edfaf 100644 --- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java @@ -33,6 +33,7 @@ import android.icu.text.CaseMap; import android.icu.text.MessageFormat; import android.net.Uri; import android.os.Bundle; +import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings; import android.text.TextUtils; @@ -65,6 +66,7 @@ import com.google.android.setupcompat.util.WizardManagerHelper; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Set; import java.util.StringJoiner; /** @@ -357,7 +359,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends } if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { if (mTwoFingerTripleTapTypeCheckBox.isChecked()) { - value |= UserShortcutType.TWOFINGERTRIPLETAP; + value |= UserShortcutType.TWOFINGER_DOUBLETAP; } } return value; @@ -419,7 +421,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends hasShortcutType(value, UserShortcutType.TRIPLETAP)); if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { mTwoFingerTripleTapTypeCheckBox.setChecked( - hasShortcutType(value, UserShortcutType.TWOFINGERTRIPLETAP)); + hasShortcutType(value, UserShortcutType.TWOFINGER_DOUBLETAP)); } } @@ -483,6 +485,13 @@ public class ToggleScreenMagnificationPreferenceFragment extends MAGNIFICATION_CONTROLLER_NAME); final List list = new ArrayList<>(); + if (android.view.accessibility.Flags.a11yQsShortcut()) { + if (hasShortcutType(shortcutTypes, UserShortcutType.QUICK_SETTINGS)) { + final CharSequence qsTitle = context.getText( + R.string.accessibility_feature_shortcut_setting_summary_quick_settings); + list.add(qsTitle); + } + } if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) { list.add(getSoftwareShortcutTypeSummary(context)); } @@ -497,7 +506,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends list.add(tripleTapTitle); } if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { - if (hasShortcutType(shortcutTypes, UserShortcutType.TWOFINGERTRIPLETAP)) { + if (hasShortcutType(shortcutTypes, UserShortcutType.TWOFINGER_DOUBLETAP)) { final CharSequence twoFingerTripleTapTitle = context.getText( R.string.accessibility_shortcut_two_finger_double_tap_keyword); list.add(twoFingerTripleTapTitle); @@ -678,15 +687,34 @@ public class ToggleScreenMagnificationPreferenceFragment extends optInMagnificationValueToSettings(context, UserShortcutType.TRIPLETAP); } if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { - if (((shortcutTypes & UserShortcutType.TWOFINGERTRIPLETAP) - == UserShortcutType.TWOFINGERTRIPLETAP)) { - optInMagnificationValueToSettings(context, UserShortcutType.TWOFINGERTRIPLETAP); + if (((shortcutTypes & UserShortcutType.TWOFINGER_DOUBLETAP) + == UserShortcutType.TWOFINGER_DOUBLETAP)) { + optInMagnificationValueToSettings(context, UserShortcutType.TWOFINGER_DOUBLETAP); + } + } + if (android.view.accessibility.Flags.a11yQsShortcut()) { + if (((shortcutTypes & UserShortcutType.QUICK_SETTINGS) + == UserShortcutType.QUICK_SETTINGS)) { + optInMagnificationValueToSettings(context, UserShortcutType.QUICK_SETTINGS); } } } - private static void optInMagnificationValueToSettings(Context context, - @UserShortcutType int shortcutType) { + private static void optInMagnificationValueToSettings( + Context context, @UserShortcutType int shortcutType) { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class); + if (a11yManager != null) { + a11yManager.enableShortcutsForTargets( + /* enable= */ true, + shortcutType, + Set.of(MAGNIFICATION_CONTROLLER_NAME), + UserHandle.myUserId() + ); + } + return; + } + if (shortcutType == UserShortcutType.TRIPLETAP) { Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, ON); @@ -694,8 +722,9 @@ public class ToggleScreenMagnificationPreferenceFragment extends } if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { - if (shortcutType == UserShortcutType.TWOFINGERTRIPLETAP) { - Settings.Secure.putInt(context.getContentResolver(), + if (shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP) { + Settings.Secure.putInt( + context.getContentResolver(), Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, ON); return; @@ -743,15 +772,34 @@ public class ToggleScreenMagnificationPreferenceFragment extends optOutMagnificationValueFromSettings(context, UserShortcutType.TRIPLETAP); } if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { - if (((shortcutTypes & UserShortcutType.TWOFINGERTRIPLETAP) - == UserShortcutType.TWOFINGERTRIPLETAP)) { - optOutMagnificationValueFromSettings(context, UserShortcutType.TWOFINGERTRIPLETAP); + if (((shortcutTypes & UserShortcutType.TWOFINGER_DOUBLETAP) + == UserShortcutType.TWOFINGER_DOUBLETAP)) { + optOutMagnificationValueFromSettings(context, UserShortcutType.TWOFINGER_DOUBLETAP); + } + } + if (android.view.accessibility.Flags.a11yQsShortcut()) { + if (((shortcutTypes & UserShortcutType.QUICK_SETTINGS) + == UserShortcutType.QUICK_SETTINGS)) { + optOutMagnificationValueFromSettings(context, UserShortcutType.QUICK_SETTINGS); } } } private static void optOutMagnificationValueFromSettings(Context context, @UserShortcutType int shortcutType) { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class); + if (a11yManager != null) { + a11yManager.enableShortcutsForTargets( + /* enable= */ false, + shortcutType, + Set.of(MAGNIFICATION_CONTROLLER_NAME), + UserHandle.myUserId() + ); + } + return; + } + if (shortcutType == UserShortcutType.TRIPLETAP) { Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF); @@ -759,8 +807,9 @@ public class ToggleScreenMagnificationPreferenceFragment extends } if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { - if (shortcutType == UserShortcutType.TWOFINGERTRIPLETAP) { - Settings.Secure.putInt(context.getContentResolver(), + if (shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP) { + Settings.Secure.putInt( + context.getContentResolver(), Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, OFF); return; @@ -803,10 +852,10 @@ public class ToggleScreenMagnificationPreferenceFragment extends exist |= hasMagnificationValueInSettings(context, UserShortcutType.TRIPLETAP); } if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { - if (((shortcutTypes & UserShortcutType.TWOFINGERTRIPLETAP) - == UserShortcutType.TWOFINGERTRIPLETAP)) { + if (((shortcutTypes & UserShortcutType.TWOFINGER_DOUBLETAP) + == UserShortcutType.TWOFINGER_DOUBLETAP)) { exist |= hasMagnificationValueInSettings(context, - UserShortcutType.TWOFINGERTRIPLETAP); + UserShortcutType.TWOFINGER_DOUBLETAP); } } return exist; @@ -820,7 +869,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends } if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { - if (shortcutType == UserShortcutType.TWOFINGERTRIPLETAP) { + if (shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP) { return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, OFF) == ON; @@ -857,8 +906,8 @@ public class ToggleScreenMagnificationPreferenceFragment extends shortcutTypes |= UserShortcutType.TRIPLETAP; } if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { - if (hasMagnificationValuesInSettings(context, UserShortcutType.TWOFINGERTRIPLETAP)) { - shortcutTypes |= UserShortcutType.TWOFINGERTRIPLETAP; + if (hasMagnificationValuesInSettings(context, UserShortcutType.TWOFINGER_DOUBLETAP)) { + shortcutTypes |= UserShortcutType.TWOFINGER_DOUBLETAP; } } return shortcutTypes; diff --git a/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java b/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java index aba342a792e..976fffb2aca 100644 --- a/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java +++ b/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java @@ -21,6 +21,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED; +import static android.provider.Settings.Secure.ACCESSIBILITY_QS_TARGETS; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME; @@ -98,6 +99,9 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { private static final Uri TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING = Settings.Secure.getUriFor(ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED); + private static final Uri QUICK_SETTINGS_SHORTCUT_SETTING = + Settings.Secure.getUriFor(ACCESSIBILITY_QS_TARGETS); + @VisibleForTesting static final Uri[] SHORTCUT_SETTINGS = { VOLUME_KEYS_SHORTCUT_SETTING, @@ -105,6 +109,7 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { BUTTON_SHORTCUT_SETTING, TRIPLE_TAP_SHORTCUT_SETTING, TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING, + QUICK_SETTINGS_SHORTCUT_SETTING, }; private Set mShortcutTargets; @@ -171,7 +176,9 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { } else if (TRIPLE_TAP_SHORTCUT_SETTING.equals(uri)) { refreshPreferenceController(TripleTapShortcutOptionController.class); } else if (TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING.equals(uri)) { - refreshPreferenceController(TwoFingersDoubleTapShortcutOptionController.class); + refreshPreferenceController(TwoFingerDoubleTapShortcutOptionController.class); + } else if (QUICK_SETTINGS_SHORTCUT_SETTING.equals(uri)) { + refreshPreferenceController(QuickSettingsShortcutOptionController.class); } PreferredShortcuts.updatePreferredShortcutsFromSettings( diff --git a/src/com/android/settings/accessibility/shortcuts/QuickSettingsShortcutOptionController.java b/src/com/android/settings/accessibility/shortcuts/QuickSettingsShortcutOptionController.java new file mode 100644 index 00000000000..27f6bc9d281 --- /dev/null +++ b/src/com/android/settings/accessibility/shortcuts/QuickSettingsShortcutOptionController.java @@ -0,0 +1,142 @@ +/* + * 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.shortcuts; + +import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType.INVISIBLE_TOGGLE; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.ComponentName; +import android.content.Context; +import android.os.UserHandle; +import android.service.quicksettings.TileService; +import android.util.ArraySet; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.Flags; + +import androidx.annotation.NonNull; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.internal.accessibility.common.ShortcutConstants; +import com.android.internal.accessibility.util.AccessibilityUtils; +import com.android.settings.R; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * A controller handles displaying the quick settings shortcut option preference and + * configuring the shortcut. + */ +public class QuickSettingsShortcutOptionController extends ShortcutOptionPreferenceController { + public QuickSettingsShortcutOptionController( + @NonNull Context context, @NonNull String preferenceKey) { + super(context, preferenceKey); + } + + @ShortcutConstants.UserShortcutType + @Override + protected int getShortcutType() { + return ShortcutConstants.UserShortcutType.QUICK_SETTINGS; + } + + @Override + public void displayPreference(@NonNull PreferenceScreen screen) { + super.displayPreference(screen); + final Preference preference = screen.findPreference(getPreferenceKey()); + if (preference instanceof ShortcutOptionPreference shortcutOptionPreference) { + shortcutOptionPreference.setTitle( + R.string.accessibility_shortcut_edit_dialog_title_quick_settings); + shortcutOptionPreference.setSummary( + R.string.accessibility_shortcut_edit_dialog_summary_quick_settings); + shortcutOptionPreference.setIntroImageResId( + R.drawable.a11y_shortcut_type_quick_settings); + } + } + + @Override + protected boolean isShortcutAvailable() { + return Flags.a11yQsShortcut() + && TileService.isQuickSettingsSupported() + && allTargetsHasQsTile() + && allTargetsHasValidQsTileUseCase(); + } + + private boolean allTargetsHasQsTile() { + AccessibilityManager accessibilityManager = mContext.getSystemService( + AccessibilityManager.class); + if (accessibilityManager == null) { + return false; + } + + Map a11yFeatureToTileMap = + accessibilityManager.getA11yFeatureToTileMap(UserHandle.myUserId()); + if (a11yFeatureToTileMap.isEmpty()) { + return false; + } + for (String target : getShortcutTargets()) { + ComponentName targetComponentName = ComponentName.unflattenFromString(target); + if (!a11yFeatureToTileMap.containsKey(targetComponentName)) { + return false; + } + } + + return true; + } + + /** + * Returns true if all targets have valid QS Tile shortcut use case. + * + *

+ * Note: We don't want to promote the qs option in the edit shortcuts screen for + * a standard AccessibilityService, because the Tile is provided by the owner of the + * AccessibilityService, and they don't have control to enable the A11yService themselves + * which makes the TileService not acting as the other a11y shortcut like FAB where the user + * can turn on/off the feature by toggling the shortcut. + * + * A standard AccessibilityService normally won't create a TileService because the + * above mentioned reason. In any case where the standard AccessibilityService provides a tile, + * we'll hide it from the Setting's UI. + *

+ */ + private boolean allTargetsHasValidQsTileUseCase() { + AccessibilityManager accessibilityManager = mContext.getSystemService( + AccessibilityManager.class); + if (accessibilityManager == null) { + return false; + } + + List installedServices = + accessibilityManager.getInstalledAccessibilityServiceList(); + final Set standardA11yServices = new ArraySet<>(); + for (AccessibilityServiceInfo serviceInfo : installedServices) { + if (AccessibilityUtils.getAccessibilityServiceFragmentType(serviceInfo) + != INVISIBLE_TOGGLE) { + standardA11yServices.add(serviceInfo.getComponentName().flattenToString()); + } + } + + for (String target : getShortcutTargets()) { + if (standardA11yServices.contains(target)) { + return false; + } + } + + return true; + } +} diff --git a/src/com/android/settings/accessibility/shortcuts/ShortcutOptionPreferenceController.java b/src/com/android/settings/accessibility/shortcuts/ShortcutOptionPreferenceController.java index 4d3555468f9..defb256c8f5 100644 --- a/src/com/android/settings/accessibility/shortcuts/ShortcutOptionPreferenceController.java +++ b/src/com/android/settings/accessibility/shortcuts/ShortcutOptionPreferenceController.java @@ -18,6 +18,8 @@ package com.android.settings.accessibility.shortcuts; import android.content.Context; import android.os.UserHandle; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.Flags; import androidx.annotation.NonNull; import androidx.preference.Preference; @@ -116,6 +118,16 @@ public abstract class ShortcutOptionPreferenceController extends BasePreferenceC Set shortcutTargets = getShortcutTargets(); @ShortcutConstants.UserShortcutType int shortcutType = getShortcutType(); + if (Flags.a11yQsShortcut()) { + AccessibilityManager a11yManager = mContext.getSystemService( + AccessibilityManager.class); + if (a11yManager != null) { + a11yManager.enableShortcutsForTargets(enable, shortcutType, shortcutTargets, + UserHandle.myUserId()); + } + return; + } + if (enable) { for (String target : shortcutTargets) { ShortcutUtils.optInValueToSettings(mContext, shortcutType, target); diff --git a/src/com/android/settings/accessibility/shortcuts/SoftwareShortcutOptionPreferenceController.java b/src/com/android/settings/accessibility/shortcuts/SoftwareShortcutOptionPreferenceController.java index 24098c81f38..861bebd83ef 100644 --- a/src/com/android/settings/accessibility/shortcuts/SoftwareShortcutOptionPreferenceController.java +++ b/src/com/android/settings/accessibility/shortcuts/SoftwareShortcutOptionPreferenceController.java @@ -21,6 +21,7 @@ import static com.android.internal.accessibility.AccessibilityShortcutController import android.content.Context; import android.provider.Settings; import android.view.View; +import android.view.accessibility.Flags; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.settings.R; @@ -65,6 +66,9 @@ public abstract class SoftwareShortcutOptionPreferenceController @Override protected void enableShortcutForTargets(boolean enable) { super.enableShortcutForTargets(enable); + if (Flags.a11yQsShortcut()) { + return; + } if (enable) { // Update the A11y FAB size to large when the Magnification shortcut is enabled diff --git a/src/com/android/settings/accessibility/shortcuts/TripleTapShortcutOptionController.java b/src/com/android/settings/accessibility/shortcuts/TripleTapShortcutOptionController.java index 0eb1ee5acd7..e43aeb29b5d 100644 --- a/src/com/android/settings/accessibility/shortcuts/TripleTapShortcutOptionController.java +++ b/src/com/android/settings/accessibility/shortcuts/TripleTapShortcutOptionController.java @@ -21,6 +21,7 @@ import static com.android.internal.accessibility.AccessibilityShortcutController import android.content.Context; import android.icu.text.MessageFormat; import android.provider.Settings; +import android.view.accessibility.Flags; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; @@ -105,6 +106,11 @@ public class TripleTapShortcutOptionController extends ShortcutOptionPreferenceC @Override protected void enableShortcutForTargets(boolean enable) { + if (Flags.a11yQsShortcut()) { + super.enableShortcutForTargets(enable); + return; + } + Settings.Secure.putInt( mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, diff --git a/src/com/android/settings/accessibility/shortcuts/TwoFingersDoubleTapShortcutOptionController.java b/src/com/android/settings/accessibility/shortcuts/TwoFingerDoubleTapShortcutOptionController.java similarity index 90% rename from src/com/android/settings/accessibility/shortcuts/TwoFingersDoubleTapShortcutOptionController.java rename to src/com/android/settings/accessibility/shortcuts/TwoFingerDoubleTapShortcutOptionController.java index 64ed7bdbd19..83ba6e4e9b9 100644 --- a/src/com/android/settings/accessibility/shortcuts/TwoFingersDoubleTapShortcutOptionController.java +++ b/src/com/android/settings/accessibility/shortcuts/TwoFingerDoubleTapShortcutOptionController.java @@ -36,17 +36,17 @@ import java.util.Set; * A controller handles displaying the two fingers double tap shortcut option preference and * configuring the shortcut. */ -public class TwoFingersDoubleTapShortcutOptionController +public class TwoFingerDoubleTapShortcutOptionController extends ShortcutOptionPreferenceController { - public TwoFingersDoubleTapShortcutOptionController(Context context, String preferenceKey) { + public TwoFingerDoubleTapShortcutOptionController(Context context, String preferenceKey) { super(context, preferenceKey); } @ShortcutConstants.UserShortcutType @Override protected int getShortcutType() { - return ShortcutConstants.UserShortcutType.TRIPLETAP; + return ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP; } @Override @@ -90,6 +90,10 @@ public class TwoFingersDoubleTapShortcutOptionController @Override protected void enableShortcutForTargets(boolean enable) { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + super.enableShortcutForTargets(enable); + return; + } Settings.Secure.putInt( mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, diff --git a/src/com/android/settings/accessibility/shortcuts/VolumeKeysShortcutOptionController.java b/src/com/android/settings/accessibility/shortcuts/VolumeKeysShortcutOptionController.java index 9083e7ccc88..e8e261cc790 100644 --- a/src/com/android/settings/accessibility/shortcuts/VolumeKeysShortcutOptionController.java +++ b/src/com/android/settings/accessibility/shortcuts/VolumeKeysShortcutOptionController.java @@ -17,6 +17,7 @@ package com.android.settings.accessibility.shortcuts; import android.content.Context; +import android.view.accessibility.Flags; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; @@ -64,6 +65,10 @@ public class VolumeKeysShortcutOptionController extends ShortcutOptionPreference @Override protected void enableShortcutForTargets(boolean enable) { super.enableShortcutForTargets(enable); + if (Flags.a11yQsShortcut()) { + return; + } + if (enable) { AccessibilityUtil.skipVolumeShortcutDialogTimeoutRestriction(mContext); } diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java index d6a2492b884..404dbe5abb3 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java @@ -98,7 +98,20 @@ public final class AccessibilityGestureNavigationTutorialTest { @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void createTutorialPages_turnOnTwoFingerTripleTapShortcut_hasOnePage() { - mShortcutTypes |= UserShortcutType.TWOFINGERTRIPLETAP; + mShortcutTypes |= UserShortcutType.TWOFINGER_DOUBLETAP; + + final AlertDialog alertDialog = + createAccessibilityTutorialDialog(mContext, mShortcutTypes); + + assertThat(createShortcutTutorialPages(mContext, + mShortcutTypes)).hasSize(/* expectedSize= */ 1); + assertThat(alertDialog).isNotNull(); + } + + @Test + @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) + public void createTutorialPages_turnOnQuickSettingShortcut_hasOnePage() { + mShortcutTypes |= UserShortcutType.QUICK_SETTINGS; final AlertDialog alertDialog = createAccessibilityTutorialDialog(mContext, mShortcutTypes); diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java index 4607a59fce0..f108b8e4bd6 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java @@ -28,15 +28,24 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; +import android.app.Activity; +import android.app.Application; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; +import android.icu.text.CaseMap; import android.os.Bundle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.Flags; import android.widget.PopupWindow; import androidx.annotation.Nullable; @@ -46,9 +55,14 @@ import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settings.SubSettings; +import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment; import com.android.settings.testutils.shadow.ShadowFragment; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -60,13 +74,14 @@ import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowApplication; +import java.util.Locale; + /** Tests for {@link AccessibilityShortcutPreferenceFragment} */ @RunWith(RobolectricTestRunner.class) @Config(shadows = { com.android.settings.testutils.shadow.ShadowFragment.class, }) public class AccessibilityShortcutPreferenceFragmentTest { - private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example"; private static final String PLACEHOLDER_CLASS_NAME = PLACEHOLDER_PACKAGE_NAME + ".placeholder"; private static final String PLACEHOLDER_TILE_CLASS_NAME = @@ -83,7 +98,8 @@ public class AccessibilityShortcutPreferenceFragmentTest { Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; private static final String HARDWARE_SHORTCUT_KEY = Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; - + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private TestAccessibilityShortcutPreferenceFragment mFragment; private PreferenceScreen mScreen; private Context mContext = ApplicationProvider.getApplicationContext(); @@ -206,6 +222,7 @@ public class AccessibilityShortcutPreferenceFragmentTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) @Config(shadows = ShadowFragment.class) public void restoreValueFromSavedInstanceState_showTooltipView() { mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat); @@ -222,6 +239,15 @@ public class AccessibilityShortcutPreferenceFragmentTest { assertThat(getLatestPopupWindow().isShowing()).isTrue(); } + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + @Config(shadows = ShadowFragment.class) + public void showQuickSettingsTooltipIfNeeded_qsFlagOn_dontShowTooltipView() { + mFragment.showQuickSettingsTooltipIfNeeded(QuickSettingsTooltipType.GUIDE_TO_EDIT); + + assertThat(getLatestPopupWindow()).isNull(); + } + @Test @Config(shadows = ShadowFragment.class) public void showGeneralCategory_shouldInitCategory() { @@ -238,6 +264,50 @@ public class AccessibilityShortcutPreferenceFragmentTest { assertThat(mFragment.getGeneralCategoryDescription(null)).isNotNull(); } + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN) + public void onSettingsClicked_editShortcutsFullScreenFlagOn_showFullScreenEditShortcutScreen() { + Activity activity = Robolectric.setupActivity(FragmentActivity.class); + when(mFragment.getContext()).thenReturn(activity); + Context context = mFragment.getContext(); + final ShortcutPreference shortcutPreference = + new ShortcutPreference(context, /* attrs= */ null); + + mFragment.onSettingsClicked(shortcutPreference); + + Intent intent = shadowOf( + (Application) context.getApplicationContext()).getNextStartedActivity(); + assertThat(intent).isNotNull(); + assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN); + assertThat(intent.getComponent()).isEqualTo( + new ComponentName(context, SubSettings.class)); + assertThat(intent.getExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) + .isEqualTo(EditShortcutsPreferenceFragment.class.getName()); + } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void getShortcutTypeSummary_shortcutSummaryIsCorrectlySet() { + final PreferredShortcut userPreferredShortcut = new PreferredShortcut( + PLACEHOLDER_COMPONENT_NAME.flattenToString(), + UserShortcutType.HARDWARE | UserShortcutType.QUICK_SETTINGS); + putUserShortcutTypeIntoSharedPreference(mContext, userPreferredShortcut); + final ShortcutPreference shortcutPreference = + new ShortcutPreference(mContext, /* attrs= */ null); + shortcutPreference.setChecked(true); + shortcutPreference.setSettingsEditable(true); + mFragment.mShortcutPreference = shortcutPreference; + String expected = CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), + /* iter= */ null, + mContext.getString( + R.string.accessibility_feature_shortcut_setting_summary_quick_settings) + + ", " + + mContext.getString(R.string.accessibility_shortcut_hardware_keyword)); + + String summary = mFragment.getShortcutTypeSummary(mContext).toString(); + assertThat(summary).isEqualTo(expected); + } + private void callEmptyOnClicked(DialogInterface dialog, int which) {} private void putStringIntoSettings(String key, String componentName) { diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java index 78256774098..2d5deeb1fcb 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java @@ -18,6 +18,10 @@ package com.android.settings.accessibility; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + import android.accessibilityservice.AccessibilityServiceInfo; import android.content.ComponentName; import android.content.Context; @@ -25,20 +29,30 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Build; +import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.Flags; import androidx.test.core.app.ApplicationProvider; +import com.android.internal.accessibility.util.ShortcutUtils; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType; +import com.android.settings.testutils.AccessibilityTestUtils; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.util.Set; import java.util.StringJoiner; @RunWith(RobolectricTestRunner.class) @@ -55,14 +69,18 @@ public final class AccessibilityUtilTest { Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; private static final String HARDWARE_SHORTCUT_KEY = Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; + private static final String QUICK_SETTINGS_SHORTCUT_KEY = + Settings.Secure.ACCESSIBILITY_QS_TARGETS; private static final String PLACEHOLDER_SETTING_FEATURE = "placeholderSettingFeature"; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private Context mContext; @Before public void setUp() { - mContext = ApplicationProvider.getApplicationContext(); + mContext = spy(ApplicationProvider.getApplicationContext()); } @Test @@ -151,11 +169,12 @@ public final class AccessibilityUtilTest { public void getUserShortcutTypeFromSettings_putOneValue_hasValue() { setShortcut(UserShortcutType.SOFTWARE, MOCK_COMPONENT_NAME.flattenToString()); - final int shortcutType = AccessibilityUtil.getUserShortcutTypesFromSettings(mContext, + final int shortcutTypes = AccessibilityUtil.getUserShortcutTypesFromSettings(mContext, MOCK_COMPONENT_NAME); - assertThat( - (shortcutType & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE).isTrue(); + assertThat(shortcutTypes).isEqualTo( + UserShortcutType.SOFTWARE + ); } @Test @@ -163,16 +182,34 @@ public final class AccessibilityUtilTest { setShortcut(UserShortcutType.SOFTWARE, MOCK_COMPONENT_NAME.flattenToString()); setShortcut(UserShortcutType.HARDWARE, MOCK_COMPONENT_NAME.flattenToString()); - final int shortcutType = AccessibilityUtil.getUserShortcutTypesFromSettings(mContext, + final int shortcutTypes = AccessibilityUtil.getUserShortcutTypesFromSettings(mContext, MOCK_COMPONENT_NAME); - assertThat( - (shortcutType & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE).isTrue(); - assertThat( - (shortcutType & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE).isTrue(); + assertThat(shortcutTypes).isEqualTo( + UserShortcutType.SOFTWARE + | UserShortcutType.HARDWARE + ); } @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void getUserShortcutTypeFromSettings_threeShortcutTypesChosen() { + setShortcut(UserShortcutType.SOFTWARE, MOCK_COMPONENT_NAME.flattenToString()); + setShortcut(UserShortcutType.HARDWARE, MOCK_COMPONENT_NAME.flattenToString()); + setShortcut(UserShortcutType.QUICK_SETTINGS, MOCK_COMPONENT_NAME.flattenToString()); + + final int shortcutTypes = AccessibilityUtil.getUserShortcutTypesFromSettings(mContext, + MOCK_COMPONENT_NAME); + + assertThat(shortcutTypes).isEqualTo( + UserShortcutType.SOFTWARE + | UserShortcutType.HARDWARE + | UserShortcutType.QUICK_SETTINGS + ); + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void optInAllValuesToSettings_optInValue_haveMatchString() { clearShortcuts(); int shortcutTypes = UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE; @@ -187,6 +224,24 @@ public final class AccessibilityUtilTest { } @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void optInAllValuesToSettings_optInValue_callsA11yManager() { + AccessibilityManager a11yManager = + AccessibilityTestUtils.setupMockAccessibilityManager(mContext); + Set shortcutTargets = Set.of(MOCK_COMPONENT_NAME.flattenToString()); + int shortcutTypes = UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE + | UserShortcutType.QUICK_SETTINGS; + + AccessibilityUtil.optInAllValuesToSettings(mContext, shortcutTypes, MOCK_COMPONENT_NAME); + + verify(a11yManager).enableShortcutsForTargets( + /* enable= */ true, shortcutTypes, + shortcutTargets, UserHandle.myUserId()); + verifyNoMoreInteractions(a11yManager); + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void optInValueToSettings_optInValue_haveMatchString() { setShortcut(UserShortcutType.SOFTWARE, MOCK_COMPONENT_NAME.flattenToString()); @@ -199,6 +254,23 @@ public final class AccessibilityUtilTest { } @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void optInValueToSettings_optInValue_callsA11yManager() { + AccessibilityManager a11yManager = + AccessibilityTestUtils.setupMockAccessibilityManager(mContext); + Set shortcutTargets = Set.of(MOCK_COMPONENT_NAME2.flattenToString()); + + AccessibilityUtil.optInValueToSettings( + mContext, UserShortcutType.HARDWARE, MOCK_COMPONENT_NAME2); + + verify(a11yManager).enableShortcutsForTargets( + /* enable= */ true, UserShortcutType.HARDWARE, + shortcutTargets, UserHandle.myUserId()); + verifyNoMoreInteractions(a11yManager); + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void optInValueToSettings_optInTwoValues_haveMatchString() { setShortcut(UserShortcutType.SOFTWARE, MOCK_COMPONENT_NAME.flattenToString()); @@ -213,6 +285,7 @@ public final class AccessibilityUtilTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void optOutAllValuesToSettings_optOutValue_emptyString() { setShortcut(UserShortcutType.SOFTWARE, MOCK_COMPONENT_NAME.flattenToString()); setShortcut(UserShortcutType.HARDWARE, MOCK_COMPONENT_NAME.flattenToString()); @@ -227,6 +300,27 @@ public final class AccessibilityUtilTest { } @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void optOutAllValuesToSettings_optOutValue_callsA1yManager() { + AccessibilityManager a11yManager = + AccessibilityTestUtils.setupMockAccessibilityManager(mContext); + int shortcutTypes = + UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE + | UserShortcutType.QUICK_SETTINGS; + Set shortcutTargets = Set.of(MOCK_COMPONENT_NAME.flattenToString()); + + AccessibilityUtil.optOutAllValuesFromSettings(mContext, shortcutTypes, + MOCK_COMPONENT_NAME); + + verify(a11yManager).enableShortcutsForTargets( + /* enable= */ false, + shortcutTypes, + shortcutTargets, UserHandle.myUserId()); + verifyNoMoreInteractions(a11yManager); + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void optOutValueFromSettings_optOutValue_emptyString() { setShortcut(UserShortcutType.SOFTWARE, MOCK_COMPONENT_NAME.flattenToString()); @@ -237,6 +331,7 @@ public final class AccessibilityUtilTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void optOutValueFromSettings_optOutValue_haveMatchString() { setShortcut(UserShortcutType.SOFTWARE, MOCK_COMPONENT_NAME.flattenToString(), MOCK_COMPONENT_NAME2.flattenToString()); @@ -248,6 +343,55 @@ public final class AccessibilityUtilTest { MOCK_COMPONENT_NAME.flattenToString()); } + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void optOutValueFromSettings_optOutValue_callsA11yManager() { + AccessibilityManager a11yManager = + AccessibilityTestUtils.setupMockAccessibilityManager(mContext); + Set shortcutTargets = Set.of(MOCK_COMPONENT_NAME.flattenToString()); + + AccessibilityUtil.optOutValueFromSettings( + mContext, UserShortcutType.QUICK_SETTINGS, MOCK_COMPONENT_NAME); + + verify(a11yManager).enableShortcutsForTargets( + /* enable= */ false, UserShortcutType.QUICK_SETTINGS, + shortcutTargets, UserHandle.myUserId()); + verifyNoMoreInteractions(a11yManager); + } + + @Test + public void convertKeyFromSettings_shortcutTypeSoftware() { + assertThat(AccessibilityUtil.convertKeyFromSettings(UserShortcutType.SOFTWARE)) + .isEqualTo(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); + } + + @Test + public void convertKeyFromSettings_shortcutTypeHardware() { + assertThat(AccessibilityUtil.convertKeyFromSettings(UserShortcutType.HARDWARE)) + .isEqualTo(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); + } + + @Test + public void convertKeyFromSettings_shortcutTypeTripleTap() { + assertThat(AccessibilityUtil.convertKeyFromSettings(UserShortcutType.TRIPLETAP)) + .isEqualTo(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); + } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void convertKeyFromSettings_shortcutTypeMultiFingersMultiTap() { + assertThat(AccessibilityUtil.convertKeyFromSettings(UserShortcutType.TWOFINGER_DOUBLETAP)) + .isEqualTo( + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED); + } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void convertKeyFromSettings_shortcutTypeQuickSettings() { + assertThat(AccessibilityUtil.convertKeyFromSettings(UserShortcutType.QUICK_SETTINGS)) + .isEqualTo(Settings.Secure.ACCESSIBILITY_QS_TARGETS); + } + private AccessibilityServiceInfo getMockAccessibilityServiceInfo() { final ApplicationInfo applicationInfo = new ApplicationInfo(); final ServiceInfo serviceInfo = new ServiceInfo(); @@ -287,12 +431,12 @@ public final class AccessibilityUtilTest { shortcutComponents.add(componentName); } Settings.Secure.putString(mContext.getContentResolver(), - shortcutType == UserShortcutType.SOFTWARE ? SOFTWARE_SHORTCUT_KEY - : HARDWARE_SHORTCUT_KEY, shortcutComponents.toString()); + ShortcutUtils.convertToKey(shortcutType), shortcutComponents.toString()); } private void clearShortcuts() { Settings.Secure.putString(mContext.getContentResolver(), SOFTWARE_SHORTCUT_KEY, ""); Settings.Secure.putString(mContext.getContentResolver(), HARDWARE_SHORTCUT_KEY, ""); + Settings.Secure.putString(mContext.getContentResolver(), QUICK_SETTINGS_SHORTCUT_KEY, ""); } } diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java index 9155113d6ab..1a82a25b2f7 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java @@ -31,10 +31,13 @@ import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Context; import android.os.Bundle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.Flags; import android.widget.PopupWindow; import androidx.fragment.app.FragmentActivity; @@ -49,6 +52,7 @@ import com.android.settings.testutils.shadow.ShadowFragment; import com.android.settings.widget.SettingsMainSwitchPreference; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -65,6 +69,8 @@ import java.util.List; @RunWith(RobolectricTestRunner.class) @Config(shadows = ShadowFragment.class) public class ToggleColorInversionPreferenceFragmentTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private final Context mContext = ApplicationProvider.getApplicationContext(); private TestToggleColorInversionPreferenceFragment mFragment; private PreferenceScreen mScreen; @@ -131,6 +137,7 @@ public class ToggleColorInversionPreferenceFragmentTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void onPreferenceToggled_colorCorrectDisabled_shouldReturnTrueAndShowTooltipView() { Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, OFF); diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java index 94db63b6d37..850d1d79e09 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java @@ -35,10 +35,13 @@ import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Context; import android.os.Bundle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.Flags; import android.widget.PopupWindow; import androidx.fragment.app.FragmentActivity; @@ -54,6 +57,7 @@ import com.android.settings.widget.SettingsMainSwitchPreference; import com.android.settingslib.widget.SelectorWithWidgetPreference; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -70,6 +74,8 @@ import java.util.List; @RunWith(RobolectricTestRunner.class) @Config(shadows = ShadowFragment.class) public class ToggleDaltonizerPreferenceFragmentTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private final Context mContext = ApplicationProvider.getApplicationContext(); private TestToggleDaltonizerPreferenceFragment mFragment; private PreferenceScreen mScreen; @@ -154,6 +160,7 @@ public class ToggleDaltonizerPreferenceFragmentTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void onPreferenceToggled_colorCorrectDisabled_shouldReturnTrueAndShowTooltipView() { Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, OFF); diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java index 70c7cd6f777..e963bd01f68 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java @@ -34,10 +34,11 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; +import android.icu.text.CaseMap; import android.os.Bundle; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; @@ -76,6 +77,8 @@ import org.robolectric.annotation.LooperMode; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowApplication; +import java.util.Locale; + /** Tests for {@link ToggleFeaturePreferenceFragment} */ @RunWith(RobolectricTestRunner.class) @LooperMode(LooperMode.Mode.LEGACY) @@ -83,9 +86,8 @@ import org.robolectric.shadows.ShadowApplication; ShadowFragment.class, }) public class ToggleFeaturePreferenceFragmentTest { - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example"; private static final String PLACEHOLDER_CLASS_NAME = PLACEHOLDER_PACKAGE_NAME + ".placeholder"; @@ -295,6 +297,7 @@ public class ToggleFeaturePreferenceFragmentTest { } @Test + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) @Config(shadows = ShadowFragment.class) public void onPreferenceToggledOnEnabledService_showTooltipView() { mFragment.onPreferenceToggled( @@ -304,7 +307,7 @@ public class ToggleFeaturePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(com.android.settings.accessibility.Flags.FLAG_REMOVE_QS_TOOLTIP_IN_SUW) + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_REMOVE_QS_TOOLTIP_IN_SUW) @Config(shadows = ShadowFragment.class) public void onPreferenceToggledOnEnabledService_inSuw_toolTipViewShouldNotShow() { Intent suwIntent = new Intent(); @@ -318,6 +321,7 @@ public class ToggleFeaturePreferenceFragmentTest { } @Test + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) @Config(shadows = ShadowFragment.class) public void onPreferenceToggledOnEnabledService_tooltipViewShown_notShowTooltipView() { mFragment.onPreferenceToggled( @@ -348,7 +352,7 @@ public class ToggleFeaturePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) + @EnableFlags(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) public void createAppInfoPreference_withValidComponentName() { when(mPackageManager.isPackageAvailable(PLACEHOLDER_PACKAGE_NAME)).thenReturn(true); mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; @@ -363,7 +367,7 @@ public class ToggleFeaturePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) + @EnableFlags(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) public void createAppInfoPreference_noComponentName_shouldBeNull() { mFragment.mComponentName = null; @@ -373,7 +377,7 @@ public class ToggleFeaturePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) + @EnableFlags(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) public void createAppInfoPreference_withUnavailablePackage_shouldBeNull() { when(mPackageManager.isPackageAvailable(PLACEHOLDER_PACKAGE_NAME)).thenReturn(false); mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; @@ -384,7 +388,7 @@ public class ToggleFeaturePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) + @EnableFlags(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) public void createAppInfoPreference_inSetupWizard_shouldBeNull() { when(mFragment.isAnySetupWizard()).thenReturn(true); mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; @@ -421,6 +425,40 @@ public class ToggleFeaturePreferenceFragmentTest { .isEqualTo(PLACEHOLDER_COMPONENT_NAME.flattenToString()); } + @Test + @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) + @Config(shadows = ShadowFragment.class) + public void showQuickSettingsTooltipIfNeeded_qsFlagOn_dontShowTooltipView() { + mFragment.showQuickSettingsTooltipIfNeeded(QuickSettingsTooltipType.GUIDE_TO_EDIT); + + assertThat(getLatestPopupWindow()).isNull(); + } + + @Test + @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) + public void getShortcutTypeSummary_shortcutSummaryIsCorrectlySet() { + final PreferredShortcut userPreferredShortcut = new PreferredShortcut( + PLACEHOLDER_COMPONENT_NAME.flattenToString(), + UserShortcutType.HARDWARE | UserShortcutType.QUICK_SETTINGS); + putUserShortcutTypeIntoSharedPreference(mContext, userPreferredShortcut); + final ShortcutPreference shortcutPreference = + new ShortcutPreference(mContext, /* attrs= */ null); + shortcutPreference.setChecked(true); + shortcutPreference.setSettingsEditable(true); + mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; + mFragment.mShortcutPreference = shortcutPreference; + String expected = CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), + /* iter= */ null, + mContext.getString( + R.string.accessibility_feature_shortcut_setting_summary_quick_settings) + + ", " + + mContext.getString(R.string.accessibility_shortcut_hardware_keyword)); + + String summary = mFragment.getShortcutTypeSummary(mContext).toString(); + + assertThat(summary).isEqualTo(expected); + } + private void putSecureStringIntoSettings(String key, String componentName) { Settings.Secure.putString(mContext.getContentResolver(), key, componentName); } diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java index b459faafac1..3d24fbb7237 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.settings.SettingsEnums; @@ -39,13 +40,16 @@ import android.content.DialogInterface; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; +import android.icu.text.CaseMap; import android.net.Uri; import android.os.Bundle; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.DeviceConfig; import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; import androidx.appcompat.app.AlertDialog; import androidx.preference.Preference; @@ -57,6 +61,7 @@ import com.android.settings.DialogCreatable; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType; +import com.android.settings.testutils.AccessibilityTestUtils; import com.android.settings.testutils.shadow.ShadowDeviceConfig; import com.android.settings.testutils.shadow.ShadowStorageManager; import com.android.settings.testutils.shadow.ShadowUserManager; @@ -80,6 +85,8 @@ import org.robolectric.util.ReflectionHelpers; import java.util.Collection; import java.util.List; +import java.util.Locale; +import java.util.Set; /** Tests for {@link ToggleScreenMagnificationPreferenceFragment}. */ @RunWith(RobolectricTestRunner.class) @@ -92,7 +99,7 @@ import java.util.List; public class ToggleScreenMagnificationPreferenceFragmentTest { @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private static final String PLACEHOLDER_PACKAGE_NAME = "com.mock.example"; private static final String PLACEHOLDER_CLASS_NAME = @@ -122,13 +129,15 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { private FragmentController mFragController; private Context mContext; + private AccessibilityManager mAccessibilityManager; private Resources mSpyResources; private ShadowPackageManager mShadowPackageManager; @Before public void setUpTestFragment() { - mContext = ApplicationProvider.getApplicationContext(); + mContext = spy(ApplicationProvider.getApplicationContext()); + mAccessibilityManager = AccessibilityTestUtils.setupMockAccessibilityManager(mContext); // Set up the fragment that support window magnification feature mSpyResources = spy(mContext.getResources()); @@ -319,26 +328,27 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void hasMagnificationValuesInSettings_twoFingerTripleTapIsOn_isTrue() { Settings.Secure.putInt( mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, ON); assertThat(ToggleScreenMagnificationPreferenceFragment.hasMagnificationValuesInSettings( - mContext, UserShortcutType.TWOFINGERTRIPLETAP)).isTrue(); + mContext, UserShortcutType.TWOFINGER_DOUBLETAP)).isTrue(); } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void hasMagnificationValuesInSettings_twoFingerTripleTapIsOff_isFalse() { Settings.Secure.putInt( mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, OFF); assertThat(ToggleScreenMagnificationPreferenceFragment.hasMagnificationValuesInSettings( - mContext, UserShortcutType.TWOFINGERTRIPLETAP)).isFalse(); + mContext, UserShortcutType.TWOFINGER_DOUBLETAP)).isFalse(); } @Test + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void optInAllValuesToSettings_optInValue_haveMatchString() { int shortcutTypes = UserShortcutType.SOFTWARE | UserShortcutType.TRIPLETAP; @@ -351,9 +361,36 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) + public void optInAllValuesToSettings_optInValue_callA11yManager() { + int shortcutTypes = + UserShortcutType.SOFTWARE | UserShortcutType.TRIPLETAP | UserShortcutType.HARDWARE + | UserShortcutType.QUICK_SETTINGS; + Set shortcutTargets = Set.of(MAGNIFICATION_CONTROLLER_NAME); + + ToggleScreenMagnificationPreferenceFragment.optInAllMagnificationValuesToSettings(mContext, + shortcutTypes); + + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ true, UserShortcutType.SOFTWARE, + shortcutTargets, UserHandle.myUserId()); + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ true, UserShortcutType.HARDWARE, + shortcutTargets, UserHandle.myUserId()); + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ true, UserShortcutType.QUICK_SETTINGS, + shortcutTargets, UserHandle.myUserId()); + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ true, UserShortcutType.TRIPLETAP, + shortcutTargets, UserHandle.myUserId()); + verifyNoMoreInteractions(mAccessibilityManager); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void optInAllValuesToSettings_twoFingerTripleTap_haveMatchString() { - int shortcutTypes = UserShortcutType.TWOFINGERTRIPLETAP; + int shortcutTypes = UserShortcutType.TWOFINGER_DOUBLETAP; ToggleScreenMagnificationPreferenceFragment.optInAllMagnificationValuesToSettings(mContext, shortcutTypes); @@ -363,6 +400,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void optInAllValuesToSettings_existOtherValue_optInValue_haveMatchString() { putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, PLACEHOLDER_COMPONENT_NAME.flattenToString()); @@ -374,6 +412,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void optInAllValuesToSettings_software_sizeValueIsNull_putLargeSizeValue() { ShadowSettings.ShadowSecure.reset(); @@ -441,6 +480,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void optOutAllValuesToSettings_optOutValue_emptyString() { putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME); putStringIntoSettings(HARDWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME); @@ -457,19 +497,46 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) + public void optOutAllValuesToSettings_optOutValue_callA11yManager() { + Set shortcutTargets = Set.of(MAGNIFICATION_CONTROLLER_NAME); + putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME); + putStringIntoSettings(HARDWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME); + setMagnificationTripleTapEnabled(/* enabled= */ true); + int shortcutTypes = + UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP; + + ToggleScreenMagnificationPreferenceFragment.optOutAllMagnificationValuesFromSettings( + mContext, shortcutTypes); + + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ false, UserShortcutType.SOFTWARE, + shortcutTargets, UserHandle.myUserId()); + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ false, UserShortcutType.HARDWARE, + shortcutTargets, UserHandle.myUserId()); + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ false, UserShortcutType.TRIPLETAP, + shortcutTargets, UserHandle.myUserId()); + verifyNoMoreInteractions(mAccessibilityManager); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void optOutAllValuesToSettings_twoFingerTripleTap_settingsValueIsOff() { Settings.Secure.putInt(mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, ON); ToggleScreenMagnificationPreferenceFragment.optOutAllMagnificationValuesFromSettings( - mContext, UserShortcutType.TWOFINGERTRIPLETAP); + mContext, UserShortcutType.TWOFINGER_DOUBLETAP); assertThat(Settings.Secure.getInt(mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, ON)).isEqualTo(OFF); } @Test + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void optOutValueFromSettings_existOtherValue_optOutValue_haveMatchString() { putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, PLACEHOLDER_COMPONENT_NAME.flattenToString() + ":" + MAGNIFICATION_CONTROLLER_NAME); @@ -526,7 +593,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void updateShortcutPreferenceData_hasTwoFingerTripleTapInSettings_assignToVariable() { Settings.Secure.putInt( mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, ON); @@ -536,14 +603,14 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, MAGNIFICATION_CONTROLLER_NAME); - assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGERTRIPLETAP); + assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGER_DOUBLETAP); } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void updateShortcutPreferenceData_hasTwoFingerTripleTapInSharedPref_assignToVariable() { final PreferredShortcut tripleTapShortcut = new PreferredShortcut( - MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.TWOFINGERTRIPLETAP); + MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.TWOFINGER_DOUBLETAP); putUserShortcutTypeIntoSharedPreference(mContext, tripleTapShortcut); mFragController.create(R.id.main_content, /* bundle= */ null).start().resume(); @@ -551,7 +618,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, MAGNIFICATION_CONTROLLER_NAME); - assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGERTRIPLETAP); + assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGER_DOUBLETAP); } @Test @@ -590,7 +657,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void setupMagnificationEditShortcutDialog_twoFingerTripleTapOn_checkboxIsSavedValue() { ToggleScreenMagnificationPreferenceFragment fragment = mFragController.create(R.id.main_content, /* bundle= */ @@ -598,7 +665,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null); final PreferredShortcut twoFingerTripleTapShortcut = new PreferredShortcut( - MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.TWOFINGERTRIPLETAP); + MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.TWOFINGER_DOUBLETAP); fragment.mShortcutPreference = shortcutPreference; PreferredShortcuts.saveUserShortcutType(mContext, twoFingerTripleTapShortcut); @@ -607,7 +674,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { createEditShortcutDialog(fragment.getActivity())); final int checkboxValue = fragment.getShortcutTypeCheckBoxValue(); - assertThat(checkboxValue).isEqualTo(UserShortcutType.TWOFINGERTRIPLETAP); + assertThat(checkboxValue).isEqualTo(UserShortcutType.TWOFINGER_DOUBLETAP); } @Test @@ -632,10 +699,10 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void restoreValueFromSavedInstanceState_twoFingerTripleTap_assignToVariable() { final Bundle fragmentState = - createFragmentSavedInstanceState(UserShortcutType.TWOFINGERTRIPLETAP); + createFragmentSavedInstanceState(UserShortcutType.TWOFINGER_DOUBLETAP); ToggleScreenMagnificationPreferenceFragment fragment = mFragController.get(); // Had to use reflection to pass the savedInstanceState when launching the fragment ReflectionHelpers.setField(fragment, "mSavedFragmentState", fragmentState); @@ -649,8 +716,8 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, MAGNIFICATION_CONTROLLER_NAME); - assertThat(value).isEqualTo(UserShortcutType.TWOFINGERTRIPLETAP); - assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGERTRIPLETAP); + assertThat(value).isEqualTo(UserShortcutType.TWOFINGER_DOUBLETAP); + assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGER_DOUBLETAP); } @Test @@ -789,7 +856,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void getSummary_magnificationGestureEnabled_returnShortcutOnWithSummary() { Settings.Secure.putInt( mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, ON); @@ -803,7 +870,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void getSummary_magnificationGestureDisabled_returnShortcutOffWithSummary() { Settings.Secure.putInt( mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, OFF); @@ -817,6 +884,33 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { mContext.getText(R.string.magnification_feature_summary))); } + @Test + @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) + public void getShortcutTypeSummary_shortcutSummaryIsCorrectlySet() { + final PreferredShortcut userPreferredShortcut = new PreferredShortcut( + MAGNIFICATION_CONTROLLER_NAME, + UserShortcutType.HARDWARE | UserShortcutType.QUICK_SETTINGS); + putUserShortcutTypeIntoSharedPreference(mContext, userPreferredShortcut); + final ShortcutPreference shortcutPreference = + new ShortcutPreference(mContext, /* attrs= */ null); + shortcutPreference.setChecked(true); + shortcutPreference.setSettingsEditable(true); + ToggleScreenMagnificationPreferenceFragment fragment = + mFragController.create(R.id.main_content, /* bundle= */ + null).start().resume().get(); + fragment.mShortcutPreference = shortcutPreference; + String expected = CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), + /* iter= */ null, + mContext.getString( + R.string.accessibility_feature_shortcut_setting_summary_quick_settings) + + ", " + + mContext.getString(R.string.accessibility_shortcut_hardware_keyword)); + + String summary = fragment.getShortcutTypeSummary(mContext).toString(); + + assertThat(summary).isEqualTo(expected); + } + private void putStringIntoSettings(String key, String componentName) { Settings.Secure.putString(mContext.getContentResolver(), key, componentName); } diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java index 56486d2a871..526b4318286 100644 --- a/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java @@ -86,7 +86,10 @@ import java.util.Set; /** * Tests for {@link EditShortcutsPreferenceFragment} */ -@Config(shadows = SettingsShadowResources.class) +@Config(shadows = { + SettingsShadowResources.class, + com.android.settings.testutils.shadow.ShadowAccessibilityManager.class +}) @RunWith(RobolectricTestRunner.class) public class EditShortcutsPreferenceFragmentTest { private static final int METRICS_CATEGORY = 123; @@ -99,7 +102,8 @@ public class EditShortcutsPreferenceFragmentTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - private final Context mContext = ApplicationProvider.getApplicationContext(); + private Context mContext = ApplicationProvider.getApplicationContext(); + private FragmentActivity mActivity; private FragmentScenario mFragmentScenario; @@ -291,7 +295,7 @@ public class EditShortcutsPreferenceFragmentTest { mFragmentScenario.onFragment(fragment -> { TwoStatePreference preference = fragment.findPreference( mContext.getString( - R.string.accessibility_shortcut_two_fingers_double_tap_pref)); + R.string.accessibility_shortcut_two_finger_double_tap_pref)); assertThat(preference.isChecked()).isTrue(); }); } @@ -476,7 +480,26 @@ public class EditShortcutsPreferenceFragmentTest { )); } + @Test + public void onQuickSettingsShortcutSettingChanged_preferredShortcutsUpdated() { + mFragmentScenario = createFragScenario(/* isInSuw= */ false); + mFragmentScenario.moveToState(Lifecycle.State.CREATED); + int currentPreferredShortcut = + PreferredShortcuts.retrieveUserShortcutType(mContext, TARGET); + assertThat(currentPreferredShortcut + & ShortcutConstants.UserShortcutType.QUICK_SETTINGS).isEqualTo(0); + ShortcutUtils.optInValueToSettings( + mContext, ShortcutConstants.UserShortcutType.QUICK_SETTINGS, TARGET); + + // Calls onFragment so that the change to Setting is notified to its observer + mFragmentScenario.onFragment(fragment -> + assertThat( + PreferredShortcuts.retrieveUserShortcutType( + mContext, TARGET) + ).isEqualTo(ShortcutConstants.UserShortcutType.QUICK_SETTINGS) + ); + } private void assertLaunchSubSettingWithCurrentTargetComponents( String componentName, boolean isInSuw) { diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/GestureShortcutOptionControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/GestureShortcutOptionControllerTest.java index 010386cf4c8..155cb2239b1 100644 --- a/tests/robotests/src/com/android/settings/accessibility/shortcuts/GestureShortcutOptionControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/GestureShortcutOptionControllerTest.java @@ -16,9 +16,10 @@ package com.android.settings.accessibility.shortcuts; +import static com.android.settings.testutils.AccessibilityTestUtils.setupMockAccessibilityManager; + import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -148,8 +149,7 @@ public class GestureShortcutOptionControllerTest { } private void enableTouchExploration(boolean enable) { - AccessibilityManager am = mock(AccessibilityManager.class); - when(mContext.getSystemService(AccessibilityManager.class)).thenReturn(am); + AccessibilityManager am = setupMockAccessibilityManager(mContext); when(am.isTouchExplorationEnabled()).thenReturn(enable); } } diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/QuickSettingsShortcutOptionControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/QuickSettingsShortcutOptionControllerTest.java new file mode 100644 index 00000000000..6086b171d8c --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/QuickSettingsShortcutOptionControllerTest.java @@ -0,0 +1,180 @@ +/* + * 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.shortcuts; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.ComponentName; +import android.content.Context; +import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.Flags; + +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; + +import com.android.internal.accessibility.common.ShortcutConstants; +import com.android.internal.accessibility.util.ShortcutUtils; +import com.android.settings.R; +import com.android.settings.testutils.AccessibilityTestUtils; +import com.android.settings.testutils.shadow.SettingsShadowResources; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Tests for {@link QuickSettingsShortcutOptionController} + */ +@RunWith(RobolectricTestRunner.class) +public class QuickSettingsShortcutOptionControllerTest { + private static final String PREF_KEY = "prefKey"; + private static final ComponentName TARGET = new ComponentName("FakePackage", "FakeClass"); + private static final String TARGET_FLATTEN = TARGET.flattenToString(); + private static final ComponentName TARGET_TILE = + new ComponentName("FakePackage", "FakeTileClass"); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private final Context mContext = spy(ApplicationProvider.getApplicationContext()); + private QuickSettingsShortcutOptionController mController; + private ShortcutOptionPreference mShortcutOptionPreference; + private AccessibilityManager mAccessibilityManager; + + private PreferenceScreen mPreferenceScreen; + + @Before + public void setUp() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_quickSettingsSupported, true); + mAccessibilityManager = AccessibilityTestUtils.setupMockAccessibilityManager(mContext); + mController = new QuickSettingsShortcutOptionController( + mContext, PREF_KEY); + mController.setShortcutTargets(Set.of(TARGET_FLATTEN)); + mShortcutOptionPreference = new ShortcutOptionPreference(mContext); + mShortcutOptionPreference.setKey(PREF_KEY); + mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext); + mPreferenceScreen.addPreference(mShortcutOptionPreference); + } + + @Test + public void displayPreference_verifyScreenTextSet() { + mController.displayPreference(mPreferenceScreen); + + assertThat(mShortcutOptionPreference.getTitle().toString()).isEqualTo( + mContext.getString( + R.string.accessibility_shortcut_edit_dialog_title_quick_settings)); + assertThat(mShortcutOptionPreference.getSummary().toString()).isEqualTo( + mContext.getString( + R.string.accessibility_shortcut_edit_dialog_summary_quick_settings)); + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void isShortcutAvailable_a11yQsShortcutFlagDisabled_returnsFalse() { + assertThat(mController.isShortcutAvailable()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void isShortcutAvailable_qsNotSupported_returnsFalse() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_quickSettingsSupported, false); + + assertThat(mController.isShortcutAvailable()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void isShortcutAvailable_qsTileProvided_returnsTrue() { + when(mAccessibilityManager.getA11yFeatureToTileMap(UserHandle.myUserId())) + .thenReturn(Map.of(TARGET, TARGET_TILE)); + + assertThat(mController.isShortcutAvailable()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void isShortcutAvailable_qsTileNotProvided_returnsFalse() { + when(mAccessibilityManager.getA11yFeatureToTileMap(UserHandle.myUserId())) + .thenReturn(Collections.emptyMap()); + + assertThat(mController.isShortcutAvailable()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void isShortcutAvailable_qsTileProvided_invalidUseCase_returnFalse() { + AccessibilityServiceInfo mockStandardA11yService = + AccessibilityTestUtils.createAccessibilityServiceInfo( + mContext, TARGET, /* isAlwaysOnService= */ false); + when(mAccessibilityManager.getA11yFeatureToTileMap(UserHandle.myUserId())) + .thenReturn(Map.of(TARGET, TARGET_TILE)); + // setup target as a standard a11y service + when(mAccessibilityManager.getInstalledAccessibilityServiceList()) + .thenReturn(List.of(mockStandardA11yService)); + + assertThat(mController.isShortcutAvailable()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void isShortcutAvailable_qsTileProvided_validUseCase_returnTrue() { + AccessibilityServiceInfo mockAlwaysOnA11yService = + AccessibilityTestUtils.createAccessibilityServiceInfo( + mContext, TARGET, /* isAlwaysOnService= */ true); + when(mAccessibilityManager.getA11yFeatureToTileMap(UserHandle.myUserId())) + .thenReturn(Map.of(TARGET, TARGET_TILE)); + // setup target as a always-on a11y service + when(mAccessibilityManager.getInstalledAccessibilityServiceList()) + .thenReturn(List.of(mockAlwaysOnA11yService)); + + + assertThat(mController.isShortcutAvailable()).isTrue(); + } + + @Test + public void isChecked_targetUseQsShortcut_returnTrue() { + ShortcutUtils.optInValueToSettings( + mContext, ShortcutConstants.UserShortcutType.QUICK_SETTINGS, TARGET_FLATTEN); + + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void isChecked_targetNotUseQsShortcut_returnFalse() { + ShortcutUtils.optOutValueFromSettings( + mContext, ShortcutConstants.UserShortcutType.QUICK_SETTINGS, TARGET_FLATTEN); + + assertThat(mController.isChecked()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/SoftwareShortcutOptionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/SoftwareShortcutOptionPreferenceControllerTest.java index 1f7e0196af8..1eeb9446c21 100644 --- a/tests/robotests/src/com/android/settings/accessibility/shortcuts/SoftwareShortcutOptionPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/SoftwareShortcutOptionPreferenceControllerTest.java @@ -22,6 +22,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityServiceInfo; @@ -30,14 +32,15 @@ import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.os.Build; +import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.text.SpannableStringBuilder; import android.view.View; import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.Flags; import androidx.fragment.app.FragmentActivity; @@ -48,18 +51,18 @@ import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.accessibility.AccessibilityButtonFragment; import com.android.settings.accessibility.FloatingMenuSizePreferenceController; +import com.android.settings.testutils.AccessibilityTestUtils; import com.android.settings.utils.AnnotationSpan; import com.android.settingslib.accessibility.AccessibilityUtils; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -import org.xmlpull.v1.XmlPullParserException; -import java.io.IOException; import java.util.List; import java.util.Set; @@ -77,18 +80,23 @@ public class SoftwareShortcutOptionPreferenceControllerTest { new ComponentName("FakePackage", "StandardA11yService"); private static final String SOFTWARE_SHORTCUT_SETTING_NAME = Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; - + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private Context mContext; + private AccessibilityManager mAccessibilityManager; private TestSoftwareShortcutOptionPreferenceController mController; @Before public void setUp() { mContext = spy(Robolectric.buildActivity(FragmentActivity.class).get()); + mAccessibilityManager = AccessibilityTestUtils.setupMockAccessibilityManager(mContext); - AccessibilityServiceInfo mAlwaysOnServiceInfo = createAccessibilityServiceInfo( - TARGET_ALWAYS_ON_A11Y_SERVICE, /* isAlwaysOnService= */ true); - AccessibilityServiceInfo mStandardServiceInfo = createAccessibilityServiceInfo( - TARGET_STANDARD_A11Y_SERVICE, /* isAlwaysOnService= */ false); + AccessibilityServiceInfo mAlwaysOnServiceInfo = + AccessibilityTestUtils.createAccessibilityServiceInfo( + mContext, TARGET_ALWAYS_ON_A11Y_SERVICE, /* isAlwaysOnService= */ true); + AccessibilityServiceInfo mStandardServiceInfo = + AccessibilityTestUtils.createAccessibilityServiceInfo( + mContext, TARGET_STANDARD_A11Y_SERVICE, /* isAlwaysOnService= */ false); AccessibilityManager am = mock(AccessibilityManager.class); when(mContext.getSystemService(Context.ACCESSIBILITY_SERVICE)).thenReturn(am); when(am.getInstalledAccessibilityServiceList()).thenReturn( @@ -170,6 +178,7 @@ public class SoftwareShortcutOptionPreferenceControllerTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_enableShortcut_shortcutTurnedOn() { String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(); mController.setShortcutTargets(Set.of(target)); @@ -185,6 +194,27 @@ public class SoftwareShortcutOptionPreferenceControllerTest { } @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void enableShortcutForTargets_enableShortcut_callA11yManager() { + String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(); + mController.setShortcutTargets(Set.of(target)); + assertThat(ShortcutUtils.isComponentIdExistingInSettings( + mContext, ShortcutConstants.UserShortcutType.SOFTWARE, target + )).isFalse(); + + mController.enableShortcutForTargets(true); + + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ true, + ShortcutConstants.UserShortcutType.SOFTWARE, + Set.of(target), + UserHandle.myUserId() + ); + verifyNoMoreInteractions(mAccessibilityManager); + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_disableShortcut_shortcutTurnedOff() { String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(); ShortcutUtils.optInValueToSettings( @@ -202,6 +232,29 @@ public class SoftwareShortcutOptionPreferenceControllerTest { } @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void enableShortcutForTargets_disableShortcut_callA11yManager() { + String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(); + ShortcutUtils.optInValueToSettings( + mContext, ShortcutConstants.UserShortcutType.SOFTWARE, target); + assertThat(ShortcutUtils.isComponentIdExistingInSettings( + mContext, ShortcutConstants.UserShortcutType.SOFTWARE, target + )).isTrue(); + mController.setShortcutTargets(Set.of(target)); + + mController.enableShortcutForTargets(false); + + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ false, + ShortcutConstants.UserShortcutType.SOFTWARE, + Set.of(target), + UserHandle.myUserId() + ); + verifyNoMoreInteractions(mAccessibilityManager); + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_enableShortcutWithMagnification_menuSizeIncreased() { mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION)); @@ -216,6 +269,7 @@ public class SoftwareShortcutOptionPreferenceControllerTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_enableShortcutWithMagnification_userConfigureSmallMenuSize_menuSizeNotChanged() { Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, @@ -233,6 +287,7 @@ public class SoftwareShortcutOptionPreferenceControllerTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_enableAlwaysOnServiceShortcut_turnsOnAlwaysOnService() { mController.setShortcutTargets( Set.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString())); @@ -244,6 +299,7 @@ public class SoftwareShortcutOptionPreferenceControllerTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_disableAlwaysOnServiceShortcut_turnsOffAlwaysOnService() { mController.setShortcutTargets( Set.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString())); @@ -255,6 +311,7 @@ public class SoftwareShortcutOptionPreferenceControllerTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_enableStandardServiceShortcut_wontTurnOnService() { mController.setShortcutTargets( Set.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString())); @@ -266,6 +323,7 @@ public class SoftwareShortcutOptionPreferenceControllerTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_disableStandardServiceShortcutWithServiceOn_wontTurnOffService() { mController.setShortcutTargets( Set.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString())); @@ -288,32 +346,6 @@ public class SoftwareShortcutOptionPreferenceControllerTest { assertThat(intent.getExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo(page); } - private AccessibilityServiceInfo createAccessibilityServiceInfo( - ComponentName componentName, boolean isAlwaysOnService) { - final ApplicationInfo applicationInfo = new ApplicationInfo(); - applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; - final ServiceInfo serviceInfo = new ServiceInfo(); - applicationInfo.packageName = componentName.getPackageName(); - serviceInfo.packageName = componentName.getPackageName(); - serviceInfo.name = componentName.getClassName(); - serviceInfo.applicationInfo = applicationInfo; - - final ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.serviceInfo = serviceInfo; - try { - final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo, - mContext); - info.setComponentName(componentName); - if (isAlwaysOnService) { - info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; - } - return info; - } catch (XmlPullParserException | IOException e) { - // Do nothing - } - return null; - } - private static class TestSoftwareShortcutOptionPreferenceController extends SoftwareShortcutOptionPreferenceController { diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/TripleTapShortcutOptionControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/TripleTapShortcutOptionControllerTest.java index 800640a84f4..b5daac5f5fb 100644 --- a/tests/robotests/src/com/android/settings/accessibility/shortcuts/TripleTapShortcutOptionControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/TripleTapShortcutOptionControllerTest.java @@ -21,19 +21,32 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + import android.content.ComponentName; import android.content.Context; import android.icu.text.MessageFormat; +import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.Flags; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; +import com.android.internal.accessibility.common.ShortcutConstants; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityUtil; +import com.android.settings.testutils.AccessibilityTestUtils; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -50,13 +63,17 @@ public class TripleTapShortcutOptionControllerTest { "com.android.server.accessibility.MagnificationController"; private static final String TARGET_FAKE = new ComponentName("FakePackage", "FakeClass").flattenToString(); - private final Context mContext = ApplicationProvider.getApplicationContext(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private final Context mContext = spy(ApplicationProvider.getApplicationContext()); private TripleTapShortcutOptionController mController; private ShortcutOptionPreference mShortcutOptionPreference; + private AccessibilityManager mAccessibilityManager; private PreferenceScreen mPreferenceScreen; @Before public void setUp() { + mAccessibilityManager = AccessibilityTestUtils.setupMockAccessibilityManager(mContext); mController = new TripleTapShortcutOptionController(mContext, PREF_KEY); mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION)); mShortcutOptionPreference = new ShortcutOptionPreference(mContext); @@ -147,19 +164,26 @@ public class TripleTapShortcutOptionControllerTest { @Test public void isChecked_tripleTapConfigured_returnTrue() { - mController.enableShortcutForTargets(true); + Settings.Secure.putInt( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, + AccessibilityUtil.State.ON); assertThat(mController.isChecked()).isTrue(); } @Test public void isChecked_tripleTapNotConfigured_returnFalse() { - mController.enableShortcutForTargets(false); + Settings.Secure.putInt( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, + AccessibilityUtil.State.OFF); assertThat(mController.isChecked()).isFalse(); } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_enableShortcut_settingUpdated() { mController.enableShortcutForTargets(true); @@ -172,6 +196,21 @@ public class TripleTapShortcutOptionControllerTest { } @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void enableShortcutForTargets_enableShortcut_callA11yManager() { + mController.enableShortcutForTargets(true); + + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ true, + ShortcutConstants.UserShortcutType.TRIPLETAP, + Set.of(TARGET_MAGNIFICATION), + UserHandle.myUserId() + ); + verifyNoMoreInteractions(mAccessibilityManager); + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_disableShortcut_settingUpdated() { mController.enableShortcutForTargets(false); @@ -182,4 +221,18 @@ public class TripleTapShortcutOptionControllerTest { AccessibilityUtil.State.OFF) ).isEqualTo(AccessibilityUtil.State.OFF); } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void enableShortcutForTargets_disableShortcut_callA11yManager() { + mController.enableShortcutForTargets(false); + + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ false, + ShortcutConstants.UserShortcutType.TRIPLETAP, + Set.of(TARGET_MAGNIFICATION), + UserHandle.myUserId() + ); + verifyNoMoreInteractions(mAccessibilityManager); + } } diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/TwoFingersDoubleTapShortcutOptionControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/TwoFingerDoubleTapShortcutOptionControllerTest.java similarity index 62% rename from tests/robotests/src/com/android/settings/accessibility/shortcuts/TwoFingersDoubleTapShortcutOptionControllerTest.java rename to tests/robotests/src/com/android/settings/accessibility/shortcuts/TwoFingerDoubleTapShortcutOptionControllerTest.java index d27560b35c5..716dcdbf274 100644 --- a/tests/robotests/src/com/android/settings/accessibility/shortcuts/TwoFingersDoubleTapShortcutOptionControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/TwoFingerDoubleTapShortcutOptionControllerTest.java @@ -18,22 +18,29 @@ package com.android.settings.accessibility.shortcuts; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + import android.content.ComponentName; import android.content.Context; import android.icu.text.MessageFormat; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; +import com.android.internal.accessibility.common.ShortcutConstants; import com.android.server.accessibility.Flags; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityUtil; +import com.android.settings.testutils.AccessibilityTestUtils; import org.junit.Before; import org.junit.Rule; @@ -44,26 +51,28 @@ import org.robolectric.RobolectricTestRunner; import java.util.Set; /** - * Tests for {@link TwoFingersDoubleTapShortcutOptionController} + * Tests for {@link TwoFingerDoubleTapShortcutOptionController} */ @RunWith(RobolectricTestRunner.class) -public class TwoFingersDoubleTapShortcutOptionControllerTest { +public class TwoFingerDoubleTapShortcutOptionControllerTest { private static final String PREF_KEY = "prefKey"; private static final String TARGET_MAGNIFICATION = "com.android.server.accessibility.MagnificationController"; private static final String TARGET_FAKE = new ComponentName("FakePackage", "FakeClass").flattenToString(); @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - private final Context mContext = ApplicationProvider.getApplicationContext(); - private TwoFingersDoubleTapShortcutOptionController mController; + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private final Context mContext = spy(ApplicationProvider.getApplicationContext()); + private AccessibilityManager mAccessibilityManager; + private TwoFingerDoubleTapShortcutOptionController mController; private ShortcutOptionPreference mShortcutOptionPreference; private PreferenceScreen mPreferenceScreen; @Before public void setUp() { - mController = new TwoFingersDoubleTapShortcutOptionController(mContext, PREF_KEY); + mAccessibilityManager = AccessibilityTestUtils.setupMockAccessibilityManager(mContext); + mController = new TwoFingerDoubleTapShortcutOptionController(mContext, PREF_KEY); mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION)); mShortcutOptionPreference = new ShortcutOptionPreference(mContext); mShortcutOptionPreference.setKey(PREF_KEY); @@ -84,30 +93,30 @@ public class TwoFingersDoubleTapShortcutOptionControllerTest { 2)); } - @RequiresFlagsDisabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) @Test + @DisableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void isShortcutAvailable_featureFlagTurnedOff_returnFalse() { assertThat(mController.isShortcutAvailable()).isFalse(); } - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) @Test + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void isShortcutAvailable_multipleTargets_returnFalse() { mController.setShortcutTargets(Set.of(TARGET_FAKE, TARGET_MAGNIFICATION)); assertThat(mController.isShortcutAvailable()).isFalse(); } - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) @Test + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void isShortcutAvailable_magnificationTargetOnly_returnTrue() { mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION)); assertThat(mController.isShortcutAvailable()).isTrue(); } - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) @Test + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) public void isShortcutAvailable_nonMagnificationTarget_returnFalse() { mController.setShortcutTargets(Set.of(TARGET_FAKE)); @@ -116,19 +125,26 @@ public class TwoFingersDoubleTapShortcutOptionControllerTest { @Test public void isChecked_twoFingersDoubleTapConfigured_returnTrue() { - mController.enableShortcutForTargets(true); + Settings.Secure.putInt( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, + AccessibilityUtil.State.ON); assertThat(mController.isChecked()).isTrue(); } @Test public void isChecked_twoFingersDoubleTapNotConfigured_returnFalse() { - mController.enableShortcutForTargets(false); + Settings.Secure.putInt( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, + AccessibilityUtil.State.OFF); assertThat(mController.isChecked()).isFalse(); } @Test + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_enableShortcut_settingUpdated() { mController.enableShortcutForTargets(true); @@ -141,6 +157,21 @@ public class TwoFingersDoubleTapShortcutOptionControllerTest { } @Test + @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) + public void enableShortcutForTargets_enableShortcut_callA11yManager() { + mController.enableShortcutForTargets(true); + + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ true, + ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP, + Set.of(TARGET_MAGNIFICATION), + UserHandle.myUserId() + ); + verifyNoMoreInteractions(mAccessibilityManager); + } + + @Test + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_disableShortcut_settingUpdated() { mController.enableShortcutForTargets(false); @@ -151,4 +182,18 @@ public class TwoFingersDoubleTapShortcutOptionControllerTest { AccessibilityUtil.State.OFF) ).isEqualTo(AccessibilityUtil.State.OFF); } + + @Test + @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) + public void enableShortcutForTargets_disableShortcut_callA11yManager() { + mController.enableShortcutForTargets(false); + + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ false, + ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP, + Set.of(TARGET_MAGNIFICATION), + UserHandle.myUserId() + ); + verifyNoMoreInteractions(mAccessibilityManager); + } } diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/VolumeKeysShortcutOptionControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/VolumeKeysShortcutOptionControllerTest.java index 48a90a7e6a6..511503aceba 100644 --- a/tests/robotests/src/com/android/settings/accessibility/shortcuts/VolumeKeysShortcutOptionControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/VolumeKeysShortcutOptionControllerTest.java @@ -18,8 +18,18 @@ package com.android.settings.accessibility.shortcuts; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + import android.content.ComponentName; import android.content.Context; +import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.Flags; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; @@ -28,8 +38,10 @@ import androidx.test.core.app.ApplicationProvider; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.util.ShortcutUtils; import com.android.settings.R; +import com.android.settings.testutils.AccessibilityTestUtils; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -45,7 +57,11 @@ public class VolumeKeysShortcutOptionControllerTest { private static final String PREF_KEY = "prefKey"; private static final String TARGET = new ComponentName("FakePackage", "FakeClass").flattenToString(); - private final Context mContext = ApplicationProvider.getApplicationContext(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private final Context mContext = spy(ApplicationProvider.getApplicationContext()); + private AccessibilityManager mAccessibilityManager; private VolumeKeysShortcutOptionController mController; private ShortcutOptionPreference mShortcutOptionPreference; @@ -53,6 +69,7 @@ public class VolumeKeysShortcutOptionControllerTest { @Before public void setUp() { + mAccessibilityManager = AccessibilityTestUtils.setupMockAccessibilityManager(mContext); mController = new VolumeKeysShortcutOptionController( mContext, PREF_KEY); mController.setShortcutTargets(Set.of(TARGET)); @@ -94,6 +111,7 @@ public class VolumeKeysShortcutOptionControllerTest { } @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_enableVolumeKeysShortcut_shortcutSet() { mController.enableShortcutForTargets(true); @@ -103,6 +121,21 @@ public class VolumeKeysShortcutOptionControllerTest { } @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void enableShortcutForTargets_enableVolumeKeysShortcut_callA11yManager() { + mController.enableShortcutForTargets(true); + + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ true, + ShortcutConstants.UserShortcutType.HARDWARE, + Set.of(TARGET), + UserHandle.myUserId() + ); + verifyNoMoreInteractions(mAccessibilityManager); + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) public void enableShortcutForTargets_disableVolumeKeysShortcut_shortcutNotSet() { mController.enableShortcutForTargets(false); @@ -110,4 +143,18 @@ public class VolumeKeysShortcutOptionControllerTest { ShortcutUtils.isComponentIdExistingInSettings( mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET)).isFalse(); } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void enableShortcutForTargets_disableVolumeKeysShortcut_callA11yManager() { + mController.enableShortcutForTargets(false); + + verify(mAccessibilityManager).enableShortcutsForTargets( + /* enable= */ false, + ShortcutConstants.UserShortcutType.HARDWARE, + Set.of(TARGET), + UserHandle.myUserId() + ); + verifyNoMoreInteractions(mAccessibilityManager); + } } diff --git a/tests/robotests/src/com/android/settings/testutils/AccessibilityTestUtils.java b/tests/robotests/src/com/android/settings/testutils/AccessibilityTestUtils.java index 8cda2d94686..5d895d908d6 100644 --- a/tests/robotests/src/com/android/settings/testutils/AccessibilityTestUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/AccessibilityTestUtils.java @@ -20,11 +20,25 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATIN import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.Build; import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; import com.android.settings.testutils.shadow.SettingsShadowResources; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + /** * Utility class for common methods used in the accessibility feature related tests */ @@ -47,4 +61,39 @@ public class AccessibilityTestUtils { NAV_BAR_MODE_3BUTTON); } } + + /** + * Returns a mock {@link AccessibilityManager} + */ + public static AccessibilityManager setupMockAccessibilityManager(Context mockContext) { + AccessibilityManager am = mock(AccessibilityManager.class); + when(mockContext.getSystemService(AccessibilityManager.class)).thenReturn(am); + return am; + } + + public static AccessibilityServiceInfo createAccessibilityServiceInfo( + Context context, ComponentName componentName, boolean isAlwaysOnService) { + final ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; + final ServiceInfo serviceInfo = new ServiceInfo(); + applicationInfo.packageName = componentName.getPackageName(); + serviceInfo.packageName = componentName.getPackageName(); + serviceInfo.name = componentName.getClassName(); + serviceInfo.applicationInfo = applicationInfo; + + final ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.serviceInfo = serviceInfo; + try { + final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo, + context); + info.setComponentName(componentName); + if (isAlwaysOnService) { + info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; + } + return info; + } catch (XmlPullParserException | IOException e) { + // Do nothing + } + return null; + } } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessibilityManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessibilityManager.java new file mode 100644 index 00000000000..d6e17d46d40 --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessibilityManager.java @@ -0,0 +1,42 @@ +/* + * 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.testutils.shadow; + +import android.annotation.UserIdInt; +import android.content.ComponentName; +import android.view.accessibility.AccessibilityManager; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +import java.util.Collections; +import java.util.Map; + +/** + * Shadow of {@link AccessibilityManager} with the hidden methods + */ +@Implements(AccessibilityManager.class) +public class ShadowAccessibilityManager extends org.robolectric.shadows.ShadowAccessibilityManager { + /** + * Implements a hidden method {@link AccessibilityManager.getA11yFeatureToTileMap} and returns + * an empty map. + */ + @Implementation + public Map getA11yFeatureToTileMap(@UserIdInt int userId) { + return Collections.emptyMap(); + } +} diff --git a/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java b/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java index e3c07ef1e95..4ef63d0df81 100644 --- a/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java +++ b/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java @@ -25,16 +25,22 @@ import static com.google.common.truth.Truth.assertThat; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; +import android.view.accessibility.Flags; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.accessibility.common.ShortcutConstants; +import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; import com.android.internal.accessibility.util.ShortcutUtils; import org.junit.AfterClass; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -54,7 +60,8 @@ public class PreferredShortcutsTest { CLASS_NAME_2); private static final ContentResolver sContentResolver = ApplicationProvider.getApplicationContext().getContentResolver(); - + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private final Context mContext = ApplicationProvider.getApplicationContext(); @Before @@ -166,11 +173,48 @@ public class PreferredShortcutsTest { .isEqualTo(target2ShortcutTypes); } + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void updatePreferredShortcutFromSettings_colorInversionWithQsAndSoftwareShortcut_preferredShortcutsMatches() { + String target = COLOR_INVERSION_COMPONENT_NAME.flattenToString(); + Settings.Secure.putString(sContentResolver, + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, target); + Settings.Secure.putString(sContentResolver, + Settings.Secure.ACCESSIBILITY_QS_TARGETS, target); + + PreferredShortcuts.updatePreferredShortcutsFromSettings(mContext, Set.of(target)); + + int savedPreferredShortcut = PreferredShortcuts.retrieveUserShortcutType( + mContext, target); + assertThat(savedPreferredShortcut).isEqualTo( + UserShortcutType.SOFTWARE | UserShortcutType.QUICK_SETTINGS); + + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void updatePreferredShortcutFromSettings_colorInversionWithQsAndHardwareShortcut_qsShortcutNotSaved() { + String target = COLOR_INVERSION_COMPONENT_NAME.flattenToString(); + Settings.Secure.putString(sContentResolver, + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, target); + Settings.Secure.putString(sContentResolver, + Settings.Secure.ACCESSIBILITY_QS_TARGETS, target); + assertThat(!android.view.accessibility.Flags.a11yQsShortcut()).isTrue(); + + PreferredShortcuts.updatePreferredShortcutsFromSettings(mContext, Set.of(target)); + + int savedPreferredShortcut = PreferredShortcuts.retrieveUserShortcutType( + mContext, target); + assertThat(savedPreferredShortcut).isEqualTo(UserShortcutType.HARDWARE); + } + private static void clearShortcuts() { Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, ""); Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, ""); + Settings.Secure.putString(sContentResolver, + Settings.Secure.ACCESSIBILITY_QS_TARGETS, ""); Settings.Secure.putInt( sContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, @@ -179,5 +223,7 @@ public class PreferredShortcutsTest { sContentResolver, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, AccessibilityUtil.State.OFF); + + PreferredShortcuts.clearPreferredShortcuts(ApplicationProvider.getApplicationContext()); } }