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

Commit 32382aa3 authored by Wenyu Zhang's avatar Wenyu Zhang
Browse files

a11y: Remove VoiceAccessShortcutController from PhoneWindowManager

With key gesture handler APIs, we can handle shortcuts in A11y
directly, this can allow components to react appropriately.
e.g. Use displayId passed in key gesture event to show UI on
correct display instead of routing that information from PWM to
A11y service.

Attaching original commit that adds voice access shortcut
(I116ac81f76198122b7ab4dce370197781386d06b) for completeness check.

Change-Id: I0f2a1c938c60772bbba19c3112c2d46cad26fc2f
Bug: 413279228
Test: atest AccessibilityManagerServiceTest
Flag: EXEMPT refactor
parent d6427c5d
Loading
Loading
Loading
Loading
+0 −16
Original line number Diff line number Diff line
@@ -83,7 +83,6 @@ 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.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;
@@ -486,8 +485,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {

    private TalkbackShortcutController mTalkbackShortcutController;

    private VoiceAccessShortcutController mVoiceAccessShortcutController;

    private WindowWakeUpPolicy mWindowWakeUpPolicy;

    boolean mSafeMode;
@@ -2258,10 +2255,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            return new TalkbackShortcutController(mContext);
        }

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

        WindowWakeUpPolicy getWindowWakeUpPolicy() {
            return new WindowWakeUpPolicy(mContext);
        }
@@ -2499,7 +2492,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                com.android.internal.R.integer.config_keyguardDrawnTimeout);
        mKeyguardDelegate = injector.getKeyguardServiceDelegate();
        mTalkbackShortcutController = injector.getTalkbackShortcutController();
        mVoiceAccessShortcutController = injector.getVoiceAccessShortcutController();
        mWindowWakeUpPolicy = injector.getWindowWakeUpPolicy();
        initSingleKeyGestureRules(injector.getLooper());
        initKeyGestures();
@@ -3412,9 +3404,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        if (enableTalkbackAndMagnifierKeyGestures()) {
            supportedGestures.add(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK);
        }
        if (enableVoiceAccessKeyGestures()) {
            supportedGestures.add(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS);
        }
        if (!com.android.window.flags.Flags.enableKeyGestureHandlerForRecents()) {
            // When enableKeyGestureHandlerForRecents is enabled, the event is handled in the
            // recents app.
@@ -3617,11 +3606,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                            TalkbackShortcutController.ShortcutSource.KEYBOARD);
                }
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS:
                if (complete) {
                    mVoiceAccessShortcutController.toggleVoiceAccess(mCurrentUserId);
                }
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION:
                AppLaunchData data = event.getAppLaunchData();
                if (complete && canLaunchApp && data != null) {
+0 −62
Original line number Diff line number Diff line
/*
 * Copyright 2025 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.server.policy;

import android.content.ComponentName;
import android.content.Context;
import android.util.Slog;

import com.android.internal.accessibility.util.AccessibilityUtils;

import androidx.annotation.VisibleForTesting;

import java.util.Set;

/** This class controls voice access shortcut related operations such as toggling, querying. */
class VoiceAccessShortcutController {
    private static final String TAG = VoiceAccessShortcutController.class.getSimpleName();
    private static final String VOICE_ACCESS_LABEL = "Voice Access";

    private final Context mContext;

    VoiceAccessShortcutController(Context context) {
        mContext = context;
    }

    /**
     * A function that toggles voice access service.
     *
     * @return whether voice access is enabled after being toggled.
     */
    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
    boolean toggleVoiceAccess(int userId) {
        final Set<ComponentName> enabledServices =
                AccessibilityUtils.getEnabledServicesFromSettings(mContext, userId);
        ComponentName componentName =
                AccessibilityUtils.getInstalledAccessibilityServiceComponentNameByLabel(
                        mContext, VOICE_ACCESS_LABEL);
        if (componentName == null) {
            Slog.e(TAG, "Toggle Voice Access failed due to componentName being null");
            return false;
        }

        boolean newState = !enabledServices.contains(componentName);
        AccessibilityUtils.setAccessibilityServiceState(mContext, componentName, newState, userId);

        return newState;
    }
}
+0 −9
Original line number Diff line number Diff line
@@ -425,15 +425,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
        mPhoneWindowManager.assertTalkBack(false);
    }

    @Test
    public void testKeyGestureToggleVoiceAccess() {
        sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS);
        mPhoneWindowManager.assertVoiceAccess(true);

        sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS);
        mPhoneWindowManager.assertVoiceAccess(false);
    }

    @Test
    public void testKeyGestureToggleDoNotDisturb() {
        mPhoneWindowManager.overrideZenMode(Settings.Global.ZEN_MODE_OFF);
+0 −23
Original line number Diff line number Diff line
@@ -199,8 +199,6 @@ class TestPhoneWindowManager {
    private boolean mIsTalkBackEnabled;
    private boolean mIsTalkBackShortcutGestureEnabled;

    private boolean mIsVoiceAccessEnabled;

    private Intent mBrowserIntent;
    private Intent mSmsIntent;

@@ -223,18 +221,6 @@ class TestPhoneWindowManager {
        }
    }

    private class TestVoiceAccessShortcutController extends VoiceAccessShortcutController {
        TestVoiceAccessShortcutController(Context context) {
            super(context);
        }

        @Override
        boolean toggleVoiceAccess(int currentUserId) {
            mIsVoiceAccessEnabled = !mIsVoiceAccessEnabled;
            return mIsVoiceAccessEnabled;
        }
    }

    private class TestInjector extends PhoneWindowManager.Injector {
        TestInjector(Context context, WindowManagerPolicy.WindowManagerFuncs funcs) {
            super(context, funcs);
@@ -270,10 +256,6 @@ class TestPhoneWindowManager {
            return new TestTalkbackShortcutController(mContext);
        }

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

        WindowWakeUpPolicy getWindowWakeUpPolicy() {
            return mWindowWakeUpPolicy;
        }
@@ -1015,11 +997,6 @@ class TestPhoneWindowManager {
        Assert.assertEquals(expectEnabled, mIsTalkBackEnabled);
    }

    void assertVoiceAccess(boolean expectEnabled) {
        mTestLooper.dispatchAll();
        Assert.assertEquals(expectEnabled, mIsVoiceAccessEnabled);
    }

    void assertKeyGestureEventSentToKeyGestureController(int gestureType) {
        verify(mInputManagerInternal)
                .handleKeyGestureInKeyGestureController(anyInt(), any(), anyInt(), eq(gestureType));