Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8fbb84d4 authored by Wenyu Zhang's avatar Wenyu Zhang
Browse files

Add a11y voice access keyboard shortcut

Proposed new shortcut to toggle voice access: Meta + Alt + V.

Change-Id: I116ac81f76198122b7ab4dce370197781386d06b
Bug: b/383734125
Test: atest KeyGestureEventTests, verified locally
Flag: com.android.hardware.input.enable_voice_access_key_gestures
parent d037da48
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -129,6 +129,7 @@ public final class KeyGestureEvent {
    public static final int KEY_GESTURE_TYPE_MAGNIFICATION_PAN_RIGHT = 79;
    public static final int KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP = 80;
    public static final int KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN = 81;
    public static final int KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS = 82;

    public static final int FLAG_CANCELLED = 1;

@@ -225,6 +226,7 @@ public final class KeyGestureEvent {
            KEY_GESTURE_TYPE_MAGNIFICATION_PAN_RIGHT,
            KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP,
            KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN,
            KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface KeyGestureType {
@@ -807,6 +809,8 @@ public final class KeyGestureEvent {
                return "KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP";
            case KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN:
                return "KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN";
            case KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS:
                return "KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS";
            default:
                return Integer.toHexString(value);
        }
+21 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
@@ -351,4 +352,24 @@ public final class AccessibilityUtils {
        }
        return result;
    }

    /** Returns the {@link ComponentName} of an installed accessibility service by label. */
    @Nullable
    public static ComponentName getInstalledAccessibilityServiceComponentNameByLabel(
            Context context, String label) {
        AccessibilityManager accessibilityManager =
                context.getSystemService(AccessibilityManager.class);
        List<AccessibilityServiceInfo> serviceInfos =
                accessibilityManager.getInstalledAccessibilityServiceList();

        for (AccessibilityServiceInfo service : serviceInfos) {
            final ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
            if (label.equals(serviceInfo.loadLabel(context.getPackageManager()).toString())
                    && (serviceInfo.applicationInfo.isSystemApp()
                            || serviceInfo.applicationInfo.isUpdatedSystemApp())) {
                return new ComponentName(serviceInfo.packageName, serviceInfo.name);
            }
        }
        return null;
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.input;
import static android.hardware.input.InputGestureData.createKeyTrigger;

import static com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures;
import static com.android.hardware.input.Flags.enableVoiceAccessKeyGestures;
import static com.android.hardware.input.Flags.keyboardA11yShortcutControl;
import static com.android.server.flags.Flags.newBugreportKeyboardShortcut;
import static com.android.window.flags.Flags.enableMoveToNextDisplayShortcut;
@@ -240,6 +241,13 @@ final class InputGestureManager {
                    KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                    KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK));
        }
        if (enableVoiceAccessKeyGestures()) {
            systemShortcuts.add(
                    createKeyGesture(
                            KeyEvent.KEYCODE_V,
                            KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS));
        }
        if (enableTaskResizingKeyboardShortcuts()) {
            systemShortcuts.add(createKeyGesture(
                    KeyEvent.KEYCODE_LEFT_BRACKET,
+19 −1
Original line number Diff line number Diff line
@@ -85,15 +85,16 @@ import static android.view.contentprotection.flags.Flags.createAccessibilityOver

import static com.android.hardware.input.Flags.enableNew25q2Keycodes;
import static com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures;
import static com.android.hardware.input.Flags.enableVoiceAccessKeyGestures;
import static com.android.hardware.input.Flags.inputManagerLifecycleSupport;
import static com.android.hardware.input.Flags.keyboardA11yShortcutControl;
import static com.android.hardware.input.Flags.modifierShortcutDump;
import static com.android.hardware.input.Flags.overridePowerKeyBehaviorInFocusedWindow;
import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
import static com.android.server.GestureLauncherService.DOUBLE_POWER_TAP_COUNT_THRESHOLD;
import static com.android.server.flags.Flags.modifierShortcutManagerMultiuser;
import static com.android.server.flags.Flags.newBugreportKeyboardShortcut;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -502,6 +503,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {

    private TalkbackShortcutController mTalkbackShortcutController;

    private VoiceAccessShortcutController mVoiceAccessShortcutController;

    private WindowWakeUpPolicy mWindowWakeUpPolicy;

    /**
@@ -2265,6 +2268,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            return new TalkbackShortcutController(mContext);
        }

        VoiceAccessShortcutController getVoiceAccessShortcutController() {
            return new VoiceAccessShortcutController(mContext);
        }

        WindowWakeUpPolicy getWindowWakeUpPolicy() {
            return new WindowWakeUpPolicy(mContext);
        }
@@ -2512,6 +2519,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                com.android.internal.R.integer.config_keyguardDrawnTimeout);
        mKeyguardDelegate = injector.getKeyguardServiceDelegate();
        mTalkbackShortcutController = injector.getTalkbackShortcutController();
        mVoiceAccessShortcutController = injector.getVoiceAccessShortcutController();
        mWindowWakeUpPolicy = injector.getWindowWakeUpPolicy();
        initKeyCombinationRules();
        initSingleKeyGestureRules(injector.getLooper());
@@ -4262,6 +4270,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                                .isAccessibilityShortcutAvailable(false);
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK:
                        return enableTalkbackAndMagnifierKeyGestures();
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS:
                        return enableVoiceAccessKeyGestures();
                    default:
                        return false;
                }
@@ -4492,6 +4502,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    return true;
                }
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS:
                if (enableVoiceAccessKeyGestures()) {
                    if (complete) {
                        mVoiceAccessShortcutController.toggleVoiceAccess(mCurrentUserId);
                    }
                    return true;
                }
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION:
                AppLaunchData data = event.getAppLaunchData();
                if (complete && canLaunchApp && data != null
+4 −28
Original line number Diff line number Diff line
@@ -18,20 +18,15 @@ package com.android.server.policy;

import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE;

import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.os.UserHandle;
import android.provider.Settings;
import android.view.accessibility.AccessibilityManager;

import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
import com.android.internal.accessibility.util.AccessibilityUtils;
import com.android.internal.annotations.VisibleForTesting;

import java.util.List;
import java.util.Set;

/**
@@ -42,7 +37,6 @@ import java.util.Set;
class TalkbackShortcutController {
    private static final String TALKBACK_LABEL = "TalkBack";
    private final Context mContext;
    private final PackageManager mPackageManager;

    public enum ShortcutSource {
        GESTURE,
@@ -51,7 +45,6 @@ class TalkbackShortcutController {

    TalkbackShortcutController(Context context) {
        mContext = context;
        mPackageManager = mContext.getPackageManager();
    }

    /**
@@ -63,7 +56,10 @@ class TalkbackShortcutController {
    boolean toggleTalkback(int userId, ShortcutSource source) {
        final Set<ComponentName> enabledServices =
                AccessibilityUtils.getEnabledServicesFromSettings(mContext, userId);
        ComponentName componentName = getTalkbackComponent();
        ComponentName componentName =
                AccessibilityUtils.getInstalledAccessibilityServiceComponentNameByLabel(
                        mContext, TALKBACK_LABEL);
        ;
        if (componentName == null) {
            return false;
        }
@@ -83,21 +79,6 @@ class TalkbackShortcutController {
        return isTalkbackAlreadyEnabled;
    }

    private ComponentName getTalkbackComponent() {
        AccessibilityManager accessibilityManager = mContext.getSystemService(
                AccessibilityManager.class);
        List<AccessibilityServiceInfo> serviceInfos =
                accessibilityManager.getInstalledAccessibilityServiceList();

        for (AccessibilityServiceInfo service : serviceInfos) {
            final ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
            if (isTalkback(serviceInfo)) {
                return new ComponentName(serviceInfo.packageName, serviceInfo.name);
            }
        }
        return null;
    }

    boolean isTalkBackShortcutGestureEnabled() {
        return Settings.System.getIntForUser(mContext.getContentResolver(),
                Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED,
@@ -120,9 +101,4 @@ class TalkbackShortcutController {
                ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE,
                /* serviceEnabled= */ true);
    }

    private boolean isTalkback(ServiceInfo info) {
        return TALKBACK_LABEL.equals(info.loadLabel(mPackageManager).toString())
            && (info.applicationInfo.isSystemApp() || info.applicationInfo.isUpdatedSystemApp());
    }
}
Loading