Refactoring A11y shortcut functions in Settings to use GESTURE

Properly integrating GESTURE into Settings, so that text pertaining to the gesture shortcut are displayed when appropriate.
Heavy refactoring has been done to allow for easier cleanup and expansion

Demo video: https://x20web.corp.google.com/users/jo/jonesriley/splitShortcut/a11ySettingsGestureCompat.mp4

NO_IFTTT=changes do not alter the order of the shortcuts.

Bug: 365570709
Test: atest com.android.settings.accessibility
Flag: android.provider.a11y_standalone_gesture_enabled
Change-Id: If90719763a48e3b8bc35988a1de9a352a766953b
This commit is contained in:
Riley Jones
2024-09-10 23:21:13 +00:00
parent b5aa5265ee
commit 3d4b0c5440
15 changed files with 515 additions and 414 deletions

View File

@@ -22,10 +22,12 @@ import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.DEFAULT;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.ComponentName;
@@ -33,6 +35,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Rect;
import android.icu.text.CaseMap;
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
@@ -47,11 +50,17 @@ import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
import com.android.internal.accessibility.util.ShortcutUtils;
import com.android.settings.R;
import com.android.settings.utils.LocaleUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.StringJoiner;
@@ -139,8 +148,8 @@ public final class AccessibilityUtil {
/** Determines if a gesture navigation bar is being used. */
public static boolean isGestureNavigateEnabled(Context context) {
return context.getResources().getInteger(
com.android.internal.R.integer.config_navBarInteractionMode)
return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.NAVIGATION_MODE, -1)
== NAV_BAR_MODE_GESTURAL;
}
@@ -335,22 +344,23 @@ public final class AccessibilityUtil {
*/
static boolean hasValuesInSettings(Context context, int shortcutTypes,
@NonNull ComponentName componentName) {
boolean exist = false;
if ((shortcutTypes & SOFTWARE) == SOFTWARE) {
exist = hasValueInSettings(context, SOFTWARE, componentName);
}
if (((shortcutTypes & HARDWARE) == HARDWARE)) {
exist |= hasValueInSettings(context, HARDWARE, componentName);
}
if (android.view.accessibility.Flags.a11yQsShortcut()) {
if ((shortcutTypes & QUICK_SETTINGS)
== QUICK_SETTINGS) {
exist |= hasValueInSettings(context, QUICK_SETTINGS,
componentName);
for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
if (!android.view.accessibility.Flags.a11yQsShortcut()) {
if ((shortcutType & QUICK_SETTINGS) == QUICK_SETTINGS) {
continue;
}
}
if (!android.provider.Flags.a11yStandaloneGestureEnabled()) {
if ((shortcutType & GESTURE) == GESTURE) {
continue;
}
}
if ((shortcutTypes & shortcutType) == shortcutType
&& hasValueInSettings(context, shortcutType, componentName)) {
return true;
}
}
return exist;
return false;
}
/**
@@ -364,29 +374,14 @@ 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);
if (TextUtils.isEmpty(targetString)) {
if (!android.view.accessibility.Flags.a11yQsShortcut()
&& (shortcutType & QUICK_SETTINGS) == QUICK_SETTINGS) {
return false;
}
sStringColonSplitter.setString(targetString);
while (sStringColonSplitter.hasNext()) {
final String name = sStringColonSplitter.next();
if ((componentName.flattenToString()).equals(name)) {
return true;
}
}
return false;
return ShortcutUtils.getShortcutTargetsFromSettings(
context, shortcutType, UserHandle.myUserId()
).contains(componentName.flattenToString());
}
/**
@@ -400,15 +395,19 @@ public final class AccessibilityUtil {
static int getUserShortcutTypesFromSettings(Context context,
@NonNull ComponentName componentName) {
int shortcutTypes = DEFAULT;
if (hasValuesInSettings(context, SOFTWARE, componentName)) {
shortcutTypes |= SOFTWARE;
}
if (hasValuesInSettings(context, HARDWARE, componentName)) {
shortcutTypes |= HARDWARE;
}
if (android.view.accessibility.Flags.a11yQsShortcut()) {
if (hasValuesInSettings(context, QUICK_SETTINGS, componentName)) {
shortcutTypes |= QUICK_SETTINGS;
for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
if (!android.view.accessibility.Flags.a11yQsShortcut()) {
if ((shortcutType & QUICK_SETTINGS) == QUICK_SETTINGS) {
continue;
}
}
if (!android.provider.Flags.a11yStandaloneGestureEnabled()) {
if ((shortcutType & GESTURE) == GESTURE) {
continue;
}
}
if (hasValueInSettings(context, shortcutType, componentName)) {
shortcutTypes |= shortcutType;
}
}
@@ -505,4 +504,66 @@ public final class AccessibilityUtil {
Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION, /*
true */ 1);
}
/**
* Assembles a localized string describing the provided shortcut types.
*/
public static CharSequence getShortcutSummaryList(Context context, int shortcutTypes) {
final List<CharSequence> list = new ArrayList<>();
// LINT.IfChange(shortcut_type_ui_order)
for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
if (!android.view.accessibility.Flags.a11yQsShortcut()
&& (shortcutType & QUICK_SETTINGS) == QUICK_SETTINGS) {
continue;
}
if (!android.provider.Flags.a11yStandaloneGestureEnabled()
&& (shortcutType & GESTURE) == GESTURE) {
continue;
}
if (!com.android.server.accessibility.Flags
.enableMagnificationMultipleFingerMultipleTapGesture()
&& (shortcutType & TWOFINGER_DOUBLETAP) == TWOFINGER_DOUBLETAP) {
continue;
}
if ((shortcutTypes & shortcutType) == shortcutType) {
list.add(switch (shortcutType) {
case QUICK_SETTINGS -> context.getText(
R.string.accessibility_feature_shortcut_setting_summary_quick_settings);
case SOFTWARE -> getSoftwareShortcutSummary(context);
case GESTURE -> context.getText(
R.string.accessibility_shortcut_edit_summary_software_gesture);
case HARDWARE -> context.getText(
R.string.accessibility_shortcut_hardware_keyword);
case TWOFINGER_DOUBLETAP -> context.getString(
R.string.accessibility_shortcut_two_finger_double_tap_keyword, 2);
case TRIPLETAP -> context.getText(
R.string.accessibility_shortcut_triple_tap_keyword);
default -> "";
});
}
}
list.sort(CharSequence::compare);
return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
null, LocaleUtils.getConcatenatedString(list));
// LINT.ThenChange(/res/xml/accessibility_edit_shortcuts.xml:shortcut_type_ui_order)
}
@VisibleForTesting
static CharSequence getSoftwareShortcutSummary(Context context) {
if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
return context.getText(R.string.accessibility_shortcut_edit_summary_software);
}
int resId;
if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
resId = R.string.accessibility_shortcut_edit_summary_software;
} else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
resId = R.string.accessibility_shortcut_edit_summary_software_gesture;
} else {
resId = R.string.accessibility_shortcut_edit_summary_software;
}
return context.getText(resId);
}
}