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

Commit 42ea6883 authored by Winson Chung's avatar Winson Chung
Browse files

1/ Initialize assistant state change listeners once with the nav bar helper

- Consolidate the meaning of init/destroy into the
  registration/unregistration of the nav bar helper state callbacks.
  This allows us to track the case where we are replacing the bars
  to prevent churn in unregistering and reregistering shared callbacks
- Using the above, we can only register the assistant content observers
  when the first bar is registered, and keep it registered across
  bar replacements

Bug: 219035565
Test: atest NavBarHelperTests
Test: atest SystemUITests

Change-Id: I2444bb0b27086b72212ef05b8c975c19a05a35d5
parent 749de2e1
Loading
Loading
Loading
Loading
+58 −22
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ public final class NavBarHelper implements
        AccessibilityButtonTargetsObserver.TargetsChangedListener,
        OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
        Dumpable, CommandQueue.Callbacks {
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final AccessibilityManager mAccessibilityManager;
    private final Lazy<AssistManager> mAssistManagerLazy;
    private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
@@ -98,7 +99,7 @@ public final class NavBarHelper implements
    private final SystemActions mSystemActions;
    private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
    private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
    private final List<NavbarTaskbarStateUpdater> mA11yEventListeners = new ArrayList<>();
    private final List<NavbarTaskbarStateUpdater> mStateListeners = new ArrayList<>();
    private final Context mContext;
    private final CommandQueue mCommandQueue;
    private final ContentResolver mContentResolver;
@@ -107,13 +108,14 @@ public final class NavBarHelper implements
    private boolean mAssistantTouchGestureEnabled;
    private int mNavBarMode;
    private int mA11yButtonState;
    private boolean mTogglingNavbarTaskbar;

    // Attributes used in NavBarHelper.CurrentSysuiState
    private int mWindowStateDisplayId;
    private @WindowVisibleState int mWindowState;

    private final ContentObserver mAssistContentObserver = new ContentObserver(
            new Handler(Looper.getMainLooper())) {
    // Listens for changes to the assistant
    private final ContentObserver mAssistContentObserver = new ContentObserver(mHandler) {
        @Override
        public void onChange(boolean selfChange, Uri uri) {
            updateAssistantAvailability();
@@ -147,18 +149,33 @@ public final class NavBarHelper implements
        mKeyguardStateController = keyguardStateController;
        mUserTracker = userTracker;
        mSystemActions = systemActions;
        accessibilityManager.addAccessibilityServicesStateChangeListener(this);
        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
        mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;

        mAccessibilityButtonModeObserver.addListener(this);
        mAccessibilityButtonTargetsObserver.addListener(this);
        mNavBarMode = navigationModeController.addListener(this);
        mCommandQueue.addCallback(this);
        overviewProxyService.addCallback(this);
        dumpManager.registerDumpable(this);
    }

    public void init() {
    /**
     * Hints to the helper that bars are being replaced, which is a signal to potentially suppress
     * normal setup/cleanup when no bars are present.
     */
    public void setTogglingNavbarTaskbar(boolean togglingNavbarTaskbar) {
        mTogglingNavbarTaskbar = togglingNavbarTaskbar;
    }

    /**
     * Called when the first (non-replacing) bar is registered.
     */
    private void setupOnFirstBar() {
        // Setup accessibility listeners
        mAccessibilityManager.addAccessibilityServicesStateChangeListener(this);
        mAccessibilityButtonModeObserver.addListener(this);
        mAccessibilityButtonTargetsObserver.addListener(this);

        // Setup assistant listener
        mContentResolver.registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
                false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);
@@ -168,59 +185,76 @@ public final class NavBarHelper implements
        mContentResolver.registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
                false, mAssistContentObserver, UserHandle.USER_ALL);
        updateAssistantAvailability();
        updateA11yState();
        mCommandQueue.addCallback(this);

    }

    public void destroy() {
    /**
     * Called after the last (non-replacing) bar is unregistered.
     */
    private void cleanupAfterLastBar() {
        // Clean up accessibility listeners
        mAccessibilityManager.removeAccessibilityServicesStateChangeListener(this);
        mAccessibilityButtonModeObserver.removeListener(this);
        mAccessibilityButtonTargetsObserver.removeListener(this);

        // Clean up assistant listeners
        mContentResolver.unregisterContentObserver(mAssistContentObserver);
        mCommandQueue.removeCallback(this);
    }

    /**
     * Registers a listener for future updates to the shared navbar/taskbar state.
     * @param listener Will immediately get callbacks based on current state
     */
    public void registerNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) {
        mA11yEventListeners.add(listener);
        mStateListeners.add(listener);
        if (!mTogglingNavbarTaskbar && mStateListeners.size() == 1) {
            setupOnFirstBar();

            // Update the state once the first bar is registered
            updateAssistantAvailability();
            updateA11yState();
            mCommandQueue.recomputeDisableFlags(mContext.getDisplayId(), false /* animate */);
        } else {
            listener.updateAccessibilityServicesState();
            listener.updateAssistantAvailable(mAssistantAvailable, mLongPressHomeEnabled);
        }
    }

    /**
     * Removes a previously registered listener.
     */
    public void removeNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) {
        mA11yEventListeners.remove(listener);
        mStateListeners.remove(listener);
        if (!mTogglingNavbarTaskbar && mStateListeners.isEmpty()) {
            cleanupAfterLastBar();
        }
    }

    private void dispatchA11yEventUpdate() {
        for (NavbarTaskbarStateUpdater listener : mA11yEventListeners) {
        for (NavbarTaskbarStateUpdater listener : mStateListeners) {
            listener.updateAccessibilityServicesState();
        }
    }

    private void dispatchAssistantEventUpdate(boolean assistantAvailable,
            boolean longPressHomeEnabled) {
        for (NavbarTaskbarStateUpdater listener : mA11yEventListeners) {
        for (NavbarTaskbarStateUpdater listener : mStateListeners) {
            listener.updateAssistantAvailable(assistantAvailable, longPressHomeEnabled);
        }
    }

    @Override
    public void onAccessibilityServicesStateChanged(AccessibilityManager manager) {
        dispatchA11yEventUpdate();
        updateA11yState();
    }

    @Override
    public void onAccessibilityButtonModeChanged(int mode) {
        updateA11yState();
        dispatchA11yEventUpdate();
    }

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

    /**
@@ -262,6 +296,8 @@ public final class NavBarHelper implements
            updateSystemAction(clickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON);
            updateSystemAction(longClickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER);
        }

        dispatchA11yEventUpdate();
    }

    /**
+4 −5
Original line number Diff line number Diff line
@@ -677,13 +677,14 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
        // start firing, since the latter is source of truth
        parseCurrentSysuiState();
        mCommandQueue.addCallback(this);
        mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
        mNavBarHelper.init();
        mHomeButtonLongPressDurationMs = Optional.of(mDeviceConfigProxy.getLong(
                DeviceConfig.NAMESPACE_SYSTEMUI,
                HOME_BUTTON_LONG_PRESS_DURATION_MS,
                /* defaultValue = */ 0
        )).filter(duration -> duration != 0);
        // This currently MUST be called after mHomeButtonLongPressDurationMs is initialized since
        // the registration callbacks will trigger code that uses it
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        mDeviceConfigProxy.addOnPropertiesChangedListener(
                DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);

@@ -709,7 +710,6 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
        mNavigationModeController.removeListener(mModeChangedListener);

        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        mNavBarHelper.destroy();
        mNotificationShadeDepthController.removeListener(mDepthListener);

        mDeviceConfigProxy.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
@@ -746,8 +746,6 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
        mView.getViewRootImpl().addSurfaceChangedCallback(mSurfaceChangedCallback);
        notifyNavigationBarSurface();

        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);

        mPipOptional.ifPresent(mView::addPipExclusionBoundsChangeListener);
        mBackAnimation.ifPresent(mView::registerBackAnimation);

@@ -1487,6 +1485,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
    }

    void updateAccessibilityStateFlags() {
        mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
        if (mView != null) {
            int a11yFlags = mNavBarHelper.getA11yButtonState();
            boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
+9 −2
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ public class NavigationBarController implements
    private final DisplayTracker mDisplayTracker;
    private final DisplayManager mDisplayManager;
    private final TaskbarDelegate mTaskbarDelegate;
    private final NavBarHelper mNavBarHelper;
    private int mNavMode;
    @VisibleForTesting boolean mIsLargeScreen;

@@ -133,6 +134,7 @@ public class NavigationBarController implements
        configurationController.addCallback(this);
        mConfigChanges.applyNewConfig(mContext.getResources());
        mNavMode = navigationModeController.addListener(this);
        mNavBarHelper = navBarHelper;
        mTaskbarDelegate = taskbarDelegate;
        mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService,
                navBarHelper, navigationModeController, sysUiFlagsContainer,
@@ -241,10 +243,15 @@ public class NavigationBarController implements

        if (taskbarEnabled) {
            Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary");
            final int displayId = mContext.getDisplayId();
            // Hint to NavBarHelper if we are replacing an existing bar to skip extra work
            mNavBarHelper.setTogglingNavbarTaskbar(mNavigationBars.contains(displayId));
            // Remove navigation bar when taskbar is showing
            removeNavigationBar(mContext.getDisplayId());
            mTaskbarDelegate.init(mContext.getDisplayId());
            removeNavigationBar(displayId);
            mTaskbarDelegate.init(displayId);
            mNavBarHelper.setTogglingNavbarTaskbar(false);
            Trace.endSection();

        } else {
            mTaskbarDelegate.destroy();
        }
+0 −2
Original line number Diff line number Diff line
@@ -239,7 +239,6 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
        mOverviewProxyService.addCallback(this);
        onNavigationModeChanged(mNavigationModeController.addListener(this));
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        mNavBarHelper.init();
        mEdgeBackGestureHandler.onNavBarAttached();
        // Initialize component callback
        Display display = mDisplayManager.getDisplay(displayId);
@@ -264,7 +263,6 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
        mOverviewProxyService.removeCallback(this);
        mNavigationModeController.removeListener(this);
        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        mNavBarHelper.destroy();
        mEdgeBackGestureHandler.onNavBarDetached();
        mScreenPinningNotify = null;
        mWindowContext = null;
+36 −17
Original line number Diff line number Diff line
@@ -128,20 +128,49 @@ public class NavBarHelperTest extends SysuiTestCase {

    @Test
    public void registerListenersInCtor() {
        verify(mAccessibilityButtonModeObserver, times(1)).addListener(mNavBarHelper);
        verify(mNavigationModeController, times(1)).addListener(mNavBarHelper);
        verify(mOverviewProxyService, times(1)).addCallback(mNavBarHelper);
        verify(mCommandQueue, times(1)).addCallback(any());
    }

    @Test
    public void registerAccessibilityContentObserver() {
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        verify(mAccessibilityButtonModeObserver, times(1)).addListener(mNavBarHelper);
        verify(mAccessibilityButtonTargetObserver, times(1)).addListener(mNavBarHelper);
        verify(mAccessibilityManager, times(1)).addAccessibilityServicesStateChangeListener(
                mNavBarHelper);
    }

    @Test
    public void unregisterAccessibilityContentObserver() {
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        verify(mAccessibilityButtonModeObserver, times(1)).removeListener(mNavBarHelper);
        verify(mAccessibilityButtonTargetObserver, times(1)).removeListener(mNavBarHelper);
        verify(mAccessibilityManager, times(1)).removeAccessibilityServicesStateChangeListener(
                mNavBarHelper);
    }

    @Test
    public void registerAssistantContentObserver() {
        mNavBarHelper.init();
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        verify(mAssistManager, times(1)).getAssistInfoForUser(anyInt());
    }

    @Test
    public void replacingBarsHint() {
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        mNavBarHelper.setTogglingNavbarTaskbar(true);
        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        mNavBarHelper.setTogglingNavbarTaskbar(false);
        // Use any state in cleanup to verify it was not called
        verify(mAccessibilityButtonModeObserver, times(0)).removeListener(mNavBarHelper);
    }

    @Test
    public void callbacksFiredWhenRegistering() {
        mNavBarHelper.init();
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        verify(mNavbarTaskbarStateUpdater, times(1))
                .updateAccessibilityServicesState();
@@ -151,7 +180,6 @@ public class NavBarHelperTest extends SysuiTestCase {

    @Test
    public void assistantCallbacksFiredAfterConnecting() {
        mNavBarHelper.init();
        // 1st set of callbacks get called when registering
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);

@@ -172,7 +200,6 @@ public class NavBarHelperTest extends SysuiTestCase {

    @Test
    public void a11yCallbacksFiredAfterModeChange() {
        mNavBarHelper.init();
        // 1st set of callbacks get called when registering
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);

@@ -185,7 +212,6 @@ public class NavBarHelperTest extends SysuiTestCase {

    @Test
    public void assistantCallbacksFiredAfterNavModeChange() {
        mNavBarHelper.init();
        // 1st set of callbacks get called when registering
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);

@@ -198,7 +224,6 @@ public class NavBarHelperTest extends SysuiTestCase {

    @Test
    public void removeListenerNoCallbacksFired() {
        mNavBarHelper.init();
        // 1st set of callbacks get called when registering
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);

@@ -220,7 +245,7 @@ public class NavBarHelperTest extends SysuiTestCase {
        when(mAccessibilityManager.getAccessibilityShortcutTargets(
                AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(createFakeShortcutTargets());

        mNavBarHelper.init();
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);

        assertThat(mNavBarHelper.getA11yButtonState()).isEqualTo(
                ACCESSIBILITY_BUTTON_CLICKABLE_STATE);
@@ -230,13 +255,15 @@ public class NavBarHelperTest extends SysuiTestCase {
    public void initAccessibilityStateWithFloatingMenuModeAndTargets_disableClickableState() {
        when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
                ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
        mNavBarHelper.init();

        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);

        assertThat(mNavBarHelper.getA11yButtonState()).isEqualTo(/* disable_clickable_state */ 0);
    }

    @Test
    public void onA11yServicesStateChangedWithMultipleServices_a11yButtonClickableState() {
        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
        when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
                ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);

@@ -249,15 +276,8 @@ public class NavBarHelperTest extends SysuiTestCase {
                ACCESSIBILITY_BUTTON_CLICKABLE_STATE);
    }

    @Test
    public void registerCommandQueueCallbacks() {
        mNavBarHelper.init();
        verify(mCommandQueue, times(1)).addCallback(any());
    }

    @Test
    public void saveMostRecentSysuiState() {
        mNavBarHelper.init();
        mNavBarHelper.setWindowState(DISPLAY_ID, WINDOW, STATE_ID);
        NavBarHelper.CurrentSysuiState state1 = mNavBarHelper.getCurrentSysuiState();

@@ -274,7 +294,6 @@ public class NavBarHelperTest extends SysuiTestCase {

    @Test
    public void ignoreNonNavbarSysuiState() {
        mNavBarHelper.init();
        mNavBarHelper.setWindowState(DISPLAY_ID, WINDOW, STATE_ID);
        NavBarHelper.CurrentSysuiState state1 = mNavBarHelper.getCurrentSysuiState();