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

Commit 264a3779 authored by Winson Chung's avatar Winson Chung
Browse files

Tweak lifecycle of nav bar/view

- Don't wait for the nav bar view to be attached to register the bar
  with the controller. This might (repro is rare) address a crash where
  the view could be created twice (with the same nav bar layer which
  is rejected by WM), because the initial bar has been created, but
  wasn't cleaned up because it wasn't attached/registered yet before
  the second request to recreate
- As as result of the above, it's possible that other code will
  reference the bar before it's attached, so the bar needs to set the
  view reference when it is created
- Also remove some deferred callbacks when detaching the view which
  could cause the callbacks to reference a null view

Bug: 188728214
Bug: 183947954
Test: atest SystemUITests with all nav modes
Change-Id: I9c05b273251c9f95cb5d693402ae53b35cc94ab5
parent 5eef4114
Loading
Loading
Loading
Loading
+53 −106
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ 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.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
@@ -200,7 +201,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    private final UiEventLogger mUiEventLogger;

    private Bundle mSavedState;
    private NavigationBarView mNavigationBarView = null;
    private NavigationBarView mNavigationBarView;

    private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;

@@ -392,7 +393,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
            };

    private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true);

    private final Runnable mEnableLayoutTransitions = () ->
            mNavigationBarView.setLayoutTransitionsEnabled(true);
    private final Runnable mOnVariableDurationHomeLongClick = () -> {
        if (onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView())) {
            mNavigationBarView.getHomeButton().getCurrentView().performHapticFeedback(
@@ -488,7 +490,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
        mA11yBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
    }

    public View getView() {
    public NavigationBarView getView() {
        return mNavigationBarView;
    }

@@ -504,16 +506,19 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
                        | WindowManager.LayoutParams.FLAG_SLIPPERY,
                PixelFormat.TRANSLUCENT);
        lp.token = new Binder();
        lp.setTitle("NavigationBar" + mContext.getDisplayId());
        lp.accessibilityTitle = mContext.getString(R.string.nav_bar);
        lp.windowAnimations = 0;
        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
        lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        lp.windowAnimations = 0;
        lp.setTitle("NavigationBar" + mContext.getDisplayId());
        lp.setFitInsetsTypes(0 /* types */);

        NavigationBarFrame frame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
                R.layout.navigation_bar_window, null);
        View barView = LayoutInflater.from(frame.getContext()).inflate(
                R.layout.navigation_bar, frame);
        barView.addOnAttachStateChangeListener(this);
        mNavigationBarView = barView.findViewById(R.id.navigation_bar_view);

        if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView);
        mContext.getSystemService(WindowManager.class).addView(frame, lp);
@@ -533,21 +538,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
        mContentResolver.registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
                false, mAssistContentObserver, UserHandle.USER_ALL);
        updateAssistantEntrypoints();

        if (savedState != null) {
            mDisabledFlags1 = savedState.getInt(EXTRA_DISABLE_STATE, 0);
            mDisabledFlags2 = savedState.getInt(EXTRA_DISABLE2_STATE, 0);
            mAppearance = savedState.getInt(EXTRA_APPEARANCE, 0);
            mBehavior = savedState.getInt(EXTRA_BEHAVIOR, 0);
            mTransientShown = savedState.getBoolean(EXTRA_TRANSIENT_STATE, false);
        }
        mSavedState = savedState;
        mAccessibilityManagerWrapper.addCallback(mAccessibilityListener);

        // Respect the latest disabled-flags.
        mCommandQueue.recomputeDisableFlags(mDisplayId, false);

        mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
                R.bool.allow_force_nav_bar_handle_opaque);
        mForceNavBarHandleOpaque = DeviceConfig.getBoolean(
@@ -561,6 +551,19 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
        )).filter(duration -> duration != 0);
        DeviceConfig.addOnPropertiesChangedListener(
                DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);
        updateAssistantEntrypoints();

        if (savedState != null) {
            mDisabledFlags1 = savedState.getInt(EXTRA_DISABLE_STATE, 0);
            mDisabledFlags2 = savedState.getInt(EXTRA_DISABLE2_STATE, 0);
            mAppearance = savedState.getInt(EXTRA_APPEARANCE, 0);
            mBehavior = savedState.getInt(EXTRA_BEHAVIOR, 0);
            mTransientShown = savedState.getBoolean(EXTRA_TRANSIENT_STATE, false);
        }
        mSavedState = savedState;

        // Respect the latest disabled-flags.
        mCommandQueue.recomputeDisableFlags(mDisplayId, false);

        mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
        mDeviceProvisionedController.addCallback(mUserSetupListener);
@@ -587,7 +590,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    @Override
    public void onViewAttachedToWindow(View v) {
        final Display display = v.getDisplay();
        mNavigationBarView = v.findViewById(R.id.navigation_bar_view);
        mNavigationBarView.setComponents(mStatusBarLazy.get().getPanelController());
        mNavigationBarView.setDisabledFlags(mDisabledFlags1);
        mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
@@ -598,6 +600,9 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
        mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
        mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
        mNavigationBarView.setBehavior(mBehavior);

        mAccessibilityManagerWrapper.addCallback(mAccessibilityListener);

        mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
        mPipOptional.ifPresent(mNavigationBarView::registerPipExclusionBoundsChangeListener);

@@ -657,10 +662,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,

    @Override
    public void onViewDetachedFromWindow(View v) {
        if (mNavigationBarView != null) {
        mNavigationBarView.getBarTransitions().destroy();
        mNavigationBarView.getLightTransitionsController().destroy(mContext);
        }
        mOverviewProxyService.removeCallback(mOverviewProxyListener);
        mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
        if (mOrientationHandle != null) {
@@ -671,6 +674,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
                    mOrientationHandleGlobalLayoutListener);
        }
        mHandler.removeCallbacks(mAutoDim);
        mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
        mHandler.removeCallbacks(mEnableLayoutTransitions);
        mNavigationBarView = null;
        mOrientationHandle = null;
    }
@@ -682,10 +687,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
        outState.putInt(EXTRA_APPEARANCE, mAppearance);
        outState.putInt(EXTRA_BEHAVIOR, mBehavior);
        outState.putBoolean(EXTRA_TRANSIENT_STATE, mTransientShown);
        if (mNavigationBarView != null) {
        mNavigationBarView.getLightTransitionsController().saveState(outState);
    }
    }

    /**
     * Called when a non-reloading configuration change happens and we need to update.
@@ -809,15 +812,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
            // mOrientedHandle is initialized lazily
            mOrientationHandle.setVisibility(View.GONE);
        }
        if (mNavigationBarView != null) {
        mNavigationBarView.setVisibility(View.VISIBLE);
        mNavigationBarView.setOrientedHandleSamplingRegion(null);
    }
    }

    private void reconfigureHomeLongClick() {
        if (mNavigationBarView == null
                || mNavigationBarView.getHomeButton().getCurrentView() == null) {
        if (mNavigationBarView.getHomeButton().getCurrentView() == null) {
            return;
        }
        if (mHomeButtonLongPressDurationMs.isPresent() || !mLongPressHomeEnabled) {
@@ -844,17 +844,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
        pw.println("  mHomeButtonLongPressDurationMs=" + mHomeButtonLongPressDurationMs);
        pw.println("  mLongPressHomeEnabled=" + mLongPressHomeEnabled);
        pw.println("  mAssistantTouchGestureEnabled=" + mAssistantTouchGestureEnabled);

        if (mNavigationBarView != null) {
        pw.println("  mNavigationBarWindowState="
                + windowStateToString(mNavigationBarWindowState));
        pw.println("  mNavigationBarMode="
                + BarTransitions.modeToString(mNavigationBarMode));
        dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
        mNavigationBarView.dump(pw);
        } else {
            pw.print("  mNavigationBarView=null");
        }
    }

    // ----- CommandQueue Callbacks -----
@@ -889,10 +884,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
        if (hints == mNavigationIconHints) return;

        mNavigationIconHints = hints;

        if (mNavigationBarView != null) {
        mNavigationBarView.setNavigationIconHints(hints);
        }
        checkBarModes();
        updateSystemUiStateFlags(-1);
    }
@@ -911,23 +903,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
                orientSecondaryHomeHandle();
            }
            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));

            if (mNavigationBarView != null) {
            mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
        }
    }
    }

    @Override
    public void onRotationProposal(final int rotation, boolean isValid) {
        if (mNavigationBarView == null) {
            if (RotationContextButton.DEBUG_ROTATION) {
                Log.v(TAG, "onRotationProposal proposedRotation=" +
                        Surface.rotationToString(rotation) + ", mNavigationBarView is null");
            }
            return;
        }

        final int winRotation = mNavigationBarView.getDisplay().getRotation();
        final boolean rotateSuggestionsDisabled = RotationButtonController
                .hasDisable2RotateSuggestionFlag(mDisabledFlags2);
@@ -941,8 +922,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
                    + ", isValid=" + isValid + ", mNavBarWindowState="
                    + StatusBarManager.windowStateToString(mNavigationBarWindowState)
                    + ", rotateSuggestionsDisabled=" + rotateSuggestionsDisabled
                    + ", isRotateButtonVisible=" + (mNavigationBarView == null ? "null"
                    : rotationButton.isVisible()));
                    + ", isRotateButtonVisible=" + rotationButton.isVisible());
        }

        // Respect the disabled flag, no need for action as flag change callback will handle hiding
@@ -983,9 +963,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
        boolean nbModeChanged = false;
        if (mAppearance != appearance) {
            mAppearance = appearance;
            if (getView() == null) {
                return;
            }
            nbModeChanged = updateBarMode(barMode(mTransientShown, appearance));
        }
        if (mLightBarController != null) {
@@ -994,9 +971,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
        }
        if (mBehavior != behavior) {
            mBehavior = behavior;
            if (mNavigationBarView != null) {
            mNavigationBarView.setBehavior(behavior);
            }
            updateSystemUiStateFlags(-1);
        }
    }
@@ -1034,12 +1009,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    }

    private void handleTransientChanged() {
        if (getView() == null) {
            return;
        }
        if (mNavigationBarView != null) {
        mNavigationBarView.onTransientStateChanged(mTransientShown);
        }
        final int barMode = barMode(mTransientShown, mAppearance);
        if (updateBarMode(barMode) && mLightBarController != null) {
            mLightBarController.onNavigationBarModeChanged(barMode);
@@ -1092,9 +1062,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
                | StatusBarManager.DISABLE_SEARCH);
        if (masked != mDisabledFlags1) {
            mDisabledFlags1 = masked;
            if (mNavigationBarView != null) {
            mNavigationBarView.setDisabledFlags(state1);
            }
            updateScreenPinningGestures();
        }

@@ -1110,18 +1078,14 @@ public class NavigationBar implements View.OnAttachStateChangeListener,

    private void setDisabled2Flags(int state2) {
        // Method only called on change of disable2 flags
        if (mNavigationBarView != null) {
        mNavigationBarView.getRotationButtonController().onDisable2FlagChanged(state2);
    }
    }

    // ----- Internal stuff -----

    private void refreshLayout(int layoutDirection) {
        if (mNavigationBarView != null) {
        mNavigationBarView.setLayoutDirection(layoutDirection);
    }
    }

    private boolean shouldDisableNavbarGestures() {
        return !mDeviceProvisionedController.isDeviceProvisioned()
@@ -1129,7 +1093,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    }

    private void repositionNavigationBar() {
        if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
        if (!mNavigationBarView.isAttachedToWindow()) return;

        prepareNavigationBarView();

@@ -1138,10 +1102,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    }

    private void updateScreenPinningGestures() {
        if (mNavigationBarView == null) {
            return;
        }

        // Change the cancel pin gesture to home and back if recents button is invisible
        boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
        ButtonDispatcher backButton = mNavigationBarView.getBackButton();
@@ -1252,10 +1212,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
                AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
        mAssistManagerLazy.get().startAssist(args);
        mStatusBarLazy.get().awakenDreams();

        if (mNavigationBarView != null) {
        mNavigationBarView.abortCurrentGesture();
        }
        return true;
    }

@@ -1405,9 +1362,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    }

    void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
        if (mNavigationBarView == null) {
            return;
        }
        boolean[] feedbackEnabled = new boolean[1];
        int a11yFlags = getA11yButtonState(feedbackEnabled);

@@ -1593,7 +1547,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,

    public void disableAnimationsDuringHide(long delay) {
        mNavigationBarView.setLayoutTransitionsEnabled(false);
        mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
        mHandler.postDelayed(mEnableLayoutTransitions,
                delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
    }

@@ -1608,11 +1562,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    }

    public NavigationBarTransitions getBarTransitions() {
        if (mNavigationBarView != null) {
        return mNavigationBarView.getBarTransitions();
    }
        return null;
    }

    public void finishBarAnimations() {
        mNavigationBarView.getBarTransitions().finishAnimations();
@@ -1626,8 +1577,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    }

    private final Consumer<Integer> mRotationWatcher = rotation -> {
        if (mNavigationBarView != null
                && mNavigationBarView.needsReorient(rotation)) {
        if (mNavigationBarView.needsReorient(rotation)) {
            repositionNavigationBar();
        }
    };
@@ -1635,9 +1585,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (mNavigationBarView == null) {
                return;
            }
            String action = intent.getAction();
            if (Intent.ACTION_SCREEN_OFF.equals(action)
                    || Intent.ACTION_SCREEN_ON.equals(action)) {
+3 −7
Original line number Diff line number Diff line
@@ -225,10 +225,7 @@ public class NavigationBarController implements Callbacks,
                if (navBar == null) {
                    continue;
                }
                NavigationBarView view = (NavigationBarView) navBar.getView();
                if (view != null) {
                    view.updateStates();
                }
                navBar.getView().updateStates();
            }
        });
    }
@@ -366,13 +363,12 @@ public class NavigationBarController implements Callbacks,
                mHandler,
                mNavBarOverlayController,
                mUiEventLogger);
        mNavigationBars.put(displayId, navBar);

        View navigationBarView = navBar.createView(savedState);
        navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
            @Override
            public void onViewAttachedToWindow(View v) {
                mNavigationBars.put(displayId, navBar);

                if (result != null) {
                    navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken,
                            result.mImeWindowVis, result.mImeBackDisposition,
@@ -448,7 +444,7 @@ public class NavigationBarController implements Callbacks,
     */
    public @Nullable NavigationBarView getNavigationBarView(int displayId) {
        NavigationBar navBar = mNavigationBars.get(displayId);
        return (navBar == null) ? null : (NavigationBarView) navBar.getView();
        return (navBar == null) ? null : navBar.getView();
    }

    /** @return {@link NavigationBar} on the default display. */
+0 −2
Original line number Diff line number Diff line
@@ -40,7 +40,6 @@ public class ButtonDispatcher {
    private final ArrayList<View> mViews = new ArrayList<>();

    private final int mId;
    private final AssistManager mAssistManager;

    private View.OnClickListener mClickListener;
    private View.OnTouchListener mTouchListener;
@@ -73,7 +72,6 @@ public class ButtonDispatcher {

    public ButtonDispatcher(int id) {
        mId = id;
        mAssistManager = Dependency.get(AssistManager.class);
    }

    public void clear() {