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

Commit fce2e99c authored by Yunfan Chen's avatar Yunfan Chen
Browse files

Layout status/nav bar and decor window as normal window

Use the general layout process for system bar windows. The hard-coded
logic of the bar position is also disabled by the patch. Such that, the
system UI will have the ability to layout the window freely.

The bars sometimes need to be layout with new rotation before the actual
rotation when we simulate the display with fixed layout. To support
that, new layout params for orientation is introduced to the layout params.

The bar may need to provide a different insets frame in gesture
navigation mode. That is for the IME to draw the hide button. Introduced
a new param called providedInternalInsets to resolve that usage.

The new flexible layout is protected by the flag
persist.debug.flexible_insets.

Bug: 161689946
Bug: 169329927
Test: DisplayPolicyTests InsetsSourceProviderTest
      InsetsStateControllerTest
Change-Id: If8ec79b3cb3b989eed578c44e8749b13fd2e8592
parent 123e88c5
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -284,6 +284,21 @@ public final class ViewRootImpl implements ViewParent,
     */
    private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500;

    /**
     * If set to {@code true}, the new logic to layout system bars as normal window and to use
     * layout result to get insets will be applied. Otherwise, the old hard-coded window logic will
     * be applied.
     */
    private static final String USE_FLEXIBLE_INSETS = "persist.debug.flexible_insets";

    /**
     * A flag to indicate to use the new generalized insets window logic, or the old hard-coded
     * insets window layout logic.
     * {@hide}
     */
    public static final boolean INSETS_LAYOUT_GENERALIZATION =
            SystemProperties.getBoolean(USE_FLEXIBLE_INSETS, false);

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();

+66 −0
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ import android.content.ClipData;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -3454,6 +3455,22 @@ public interface WindowManager extends ViewManager {
         */
        public @InsetsState.InternalInsetsType int[] providesInsetsTypes;

        /**
         * If specified, the insets provided by this window will be our window frame minus the
         * insets specified by providedInternalInsets.
         *
         * @hide
         */
        public Insets providedInternalInsets = Insets.NONE;

        /**
         * {@link LayoutParams} to be applied to the window when layout with a assigned rotation.
         * This will make layout during rotation change smoothly.
         *
         * @hide
         */
        public LayoutParams[] paramsForRotation;

        /**
         * Specifies types of insets that this window should avoid overlapping during layout.
         *
@@ -3553,6 +3570,18 @@ public interface WindowManager extends ViewManager {
            return mFitInsetsIgnoringVisibility;
        }

        private void checkNonRecursiveParams() {
            if (paramsForRotation == null) {
                return;
            }
            for (int i = paramsForRotation.length - 1; i >= 0; i--) {
                if (paramsForRotation[i].paramsForRotation != null) {
                    throw new IllegalArgumentException(
                            "Params cannot contain params recursively.");
                }
            }
        }

        public LayoutParams() {
            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            type = TYPE_APPLICATION;
@@ -3805,6 +3834,14 @@ public interface WindowManager extends ViewManager {
            } else {
                out.writeInt(0);
            }
            providedInternalInsets.writeToParcel(out, 0 /* parcelableFlags */);
            if (paramsForRotation != null) {
                checkNonRecursiveParams();
                out.writeInt(paramsForRotation.length);
                out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
            } else {
                out.writeInt(0);
            }
        }

        public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -3874,6 +3911,12 @@ public interface WindowManager extends ViewManager {
                providesInsetsTypes = new int[insetsTypesLength];
                in.readIntArray(providesInsetsTypes);
            }
            providedInternalInsets = Insets.CREATOR.createFromParcel(in);
            int paramsForRotationLength = in.readInt();
            if (paramsForRotationLength > 0) {
                paramsForRotation = new LayoutParams[paramsForRotationLength];
                in.readTypedArray(paramsForRotation, LayoutParams.CREATOR);
            }
        }

        @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -4156,6 +4199,17 @@ public interface WindowManager extends ViewManager {
                changes |= LAYOUT_CHANGED;
            }

            if (!providedInternalInsets.equals(o.providedInternalInsets)) {
                providedInternalInsets = o.providedInternalInsets;
                changes |= LAYOUT_CHANGED;
            }

            if (!Arrays.equals(paramsForRotation, o.paramsForRotation)) {
                paramsForRotation = o.paramsForRotation;
                checkNonRecursiveParams();
                changes |= LAYOUT_CHANGED;
            }

            return changes;
        }

@@ -4343,6 +4397,18 @@ public interface WindowManager extends ViewManager {
                    sb.append(InsetsState.typeToString(providesInsetsTypes[i]));
                }
            }
            if (!providedInternalInsets.equals(Insets.NONE)) {
                sb.append(" providedInternalInsets=");
                sb.append(providedInternalInsets);
            }
            if (paramsForRotation != null && paramsForRotation.length != 0) {
                sb.append(System.lineSeparator());
                sb.append(prefix).append("  paramsForRotation=");
                for (int i = 0; i < paramsForRotation.length; ++i) {
                    if (i > 0) sb.append(' ');
                    sb.append(paramsForRotation[i].toString());
                }
            }

            sb.append('}');
            return sb.toString();
+99 −31
Original line number Diff line number Diff line
@@ -23,10 +23,12 @@ import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.WindowType;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.containsType;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
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;
@@ -67,6 +69,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -199,6 +202,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,

    private Bundle mSavedState;
    private NavigationBarView mNavigationBarView;
    private NavigationBarFrame mFrame;

    private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;

@@ -489,34 +493,17 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    }

    public View createView(Bundle savedState) {
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                        | WindowManager.LayoutParams.FLAG_SLIPPERY,
                PixelFormat.TRANSLUCENT);
        lp.token = new Binder();
        lp.accessibilityTitle = mContext.getString(R.string.nav_bar);
        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 */);
        lp.setTrustedOverlay();

        NavigationBarFrame frame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
        mFrame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
                R.layout.navigation_bar_window, null);
        View barView = LayoutInflater.from(frame.getContext()).inflate(
                R.layout.navigation_bar, frame);
        View barView = LayoutInflater.from(mFrame.getContext()).inflate(
                R.layout.navigation_bar, mFrame);
        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);
        mContext.getSystemService(WindowManager.class).addView(mFrame,
                getBarLayoutParams(mContext.getResources().getConfiguration().windowConfiguration
                        .getRotation()));
        mDisplayId = mContext.getDisplayId();
        mIsOnDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;

@@ -670,6 +657,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
        mHandler.removeCallbacks(mAutoDim);
        mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
        mHandler.removeCallbacks(mEnableLayoutTransitions);
        mFrame = null;
        mNavigationBarView = null;
        mOrientationHandle = null;
    }
@@ -688,6 +676,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
     * Called when a non-reloading configuration change happens and we need to update.
     */
    public void onConfigurationChanged(Configuration newConfig) {
        final int rotation = newConfig.windowConfiguration.getRotation();
        final Locale locale = mContext.getResources().getConfiguration().locale;
        final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
        if (!locale.equals(mLocale) || ld != mLayoutDirection) {
@@ -701,9 +690,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
            refreshLayout(ld);
        }

        repositionNavigationBar();
        repositionNavigationBar(rotation);
        if (canShowSecondaryHandle()) {
            int rotation = newConfig.windowConfiguration.getRotation();
            if (rotation != mCurrentRotation) {
                mCurrentRotation = rotation;
                orientSecondaryHomeHandle();
@@ -1068,13 +1056,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
                || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0;
    }

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

        prepareNavigationBarView();

        mWindowManager.updateViewLayout((View) mNavigationBarView.getParent(),
                ((View) mNavigationBarView.getParent()).getLayoutParams());
        mWindowManager.updateViewLayout(mFrame, getBarLayoutParams(rotation));
    }

    private void updateScreenPinningGestures() {
@@ -1509,13 +1496,94 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
    private final NavigationBarA11yHelper.NavA11yEventListener mAccessibilityListener =
            this::updateAccessibilityServicesState;

    private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
        WindowManager.LayoutParams lp = getBarLayoutParamsForRotation(rotation);
        lp.paramsForRotation = new WindowManager.LayoutParams[4];
        for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
            lp.paramsForRotation[rot] = getBarLayoutParamsForRotation(rot);
        }
        return lp;
    }

    private WindowManager.LayoutParams getBarLayoutParamsForRotation(int rotation) {
        int width = WindowManager.LayoutParams.MATCH_PARENT;
        int height = WindowManager.LayoutParams.MATCH_PARENT;
        int insetsHeight = -1;
        int gravity = Gravity.BOTTOM;
        if (INSETS_LAYOUT_GENERALIZATION) {
            boolean navBarCanMove = true;
            if (mWindowManager != null && mWindowManager.getCurrentWindowMetrics() != null) {
                Rect displaySize = mWindowManager.getCurrentWindowMetrics().getBounds();
                navBarCanMove = displaySize.width() != displaySize.height()
                        && mContext.getResources().getBoolean(
                        com.android.internal.R.bool.config_navBarCanMove);
            }
            if (!navBarCanMove) {
                height = mContext.getResources().getDimensionPixelSize(
                        com.android.internal.R.dimen.navigation_bar_frame_height);
                insetsHeight = mContext.getResources().getDimensionPixelSize(
                        com.android.internal.R.dimen.navigation_bar_height);
            } else {
                switch (rotation) {
                    case ROTATION_UNDEFINED:
                    case Surface.ROTATION_0:
                    case Surface.ROTATION_180:
                        height = mContext.getResources().getDimensionPixelSize(
                                com.android.internal.R.dimen.navigation_bar_frame_height);
                        insetsHeight = mContext.getResources().getDimensionPixelSize(
                                com.android.internal.R.dimen.navigation_bar_height);
                        break;
                    case Surface.ROTATION_90:
                        gravity = Gravity.RIGHT;
                        width = mContext.getResources().getDimensionPixelSize(
                                com.android.internal.R.dimen.navigation_bar_width);
                        break;
                    case Surface.ROTATION_270:
                        gravity = Gravity.LEFT;
                        width = mContext.getResources().getDimensionPixelSize(
                                com.android.internal.R.dimen.navigation_bar_width);
                        break;
                }
            }
        }
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                width,
                height,
                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                        | WindowManager.LayoutParams.FLAG_SLIPPERY,
                PixelFormat.TRANSLUCENT);
        if (INSETS_LAYOUT_GENERALIZATION) {
            lp.gravity = gravity;
            if (insetsHeight != -1) {
                lp.providedInternalInsets = Insets.of(0, height - insetsHeight, 0, 0);
            } else {
                lp.providedInternalInsets = Insets.NONE;
            }
        }
        lp.token = new Binder();
        lp.accessibilityTitle = mContext.getString(R.string.nav_bar);
        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 */);
        lp.setTrustedOverlay();
        return lp;
    }

    private boolean canShowSecondaryHandle() {
        return mNavBarMode == NAV_BAR_MODE_GESTURAL && mOrientationHandle != null;
    }

    private final Consumer<Integer> mRotationWatcher = rotation -> {
        if (mNavigationBarView.needsReorient(rotation)) {
            repositionNavigationBar();
        if (mNavigationBarView != null
                && mNavigationBarView.needsReorient(rotation)) {
            repositionNavigationBar(rotation);
        }
    };

+61 −15
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.statusbar.phone;

import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
@@ -34,6 +36,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.Gravity;
import android.view.IWindowManager;
import android.view.Surface;
import android.view.ViewGroup;
import android.view.WindowManager;

@@ -118,21 +121,7 @@ public class StatusBarWindowController {
        // Now that the status bar window encompasses the sliding panel and its
        // translucent backdrop, the entire thing is made TRANSLUCENT and is
        // hardware-accelerated.
        mLp = new WindowManager.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                mBarHeight,
                WindowManager.LayoutParams.TYPE_STATUS_BAR,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                PixelFormat.TRANSLUCENT);
        mLp.privateFlags |= PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
        mLp.token = new Binder();
        mLp.gravity = Gravity.TOP;
        mLp.setFitInsetsTypes(0 /* types */);
        mLp.setTitle("StatusBar");
        mLp.packageName = mContext.getPackageName();
        mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        mLp = getBarLayoutParams(mContext.getDisplay().getRotation());

        mWindowManager.addView(mStatusBarView, mLp);
        mLpChanged.copyFrom(mLp);
@@ -141,6 +130,63 @@ public class StatusBarWindowController {
        calculateStatusBarLocationsForAllRotations();
    }

    private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
        WindowManager.LayoutParams lp = getBarLayoutParamsForRotation(rotation);
        lp.paramsForRotation = new WindowManager.LayoutParams[4];
        for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
            lp.paramsForRotation[rot] = getBarLayoutParamsForRotation(rot);
        }
        return lp;
    }

    private WindowManager.LayoutParams getBarLayoutParamsForRotation(int rotation) {
        int height = mBarHeight;
        if (INSETS_LAYOUT_GENERALIZATION) {
            Rect displayBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
            int defaultAndUpsideDownHeight;
            int theOtherHeight;
            if (displayBounds.width() > displayBounds.height()) {
                defaultAndUpsideDownHeight = mContext.getResources().getDimensionPixelSize(
                        com.android.internal.R.dimen.status_bar_height_landscape);
                theOtherHeight = mContext.getResources().getDimensionPixelSize(
                        com.android.internal.R.dimen.status_bar_height_portrait);
            } else {
                defaultAndUpsideDownHeight = mContext.getResources().getDimensionPixelSize(
                        com.android.internal.R.dimen.status_bar_height_portrait);
                theOtherHeight = mContext.getResources().getDimensionPixelSize(
                        com.android.internal.R.dimen.status_bar_height_landscape);
            }
            switch (rotation) {
                case ROTATION_UNDEFINED:
                case Surface.ROTATION_0:
                case Surface.ROTATION_180:
                    height = defaultAndUpsideDownHeight;
                    break;
                case Surface.ROTATION_90:
                case Surface.ROTATION_270:
                    height = theOtherHeight;
                    break;
            }
        }
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,
                height,
                WindowManager.LayoutParams.TYPE_STATUS_BAR,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                PixelFormat.TRANSLUCENT);
        lp.privateFlags |= PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
        lp.token = new Binder();
        lp.gravity = Gravity.TOP;
        lp.setFitInsetsTypes(0 /* types */);
        lp.setTitle("StatusBar");
        lp.packageName = mContext.getPackageName();
        lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        return lp;

    }

    private void calculateStatusBarLocationsForAllRotations() {
        Rect[] bounds = new Rect[4];
        bounds[0] = mContentInsetsProvider
+206 −49

File changed.

Preview size limit exceeded, changes collapsed.

Loading