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

Commit 078b7fac authored by Riley Jones's avatar Riley Jones Committed by Android (Google) Code Review
Browse files

Merge "Allow gesture shortcut to be clickable while FAB is present." into main

parents 88f1c7e6 01dc4402
Loading
Loading
Loading
Loading
+13 −17
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.UserSh

import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
@@ -176,24 +177,19 @@ public final class ShortcutUtils {
     * @param type The shortcut type.
     * @return Mapping key in Settings.
     */
    @SuppressLint("SwitchIntDef")
    public static String convertToKey(@UserShortcutType int type) {
        switch (type) {
            case SOFTWARE:
                return Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
            case GESTURE:
                return Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS;
            case HARDWARE:
                return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
            case TRIPLETAP:
                return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
            case TWOFINGER_DOUBLETAP:
                return Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED;
            case QUICK_SETTINGS:
                return Settings.Secure.ACCESSIBILITY_QS_TARGETS;
            default:
                throw new IllegalArgumentException(
        return switch (type) {
            case SOFTWARE -> Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
            case GESTURE -> Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS;
            case HARDWARE -> Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
            case TRIPLETAP -> Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
            case TWOFINGER_DOUBLETAP ->
                    Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED;
            case QUICK_SETTINGS -> Settings.Secure.ACCESSIBILITY_QS_TARGETS;
            default -> throw new IllegalArgumentException(
                    "Unsupported user shortcut type: " + type);
        }
        };
    }

    /**
+67 −0
Original line number Diff line number Diff line
/*
 * 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.systemui.accessibility;

import android.content.Context;
import android.provider.Settings;

import androidx.annotation.MainThread;
import androidx.annotation.Nullable;

import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.settings.UserTracker;

import javax.inject.Inject;

/**
 * Controller for tracking the current accessibility gesture list.
 *
 * @see Settings.Secure#ACCESSIBILITY_GESTURE_TARGETS
 */
@MainThread
@SysUISingleton
public class AccessibilityGestureTargetsObserver extends
        SecureSettingsContentObserver<AccessibilityGestureTargetsObserver.TargetsChangedListener> {

    /** Listener for accessibility gesture targets changes. */
    public interface TargetsChangedListener {

        /**
         * Called when accessibility gesture targets changes.
         *
         * @param targets Current content of {@link Settings.Secure#ACCESSIBILITY_GESTURE_TARGETS}
         */
        void onAccessibilityGestureTargetsChanged(String targets);
    }

    @Inject
    public AccessibilityGestureTargetsObserver(Context context, UserTracker userTracker) {
        super(context, userTracker, Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS);
    }

    @Override
    void onValueChanged(TargetsChangedListener listener, String value) {
        listener.onAccessibilityGestureTargetsChanged(value);
    }

    /** Returns the current string from settings key
     *  {@link Settings.Secure#ACCESSIBILITY_GESTURE_TARGETS}. */
    @Nullable
    public String getCurrentAccessibilityGestureTargets() {
        return getSettingsValue();
    }
}
+47 −28
Original line number Diff line number Diff line
@@ -19,19 +19,24 @@ package com.android.systemui.navigationbar;
import static android.app.StatusBarManager.WINDOW_NAVIGATION_BAR;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
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.SOFTWARE;
import static com.android.systemui.accessibility.SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON;
import static com.android.systemui.accessibility.SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;

import android.content.ContentResolver;
import android.content.Context;
@@ -60,10 +65,11 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;

import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.accessibility.AccessibilityGestureTargetsObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dagger.SysUISingleton;
@@ -107,6 +113,7 @@ public final class NavBarHelper implements
        AccessibilityManager.AccessibilityServicesStateChangeListener,
        AccessibilityButtonModeObserver.ModeChangedListener,
        AccessibilityButtonTargetsObserver.TargetsChangedListener,
        AccessibilityGestureTargetsObserver.TargetsChangedListener,
        OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
        Dumpable, CommandQueue.Callbacks, ConfigurationController.ConfigurationListener {
    private static final String TAG = NavBarHelper.class.getSimpleName();
@@ -122,6 +129,7 @@ public final class NavBarHelper implements
    private final SystemActions mSystemActions;
    private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
    private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
    private final AccessibilityGestureTargetsObserver mAccessibilityGestureTargetsObserver;
    private final List<NavbarTaskbarStateUpdater> mStateListeners = new ArrayList<>();
    private final Context mContext;
    private final NotificationShadeWindowController mNotificationShadeWindowController;
@@ -188,6 +196,7 @@ public final class NavBarHelper implements
    public NavBarHelper(Context context, AccessibilityManager accessibilityManager,
            AccessibilityButtonModeObserver accessibilityButtonModeObserver,
            AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
            AccessibilityGestureTargetsObserver accessibilityGestureTargetsObserver,
            SystemActions systemActions,
            OverviewProxyService overviewProxyService,
            Lazy<AssistManager> assistManagerLazy,
@@ -220,6 +229,7 @@ public final class NavBarHelper implements
        mSystemActions = systemActions;
        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
        mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;
        mAccessibilityGestureTargetsObserver = accessibilityGestureTargetsObserver;
        mWm = wm;
        mDefaultDisplayId = displayTracker.getDefaultDisplayId();
        mEdgeBackGestureHandler = edgeBackGestureHandlerFactory.create(context);
@@ -249,6 +259,7 @@ public final class NavBarHelper implements
        mAccessibilityManager.addAccessibilityServicesStateChangeListener(this);
        mAccessibilityButtonModeObserver.addListener(this);
        mAccessibilityButtonTargetsObserver.addListener(this);
        mAccessibilityGestureTargetsObserver.addListener(this);

        // Setup assistant listener
        mContentResolver.registerContentObserver(
@@ -291,6 +302,7 @@ public final class NavBarHelper implements
        mAccessibilityManager.removeAccessibilityServicesStateChangeListener(this);
        mAccessibilityButtonModeObserver.removeListener(this);
        mAccessibilityButtonTargetsObserver.removeListener(this);
        mAccessibilityGestureTargetsObserver.removeListener(this);

        // Clean up assistant listeners
        mContentResolver.unregisterContentObserver(mAssistContentObserver);
@@ -379,44 +391,51 @@ public final class NavBarHelper implements
        updateA11yState();
    }

    @Override
    public void onAccessibilityGestureTargetsChanged(String targets) {
        updateA11yState();
    }

    @Override
    public void onConfigChanged(Configuration newConfig) {
        mEdgeBackGestureHandler.onConfigurationChanged(newConfig);
    }

    private int getNumOfA11yShortcutTargetsForNavSystem() {
        final int buttonMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
        final int shortcutType;
        if (!android.provider.Flags.a11yStandaloneGestureEnabled()) {
            shortcutType = buttonMode
                    != ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU ? SOFTWARE : DEFAULT;
            // If accessibility button is floating menu mode, there are no clickable targets.
        } else {
            if (mNavBarMode == NAV_BAR_MODE_GESTURAL) {
                shortcutType = GESTURE;
            } else {
                shortcutType = buttonMode == ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR
                        ? SOFTWARE : DEFAULT;
            }
        }
        return mAccessibilityManager.getAccessibilityShortcutTargets(shortcutType).size();
    }

    /**
     * Updates the current accessibility button state. The accessibility button state is only
     * used for {@link Secure#ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} and
     * {@link Secure#ACCESSIBILITY_BUTTON_MODE_GESTURE}, otherwise it is reset to 0.
     */
    private void updateA11yState() {
    @VisibleForTesting
    void updateA11yState() {
        final long prevState = mA11yButtonState;
        final boolean clickable;
        final boolean longClickable;
        if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
                == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
            // If accessibility button is floating menu mode, click and long click state should be
            // disabled.
            clickable = false;
            longClickable = false;
            mA11yButtonState = 0;
        } else {
            // AccessibilityManagerService resolves services for the current user since the local
            // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS
            // permission
            final List<String> a11yButtonTargets =
                    mAccessibilityManager.getAccessibilityShortcutTargets(
                            ShortcutConstants.UserShortcutType.SOFTWARE);
            final int requestingServices = a11yButtonTargets.size();

            clickable = requestingServices >= 1;

        int clickableServices = getNumOfA11yShortcutTargetsForNavSystem();
        clickable = clickableServices >= 1;
        // `longClickable` is used to determine whether to pop up the accessibility chooser
        // dialog or not, and it’s also only for multiple services.
            longClickable = requestingServices >= 2;
        longClickable = clickableServices >= 2;
        mA11yButtonState = (clickable ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
                | (longClickable ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
        }

        // Update the system actions if the state has changed
        if (prevState != mA11yButtonState) {
+104 −0
Original line number Diff line number Diff line
/*
 * 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.systemui.accessibility;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.ActivityManager;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;

import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.settings.UserTracker;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

/** Test for {@link AccessibilityGestureTargetsObserver}. */
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class AccessibilityGestureTargetsObserverTest extends SysuiTestCase {
    private static final int MY_USER_ID = ActivityManager.getCurrentUser();

    @Rule
    public MockitoRule mockito = MockitoJUnit.rule();

    @Mock
    private UserTracker mUserTracker;
    @Mock
    private AccessibilityGestureTargetsObserver.TargetsChangedListener mListener;

    private AccessibilityGestureTargetsObserver mAccessibilityGestureTargetsObserver;

    private static final String TEST_A11Y_BTN_TARGETS = "Magnification";

    @Before
    public void setUp() {
        when(mUserTracker.getUserId()).thenReturn(MY_USER_ID);
        mAccessibilityGestureTargetsObserver = new AccessibilityGestureTargetsObserver(mContext,
                mUserTracker);
    }

    @Test
    public void onChange_haveListener_invokeCallback() {
        mAccessibilityGestureTargetsObserver.addListener(mListener);
        Settings.Secure.putStringForUser(mContext.getContentResolver(),
                Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS, TEST_A11Y_BTN_TARGETS,
                MY_USER_ID);

        mAccessibilityGestureTargetsObserver.mContentObserver.onChange(false);

        verify(mListener).onAccessibilityGestureTargetsChanged(TEST_A11Y_BTN_TARGETS);
    }

    @Test
    public void onChange_listenerRemoved_noInvokeCallback() {
        mAccessibilityGestureTargetsObserver.addListener(mListener);
        mAccessibilityGestureTargetsObserver.removeListener(mListener);
        Settings.Secure.putStringForUser(mContext.getContentResolver(),
                Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS, TEST_A11Y_BTN_TARGETS,
                MY_USER_ID);

        mAccessibilityGestureTargetsObserver.mContentObserver.onChange(false);

        verify(mListener, never()).onAccessibilityGestureTargetsChanged(anyString());
    }

    @Test
    public void getCurrentAccessibilityGestureTargets_expectedValue() {
        Settings.Secure.putStringForUser(mContext.getContentResolver(),
                Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS, TEST_A11Y_BTN_TARGETS,
                MY_USER_ID);

        final String actualValue =
                mAccessibilityGestureTargetsObserver.getCurrentAccessibilityGestureTargets();

        assertThat(actualValue).isEqualTo(TEST_A11Y_BTN_TARGETS);
    }
}
+88 −0
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ package com.android.systemui.navigationbar;

import static android.app.StatusBarManager.WINDOW_NAVIGATION_BAR;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;

import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
@@ -37,6 +39,9 @@ import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.res.Configuration;
import android.os.Handler;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.provider.Flags;
import android.view.IWindowManager;
import android.view.accessibility.AccessibilityManager;

@@ -47,6 +52,7 @@ import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutT
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.accessibility.AccessibilityGestureTargetsObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dump.DumpManager;
@@ -94,6 +100,8 @@ public class NavBarHelperTest extends SysuiTestCase {
    @Mock
    AccessibilityButtonTargetsObserver mAccessibilityButtonTargetObserver;
    @Mock
    AccessibilityGestureTargetsObserver mAccessibilityGestureTargetObserver;
    @Mock
    SystemActions mSystemActions;
    @Mock
    OverviewProxyService mOverviewProxyService;
@@ -152,6 +160,7 @@ public class NavBarHelperTest extends SysuiTestCase {
                mAccessibilityManager).addAccessibilityServicesStateChangeListener(any());
        mNavBarHelper = new NavBarHelper(mContext, mAccessibilityManager,
                mAccessibilityButtonModeObserver, mAccessibilityButtonTargetObserver,
                mAccessibilityGestureTargetObserver,
                mSystemActions, mOverviewProxyService, mAssistManagerLazy,
                () -> Optional.of(mock(CentralSurfaces.class)), mock(KeyguardStateController.class),
                mNavigationModeController, mEdgeBackGestureHandlerFactory, mWm, mUserTracker,
@@ -171,6 +180,7 @@ public class NavBarHelperTest extends SysuiTestCase {
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        verify(mAccessibilityButtonModeObserver, times(1)).addListener(mNavBarHelper);
        verify(mAccessibilityButtonTargetObserver, times(1)).addListener(mNavBarHelper);
        verify(mAccessibilityGestureTargetObserver, times(1)).addListener(mNavBarHelper);
        verify(mAccessibilityManager, times(1)).addAccessibilityServicesStateChangeListener(
                mNavBarHelper);
        verify(mAssistManager, times(1)).getAssistInfoForUser(anyInt());
@@ -185,6 +195,7 @@ public class NavBarHelperTest extends SysuiTestCase {
        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        verify(mAccessibilityButtonModeObserver, times(1)).removeListener(mNavBarHelper);
        verify(mAccessibilityButtonTargetObserver, times(1)).removeListener(mNavBarHelper);
        verify(mAccessibilityGestureTargetObserver, times(1)).removeListener(mNavBarHelper);
        verify(mAccessibilityManager, times(1)).removeAccessibilityServicesStateChangeListener(
                mNavBarHelper);
        verify(mWm, times(1)).removeRotationWatcher(any());
@@ -353,6 +364,83 @@ public class NavBarHelperTest extends SysuiTestCase {
        verify(mEdgeBackGestureHandler, times(1)).onConfigurationChanged(any());
    }

    @Test
    public void updateA11yState_navBarMode_softwareTargets_isClickable() {
        when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
                ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
        when(mAccessibilityManager.getAccessibilityShortcutTargets(UserShortcutType.SOFTWARE))
                .thenReturn(createFakeShortcutTargets());

        mNavBarHelper.updateA11yState();
        long state = mNavBarHelper.getA11yButtonState();
        assertThat(state & SYSUI_STATE_A11Y_BUTTON_CLICKABLE).isEqualTo(
                SYSUI_STATE_A11Y_BUTTON_CLICKABLE);
        assertThat(state & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE).isEqualTo(
                SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE);
    }

    @Test
    @DisableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
    public void updateA11yState_gestureMode_softwareTargets_isClickable() {
        when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
                ACCESSIBILITY_BUTTON_MODE_GESTURE);
        when(mAccessibilityManager.getAccessibilityShortcutTargets(UserShortcutType.SOFTWARE))
                .thenReturn(createFakeShortcutTargets());

        mNavBarHelper.updateA11yState();
        long state = mNavBarHelper.getA11yButtonState();
        assertThat(state & SYSUI_STATE_A11Y_BUTTON_CLICKABLE).isEqualTo(
                SYSUI_STATE_A11Y_BUTTON_CLICKABLE);
        assertThat(state & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE).isEqualTo(
                SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE);
    }

    @Test
    @EnableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
    public void updateA11yState_gestureNavMode_floatingButtonMode_gestureTargets_isClickable() {
        mNavBarHelper.onNavigationModeChanged(NAV_BAR_MODE_GESTURAL);
        when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
                ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
        when(mAccessibilityManager.getAccessibilityShortcutTargets(UserShortcutType.GESTURE))
                .thenReturn(createFakeShortcutTargets());

        mNavBarHelper.updateA11yState();
        long state = mNavBarHelper.getA11yButtonState();
        assertThat(state & SYSUI_STATE_A11Y_BUTTON_CLICKABLE).isEqualTo(
                SYSUI_STATE_A11Y_BUTTON_CLICKABLE);
        assertThat(state & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE).isEqualTo(
                SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE);
    }

    @Test
    @EnableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
    public void updateA11yState_navBarMode_gestureTargets_isNotClickable() {
        when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
                ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
        when(mAccessibilityManager.getAccessibilityShortcutTargets(UserShortcutType.GESTURE))
                .thenReturn(createFakeShortcutTargets());

        mNavBarHelper.updateA11yState();
        long state = mNavBarHelper.getA11yButtonState();
        assertThat(state & SYSUI_STATE_A11Y_BUTTON_CLICKABLE).isEqualTo(0);
        assertThat(state & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE).isEqualTo(0);
    }

    @Test
    @EnableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
    public void updateA11yState_singleTarget_clickableButNotLongClickable() {
        when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
                ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
        when(mAccessibilityManager.getAccessibilityShortcutTargets(UserShortcutType.SOFTWARE))
                .thenReturn(new ArrayList<>(List.of("a")));

        mNavBarHelper.updateA11yState();
        long state = mNavBarHelper.getA11yButtonState();
        assertThat(state & SYSUI_STATE_A11Y_BUTTON_CLICKABLE).isEqualTo(
                SYSUI_STATE_A11Y_BUTTON_CLICKABLE);
        assertThat(state & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE).isEqualTo(0);
    }

    private List<String> createFakeShortcutTargets() {
        return new ArrayList<>(List.of("a", "b", "c", "d"));
    }
Loading