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

Commit 736e8955 authored by David Padlipsky's avatar David Padlipsky
Browse files

Implement toggle talkback shortcut

Bug: 373458181
Test: atest WmTests
Flag: com.android.hardware.input.keyboard_a11y_shortcut_control
Change-Id: I42d61f620b7b15e0e4d215d6b99b090b9862b15d
parent 49cf41db
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ public final class KeyGestureEvent {
    public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT = 60;
    public static final int KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS = 61;
    public static final int KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY = 62;
    public static final int KEY_GESTURE_TYPE_TOGGLE_TALKBACK = 63;

    public static final int FLAG_CANCELLED = 1;

@@ -177,6 +178,7 @@ public final class KeyGestureEvent {
            KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT,
            KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
            KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY,
            KEY_GESTURE_TYPE_TOGGLE_TALKBACK,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface KeyGestureType {
@@ -597,6 +599,8 @@ public final class KeyGestureEvent {
                return "KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT";
            case KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS:
                return "KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS";
            case KEY_GESTURE_TYPE_TOGGLE_TALKBACK:
                return "KEY_GESTURE_TYPE_TOGGLE_TALKBACK";
            default:
                return Integer.toHexString(value);
        }
+12 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.view.WindowManagerPolicyConstants.FLAG_INTERACTIVE;

import static com.android.hardware.input.Flags.keyboardA11yShortcutControl;
import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
import static com.android.hardware.input.Flags.useKeyGestureEventHandlerMultiPressGestures;
import static com.android.server.flags.Flags.newBugreportKeyboardShortcut;
@@ -577,6 +578,17 @@ final class KeyGestureController {
                            focusedToken, /* flags = */0);
                }
                break;
            case KeyEvent.KEYCODE_T:
                if (keyboardA11yShortcutControl()) {
                    if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
                                focusedToken, /* flags = */0);
                    }
                }
                break;
            case KeyEvent.KEYCODE_DEL:
                if (newBugreportKeyboardShortcut()) {
                    if (firstDown && mEnableBugReportKeyboardShortcut && event.isMetaPressed()
+25 −1
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
import static android.view.contentprotection.flags.Flags.createAccessibilityOverlayAppOpEnabled;

import static com.android.hardware.input.Flags.emojiAndScreenshotKeycodesAvailable;
import static com.android.hardware.input.Flags.keyboardA11yShortcutControl;
import static com.android.hardware.input.Flags.modifierShortcutDump;
import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
import static com.android.hardware.input.Flags.useKeyGestureEventHandlerMultiPressGestures;
@@ -1615,7 +1616,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            case TRIPLE_PRESS_PRIMARY_NOTHING:
                break;
            case TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY:
                mTalkbackShortcutController.toggleTalkback(mCurrentUserId);
                mTalkbackShortcutController.toggleTalkback(mCurrentUserId,
                        TalkbackShortcutController.ShortcutSource.GESTURE);
                if (mTalkbackShortcutController.isTalkBackShortcutGestureEnabled()) {
                    performHapticFeedback(HapticFeedbackConstants.CONFIRM,
                            "Stem primary - Triple Press - Toggle Accessibility");
@@ -3603,6 +3605,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    return true;
                }
                break;
            case KeyEvent.KEYCODE_T:
                if (keyboardA11yShortcutControl()) {
                    if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
                        mTalkbackShortcutController.toggleTalkback(mCurrentUserId,
                                TalkbackShortcutController.ShortcutSource.KEYBOARD);
                        notifyKeyGestureCompleted(event,
                                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK);
                        return true;
                    }
                }
                break;
            case KeyEvent.KEYCODE_DEL:
                if (newBugreportKeyboardShortcut()) {
                    if (mEnableBugReportKeyboardShortcut && firstDown
@@ -4034,6 +4047,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD:
                        return mDefaultDisplayPolicy.isAwake() && mAccessibilityShortcutController
                                .isAccessibilityShortcutAvailable(false);
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK:
                        return keyboardA11yShortcutControl();
                    default:
                        return false;
                }
@@ -4251,6 +4266,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    mContext.closeSystemDialogs();
                }
                return true;
            case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK:
                if (keyboardA11yShortcutControl()) {
                    if (complete) {
                        mTalkbackShortcutController.toggleTalkback(mCurrentUserId,
                                TalkbackShortcutController.ShortcutSource.KEYBOARD);
                    }
                    return true;
                }
                break;
        }
        return false;
    }
+9 −4
Original line number Diff line number Diff line
@@ -44,6 +44,11 @@ class TalkbackShortcutController {
    private final Context mContext;
    private final PackageManager mPackageManager;

    public enum ShortcutSource {
        GESTURE,
        KEYBOARD,
    }

    TalkbackShortcutController(Context context) {
        mContext = context;
        mPackageManager = mContext.getPackageManager();
@@ -55,7 +60,7 @@ class TalkbackShortcutController {
     * @return talkback state after toggle. {@code true} if talkback is enabled, {@code false} if
     * talkback is disabled
     */
    boolean toggleTalkback(int userId) {
    boolean toggleTalkback(int userId, ShortcutSource source) {
        final Set<ComponentName> enabledServices =
                AccessibilityUtils.getEnabledServicesFromSettings(mContext, userId);
        ComponentName componentName = getTalkbackComponent();
@@ -65,13 +70,13 @@ class TalkbackShortcutController {

        boolean isTalkbackAlreadyEnabled = enabledServices.contains(componentName);

        if (isTalkBackShortcutGestureEnabled()) {
        if (source == ShortcutSource.KEYBOARD || isTalkBackShortcutGestureEnabled()) {
            isTalkbackAlreadyEnabled = !isTalkbackAlreadyEnabled;
            AccessibilityUtils.setAccessibilityServiceState(mContext, componentName,
                    isTalkbackAlreadyEnabled);
                    isTalkbackAlreadyEnabled, userId);

            // log stem triple press telemetry if it's a talkback enabled event.
            if (isTalkbackAlreadyEnabled) {
            if (source == ShortcutSource.GESTURE && isTalkbackAlreadyEnabled) {
                logStemTriplePressAccessibilityTelemetry(componentName);
            }
        }
+24 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.view.KeyEvent;

import androidx.test.filters.MediumTest;

import com.android.hardware.input.Flags;
import com.android.internal.annotations.Keep;

import junit.framework.Assert;
@@ -393,6 +394,17 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
                META_ON | CTRL_ON);
    }

    @Test
    @EnableFlags(Flags.FLAG_KEYBOARD_A11Y_SHORTCUT_CONTROL)
    @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    public void testToggleTalkbackPress() {
        testShortcutInternal("Meta + Alt + T -> Toggle talkback",
                new int[]{META_KEY, ALT_KEY, KeyEvent.KEYCODE_T},
                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK,
                KeyEvent.KEYCODE_T,
                META_ON | ALT_ON);
    }

    private void testShortcutInternal(String testName, int[] testKeys,
            @KeyGestureEvent.KeyGestureType int expectedKeyGestureType, int expectedKey,
            int expectedModifierState) {
@@ -699,4 +711,16 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS));
        mPhoneWindowManager.assertCloseAllDialogs();
    }

    @Test
    @EnableFlags(com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SHORTCUT_CONTROL)
    public void testKeyGestureToggleTalkback() {
        Assert.assertTrue(
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK));
        mPhoneWindowManager.assertTalkBack(true);

        Assert.assertTrue(
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK));
        mPhoneWindowManager.assertTalkBack(false);
    }
}
Loading