Cache accessibility info in NavBarHelper to reduce binder calls

- Currently, we make two binder calls whenever the sysui state changes
  to fetch the current accessibility info.  Instead we can use the
  AccessibilityButtonTargetsObserver to listen for the changes and
  only update the accessibility state when it changes.

Bug: 201633154
Test: Enable/disable accessibility services and verify button shows
      Enable/disable > 1 accessibility services and verify that
      button is long-clickable to show the services menu
      Verify both of the above with gesture nav & accessibility service
      as well

Change-Id: I84a7d20040c61ea75ac0b9e1f790f4a8b0ebe398
This commit is contained in:
Winson Chung
2022-02-01 22:48:47 +00:00
parent d7c5ca769d
commit 62f476835c
5 changed files with 105 additions and 72 deletions

View File

@@ -18,6 +18,8 @@ package com.android.systemui.navigationbar;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
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;
@@ -39,6 +41,8 @@ import androidx.annotation.NonNull;
import com.android.systemui.Dumpable;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
@@ -70,13 +74,16 @@ import dagger.Lazy;
@SysUISingleton
public final class NavBarHelper implements
AccessibilityButtonModeObserver.ModeChangedListener,
AccessibilityButtonTargetsObserver.TargetsChangedListener,
OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
Dumpable {
private final AccessibilityManager mAccessibilityManager;
private final Lazy<AssistManager> mAssistManagerLazy;
private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
private final UserTracker mUserTracker;
private final SystemActions mSystemActions;
private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
private final List<NavbarTaskbarStateUpdater> mA11yEventListeners = new ArrayList<>();
private final Context mContext;
private ContentResolver mContentResolver;
@@ -84,12 +91,13 @@ public final class NavBarHelper implements
private boolean mLongPressHomeEnabled;
private boolean mAssistantTouchGestureEnabled;
private int mNavBarMode;
private int mA11yButtonState;
private final ContentObserver mAssistContentObserver = new ContentObserver(
new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange, Uri uri) {
updateAssitantAvailability();
updateAssistantAvailability();
}
};
@@ -100,8 +108,9 @@ public final class NavBarHelper implements
*/
@Inject
public NavBarHelper(Context context, AccessibilityManager accessibilityManager,
AccessibilityManagerWrapper accessibilityManagerWrapper,
AccessibilityButtonModeObserver accessibilityButtonModeObserver,
AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
SystemActions systemActions,
OverviewProxyService overviewProxyService,
Lazy<AssistManager> assistManagerLazy,
Lazy<Optional<StatusBar>> statusBarOptionalLazy,
@@ -114,11 +123,14 @@ public final class NavBarHelper implements
mAssistManagerLazy = assistManagerLazy;
mStatusBarOptionalLazy = statusBarOptionalLazy;
mUserTracker = userTracker;
accessibilityManagerWrapper.addCallback(
mSystemActions = systemActions;
accessibilityManager.addAccessibilityServicesStateChangeListener(
accessibilityManager1 -> NavBarHelper.this.dispatchA11yEventUpdate());
mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;
mAccessibilityButtonModeObserver.addListener(this);
mAccessibilityButtonTargetsObserver.addListener(this);
mNavBarMode = navigationModeController.addListener(this);
overviewProxyService.addCallback(this);
dumpManager.registerDumpable(this);
@@ -134,7 +146,7 @@ public final class NavBarHelper implements
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
false, mAssistContentObserver, UserHandle.USER_ALL);
updateAssitantAvailability();
updateAssistantAvailability();
}
public void destroy() {
@@ -168,9 +180,63 @@ public final class NavBarHelper implements
@Override
public void onAccessibilityButtonModeChanged(int mode) {
updateA11yState();
dispatchA11yEventUpdate();
}
@Override
public void onAccessibilityButtonTargetsChanged(String targets) {
updateA11yState();
dispatchA11yEventUpdate();
}
/**
* Updates the current accessibility button state.
*/
private void updateA11yState() {
final int 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(
AccessibilityManager.ACCESSIBILITY_BUTTON);
final int requestingServices = a11yButtonTargets.size();
clickable = requestingServices >= 1;
longClickable = requestingServices >= 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) {
updateSystemAction(clickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON);
updateSystemAction(longClickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER);
}
}
/**
* Registers/unregisters the given system action id.
*/
private void updateSystemAction(boolean register, int actionId) {
if (register) {
mSystemActions.register(actionId);
} else {
mSystemActions.unregister(actionId);
}
}
/**
* See {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and
* {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE}
@@ -179,32 +245,17 @@ public final class NavBarHelper implements
* a11y button in the navbar
*/
public int getA11yButtonState() {
// 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(
AccessibilityManager.ACCESSIBILITY_BUTTON);
final int requestingServices = a11yButtonTargets.size();
// If accessibility button is floating menu mode, click and long click state should be
// disabled.
if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
== ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
return 0;
}
return (requestingServices >= 1 ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
| (requestingServices >= 2 ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
return mA11yButtonState;
}
@Override
public void onConnectionChanged(boolean isConnected) {
if (isConnected) {
updateAssitantAvailability();
updateAssistantAvailability();
}
}
private void updateAssitantAvailability() {
private void updateAssistantAvailability() {
boolean assistantAvailableForUser = mAssistManagerLazy.get()
.getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
boolean longPressDefault = mContext.getResources().getBoolean(
@@ -236,7 +287,7 @@ public final class NavBarHelper implements
@Override
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
updateAssitantAvailability();
updateAssistantAvailability();
}
/**

View File

@@ -110,7 +110,6 @@ import com.android.internal.util.LatencyTracker;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.R;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
@@ -122,7 +121,6 @@ import com.android.systemui.navigationbar.gestural.QuickswitchOrientedNavHandle;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.rotation.RotationButton;
import com.android.systemui.shared.rotation.RotationButtonController;
@@ -192,7 +190,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final Optional<LegacySplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
private final Optional<BackAnimation> mBackAnimation;
private final SystemActions mSystemActions;
private final Handler mHandler;
private final NavigationBarOverlayController mNavbarOverlayController;
private final UiEventLogger mUiEventLogger;
@@ -307,7 +304,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
new NavBarHelper.NavbarTaskbarStateUpdater() {
@Override
public void updateAccessibilityServicesState() {
updateAcessibilityStateFlags();
updateAccessibilityStateFlags();
}
@Override
@@ -495,12 +492,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
ShadeController shadeController,
NotificationRemoteInputManager notificationRemoteInputManager,
NotificationShadeDepthController notificationShadeDepthController,
SystemActions systemActions,
@Main Handler mainHandler,
NavigationBarOverlayController navbarOverlayController,
UiEventLogger uiEventLogger,
NavBarHelper navBarHelper,
UserTracker userTracker,
LightBarController mainLightBarController,
LightBarController.Factory lightBarControllerFactory,
AutoHideController mainAutoHideController,
@@ -528,7 +523,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
mBackAnimation = backAnimation;
mSystemActions = systemActions;
mHandler = mainHandler;
mNavbarOverlayController = navbarOverlayController;
mUiEventLogger = uiEventLogger;
@@ -646,7 +640,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
notifyNavigationBarScreenOn();
mOverviewProxyService.addCallback(mOverviewProxyListener);
updateSystemUiStateFlags(-1);
updateSystemUiStateFlags();
// Currently there is no accelerometer sensor on non-default display.
if (mIsOnDefaultDisplay) {
@@ -904,7 +898,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mNavigationBarView.setNavigationIconHints(hints);
}
checkBarModes();
updateSystemUiStateFlags(-1);
updateSystemUiStateFlags();
}
@Override
@@ -914,7 +908,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
&& window == StatusBarManager.WINDOW_NAVIGATION_BAR
&& mNavigationBarWindowState != state) {
mNavigationBarWindowState = state;
updateSystemUiStateFlags(-1);
updateSystemUiStateFlags();
mShowOrientedHandleForImmersiveMode = state == WINDOW_STATE_HIDDEN;
if (mOrientationHandle != null
&& mStartingQuickSwitchRotation != -1) {
@@ -993,7 +987,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
if (mBehavior != behavior) {
mBehavior = behavior;
mNavigationBarView.setBehavior(behavior);
updateSystemUiStateFlags(-1);
updateSystemUiStateFlags();
}
}
@@ -1160,7 +1154,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
accessibilityButton.setOnClickListener(this::onAccessibilityClick);
accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
updateAcessibilityStateFlags();
updateAccessibilityStateFlags();
ButtonDispatcher imeSwitcherButton = mNavigationBarView.getImeSwitchButton();
imeSwitcherButton.setOnClickListener(this::onImeSwitcherClick);
@@ -1386,21 +1380,18 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
return true;
}
void updateAcessibilityStateFlags() {
int a11yFlags = mNavBarHelper.getA11yButtonState();
void updateAccessibilityStateFlags() {
if (mNavigationBarView != null) {
int a11yFlags = mNavBarHelper.getA11yButtonState();
boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
}
updateSystemUiStateFlags(a11yFlags);
updateSystemUiStateFlags();
}
public void updateSystemUiStateFlags(int a11yFlags) {
if (a11yFlags < 0) {
a11yFlags = mNavBarHelper.getA11yButtonState();
}
public void updateSystemUiStateFlags() {
int a11yFlags = mNavBarHelper.getA11yButtonState();
boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
@@ -1414,16 +1405,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
.setFlag(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
allowSystemGestureIgnoringBarVisibility())
.commitUpdate(mDisplayId);
registerAction(clickable, SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON);
registerAction(longClickable, SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER);
}
private void registerAction(boolean register, int actionId) {
if (register) {
mSystemActions.register(actionId);
} else {
mSystemActions.unregister(actionId);
}
}
private void updateAssistantEntrypoints(boolean assistantAvailable) {
@@ -1641,7 +1622,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
// The accessibility settings may be different for the new user
updateAcessibilityStateFlags();
updateAccessibilityStateFlags();
}
}
};
@@ -1673,12 +1654,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final ShadeController mShadeController;
private final NotificationRemoteInputManager mNotificationRemoteInputManager;
private final NotificationShadeDepthController mNotificationShadeDepthController;
private final SystemActions mSystemActions;
private final Handler mMainHandler;
private final NavigationBarOverlayController mNavbarOverlayController;
private final UiEventLogger mUiEventLogger;
private final NavBarHelper mNavBarHelper;
private final UserTracker mUserTracker;
private final LightBarController mMainLightBarController;
private final LightBarController.Factory mLightBarControllerFactory;
private final AutoHideController mMainAutoHideController;
@@ -1707,12 +1686,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
ShadeController shadeController,
NotificationRemoteInputManager notificationRemoteInputManager,
NotificationShadeDepthController notificationShadeDepthController,
SystemActions systemActions,
@Main Handler mainHandler,
NavigationBarOverlayController navbarOverlayController,
UiEventLogger uiEventLogger,
NavBarHelper navBarHelper,
UserTracker userTracker,
LightBarController mainLightBarController,
LightBarController.Factory lightBarControllerFactory,
AutoHideController mainAutoHideController,
@@ -1738,12 +1715,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mShadeController = shadeController;
mNotificationRemoteInputManager = notificationRemoteInputManager;
mNotificationShadeDepthController = notificationShadeDepthController;
mSystemActions = systemActions;
mMainHandler = mainHandler;
mNavbarOverlayController = navbarOverlayController;
mUiEventLogger = uiEventLogger;
mNavBarHelper = navBarHelper;
mUserTracker = userTracker;
mMainLightBarController = mainLightBarController;
mLightBarControllerFactory = lightBarControllerFactory;
mMainAutoHideController = mainAutoHideController;
@@ -1763,9 +1738,9 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mSysUiFlagsContainer, mBroadcastDispatcher, mCommandQueue, mPipOptional,
mSplitScreenOptional, mRecentsOptional, mStatusBarOptionalLazy,
mShadeController, mNotificationRemoteInputManager,
mNotificationShadeDepthController, mSystemActions, mMainHandler,
mNotificationShadeDepthController, mMainHandler,
mNavbarOverlayController, mUiEventLogger, mNavBarHelper,
mUserTracker, mMainLightBarController, mLightBarControllerFactory,
mMainLightBarController, mLightBarControllerFactory,
mMainAutoHideController, mAutoHideControllerFactory, mTelecomManagerOptional,
mInputMethodManager, mBackAnimation);
}

View File

@@ -677,7 +677,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
if (navBarFragment != null) {
navBarFragment.updateSystemUiStateFlags(-1);
navBarFragment.updateSystemUiStateFlags();
}
if (navBarView != null) {
navBarView.updateDisabledSystemUiStateFlags();

View File

@@ -31,6 +31,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.recents.OverviewProxyService;
@@ -55,10 +57,12 @@ public class NavBarHelperTest extends SysuiTestCase {
@Mock
AccessibilityManager mAccessibilityManager;
@Mock
AccessibilityManagerWrapper mAccessibilityManagerWrapper;
@Mock
AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
@Mock
AccessibilityButtonTargetsObserver mAccessibilityButtonTargetObserver;
@Mock
SystemActions mSystemActions;
@Mock
OverviewProxyService mOverviewProxyService;
@Mock
Lazy<AssistManager> mAssistManagerLazy;
@@ -85,8 +89,9 @@ public class NavBarHelperTest extends SysuiTestCase {
when(mUserTracker.getUserId()).thenReturn(1);
mNavBarHelper = new NavBarHelper(mContext, mAccessibilityManager,
mAccessibilityManagerWrapper, mAccessibilityButtonModeObserver,
mOverviewProxyService, mAssistManagerLazy, () -> Optional.of(mock(StatusBar.class)),
mAccessibilityButtonModeObserver, mAccessibilityButtonTargetObserver,
mSystemActions, mOverviewProxyService, mAssistManagerLazy,
() -> Optional.of(mock(StatusBar.class)),
mNavigationModeController, mUserTracker, mDumpManager);
}

View File

@@ -73,6 +73,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestableContext;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -120,6 +121,8 @@ public class NavigationBarTest extends SysuiTestCase {
private SysuiTestableContext mSysuiTestableContextExternal;
@Mock
private SystemActions mSystemActions;
@Mock
private OverviewProxyService mOverviewProxyService;
@Mock
private StatusBarStateController mStatusBarStateController;
@@ -182,8 +185,9 @@ public class NavigationBarTest extends SysuiTestCase {
mDependency.injectTestDependency(NavigationModeController.class, mNavigationModeController);
TestableLooper.get(this).runWithLooper(() -> {
mNavBarHelper = spy(new NavBarHelper(mContext, mock(AccessibilityManager.class),
mock(AccessibilityManagerWrapper.class),
mock(AccessibilityButtonModeObserver.class), mOverviewProxyService,
mock(AccessibilityButtonModeObserver.class),
mock(AccessibilityButtonTargetsObserver.class),
mSystemActions, mOverviewProxyService,
() -> mock(AssistManager.class), () -> Optional.of(mStatusBar),
mock(NavigationModeController.class), mock(UserTracker.class),
mock(DumpManager.class)));
@@ -346,7 +350,7 @@ public class NavigationBarTest extends SysuiTestCase {
NavBarHelper.NavbarTaskbarStateUpdater.class));
// Should be safe even though the internal view is now null.
mNavigationBar.updateAcessibilityStateFlags();
mNavigationBar.updateAccessibilityStateFlags();
}
private NavigationBar createNavBar(Context context) {
@@ -372,12 +376,10 @@ public class NavigationBarTest extends SysuiTestCase {
mock(ShadeController.class),
mock(NotificationRemoteInputManager.class),
mock(NotificationShadeDepthController.class),
mock(SystemActions.class),
mHandler,
mock(NavigationBarOverlayController.class),
mUiEventLogger,
mNavBarHelper,
mock(UserTracker.class),
mLightBarController,
mLightBarcontrollerFactory,
mAutoHideController,