Android 12系统源码_SystemUI(七)DisplayPolicy构建状态栏和导航栏视图窗口区域坐标

前言

NavigationBar 和 StatusBar 都属于 SystemBar,也叫做 decor,就是说给 App 装饰的意思。在Android12中,一般的window的是在 DisplayPolicy的layoutWindowLw方法中布局的,而导航栏和状态栏分别是在DisplayPolicy的layoutNavigationBar和layoutStatusBar方法中布局的。

一、简单认识Android12中的DisplayFrames

mDisplayId 是跟物理屏幕相关的,DEFAULT_DISPLAY 的值是 0,mDisplayWidth 是物理屏幕宽度,mDisplayHeight 是物理屏幕高度。

public class DisplayFrames {
    
    
    public final int mDisplayId;

    public final InsetsState mInsetsState;

    /**
     * The current visible size of the screen; really; (ir)regardless of whether the status bar can
     * be hidden but not extending into the overscan area.
     */
    public final Rect mUnrestricted = new Rect();

    /**
     * During layout, the frame that is display-cutout safe, i.e. that does not intersect with it.
     */
    public final Rect mDisplayCutoutSafe = new Rect();

    public int mDisplayWidth;
    public int mDisplayHeight;

    public int mRotation;

    public DisplayFrames(int displayId, InsetsState insetsState, DisplayInfo info,
            WmDisplayCutout displayCutout, RoundedCorners roundedCorners,
            PrivacyIndicatorBounds indicatorBounds) {
    
    
        mDisplayId = displayId;
        mInsetsState = insetsState;
        onDisplayInfoUpdated(info, displayCutout, roundedCorners, indicatorBounds);
    }

    /**
     * Update {@link DisplayFrames} when {@link DisplayInfo} is updated.
     *
     * @param info the updated {@link DisplayInfo}.
     * @param displayCutout the updated {@link DisplayCutout}.
     * @param roundedCorners the updated {@link RoundedCorners}.
     * @return {@code true} if the insets state has been changed; {@code false} otherwise.
     */
    public boolean onDisplayInfoUpdated(DisplayInfo info, @NonNull WmDisplayCutout displayCutout,
            @NonNull RoundedCorners roundedCorners,
            @NonNull PrivacyIndicatorBounds indicatorBounds) {
    
    
        mRotation = info.rotation;

        final InsetsState state = mInsetsState;
        final Rect safe = mDisplayCutoutSafe;
        final DisplayCutout cutout = displayCutout.getDisplayCutout();
        if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight
                 && state.getDisplayCutout().equals(cutout)
                && state.getRoundedCorners().equals(roundedCorners)
                && state.getPrivacyIndicatorBounds().equals(indicatorBounds)) {
    
    
            return false;
        }
        mDisplayWidth = info.logicalWidth;
        mDisplayHeight = info.logicalHeight;
        final Rect unrestricted = mUnrestricted;
        unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
        safe.set(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
        state.setDisplayFrame(unrestricted);
        state.setDisplayCutout(cutout);
        state.setRoundedCorners(roundedCorners);
        state.setPrivacyIndicatorBounds(indicatorBounds);
        if (!cutout.isEmpty()) {
    
    
            if (cutout.getSafeInsetLeft() > 0) {
    
    
                safe.left = unrestricted.left + cutout.getSafeInsetLeft();
            }
            if (cutout.getSafeInsetTop() > 0) {
    
    
                safe.top = unrestricted.top + cutout.getSafeInsetTop();
            }
            if (cutout.getSafeInsetRight() > 0) {
    
    
                safe.right = unrestricted.right - cutout.getSafeInsetRight();
            }
            if (cutout.getSafeInsetBottom() > 0) {
    
    
                safe.bottom = unrestricted.bottom - cutout.getSafeInsetBottom();
            }
            state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(
                    unrestricted.left, unrestricted.top, safe.left, unrestricted.bottom);
            state.getSource(ITYPE_TOP_DISPLAY_CUTOUT).setFrame(
                    unrestricted.left, unrestricted.top, unrestricted.right, safe.top);
            state.getSource(ITYPE_RIGHT_DISPLAY_CUTOUT).setFrame(
                    safe.right, unrestricted.top, unrestricted.right, unrestricted.bottom);
            state.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(
                    unrestricted.left, safe.bottom, unrestricted.right, unrestricted.bottom);
        } else {
    
    
            state.removeSource(ITYPE_LEFT_DISPLAY_CUTOUT);
            state.removeSource(ITYPE_TOP_DISPLAY_CUTOUT);
            state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT);
            state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT);
        }
        return true;
    }

    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
    
    
        final long token = proto.start(fieldId);
        proto.end(token);
    }

    public void dump(String prefix, PrintWriter pw) {
    
    
        pw.println(prefix + "DisplayFrames w=" + mDisplayWidth + " h=" + mDisplayHeight
                + " r=" + mRotation);
    }
}

二、构建SystemBar对应的视图窗口区域坐标对象

1、系统主要是在DisplayPolicy的layoutWindowLw() 方法中构建SystemBar对应的视图窗口区域坐标对象的。

frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java

public class DisplayPolicy {
    
    
    public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
    
    
        Log.d("SystemBar", "DisplayPolicy_layoutWindowLw");
        if (win == mNavigationBar && !INSETS_LAYOUT_GENERALIZATION) {
    
    
            Log.d("SystemBar", "DisplayPolicy_layoutNavigationBar");
            mNavigationBarPosition = layoutNavigationBar(displayFrames,
                    mBarContentFrames.get(TYPE_NAVIGATION_BAR));
            return;
        }
        if ((win == mStatusBar && !canReceiveInput(win)) && !INSETS_LAYOUT_GENERALIZATION) {
    
    
            Log.d("SystemBar", "DisplayPolicy_layoutStatusBar");
            layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR));
            return;
        }
        ...代码省略...
     }
 }     

layoutWindowLw方法中首先会判断win的类型,然后调用layoutNavigationBar方法和layoutStatusBar方法构建NavigationBar和StatusBar所对应的视图窗口区域坐标。

三、导航栏视图窗口区域坐标对象的构建

构建导航栏视图窗口区域坐标的layoutNavigationBar方法r如下所示。

public class DisplayPolicy {
    
    
    private int layoutNavigationBar(DisplayFrames displayFrames, Rect contentFrame) {
    
    
        if (mNavigationBar == null) {
    
    
            return NAV_BAR_INVALID;
        }

        final int uiMode = mDisplayContent.getConfiguration().uiMode;
        final Rect navigationFrame = sTmpNavFrame;
        // Force the navigation bar to its appropriate place and size. We need to do this directly,
        // instead of relying on it to bubble up from the nav bar, because this needs to change
        // atomically with screen rotations.
        final int rotation = displayFrames.mRotation;
        final int displayHeight = displayFrames.mDisplayHeight;
        final int displayWidth = displayFrames.mDisplayWidth;
        final int navBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);

        getRotatedWindowBounds(displayFrames, mNavigationBar, navigationFrame);

        final Rect cutoutSafeUnrestricted = sTmpRect;
        cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
        cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);

        if (navBarPosition == NAV_BAR_BOTTOM) {
    
    
            // It's a system nav bar or a portrait screen; nav bar goes on bottom.
            int temp_bottom = Math.min(cutoutSafeUnrestricted.bottom, navigationFrame.bottom);
            int navigationBarFrameHeight = getNavigationBarFrameHeight(rotation, uiMode);
            navigationFrame.top = temp_bottom - navigationBarFrameHeight;
            Log.d("SystemBar","layoutNavigationBar temp_bottom=" + temp_bottom
                    + " navigationBarFrameHeight=" + navigationBarFrameHeight
                    + " navigationFrame.top=" + navigationFrame.top
            );
        } else if (navBarPosition == NAV_BAR_RIGHT) {
    
    
            // Landscape screen; nav bar goes to the right.
            navigationFrame.left = Math.min(cutoutSafeUnrestricted.right, navigationFrame.right)
                    - getNavigationBarWidth(rotation, uiMode, navBarPosition);
        } else if (navBarPosition == NAV_BAR_LEFT) {
    
    
            // Seascape screen; nav bar goes to the left.
            navigationFrame.right = Math.max(cutoutSafeUnrestricted.left, navigationFrame.left)
                    + getNavigationBarWidth(rotation, uiMode, navBarPosition);
        }

        // Compute the final frame.
        final WindowFrames windowFrames = mNavigationBar.getLayoutingWindowFrames();
        windowFrames.setFrames(navigationFrame /* parentFrame */,
                navigationFrame /* displayFrame */);
        mNavigationBar.computeFrameAndUpdateSourceFrame(displayFrames);
        sTmpRect.set(windowFrames.mFrame);
        sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
        contentFrame.set(sTmpRect);

        if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
        return navBarPosition;
    }
}

四、状态栏视图窗口区域坐标对象的构建

1、构建状态栏视图窗口区域坐标的layoutStatusBar方法r如下所示。

    private void layoutStatusBar(DisplayFrames displayFrames, Rect contentFrame) {
    
    
        // decide where the status bar goes ahead of time
        if (mStatusBar == null) {
    
    
            return;
        }
        // apply any status bar insets
        getRotatedWindowBounds(displayFrames, mStatusBar, sTmpStatusFrame);
        final WindowFrames windowFrames = mStatusBar.getLayoutingWindowFrames();
        windowFrames.setFrames(sTmpStatusFrame /* parentFrame */,
                sTmpStatusFrame /* displayFrame */);
        // Let the status bar determine its size.
        mStatusBar.computeFrameAndUpdateSourceFrame(displayFrames);

        // For layout, the status bar is always at the top with our fixed height.
        int statusBarBottom = displayFrames.mUnrestricted.top
                + mStatusBarHeightForRotation[displayFrames.mRotation];

        if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
    
    
            // Make sure that the zone we're avoiding for the cutout is at least as tall as the
            // status bar; otherwise fullscreen apps will end up cutting halfway into the status
            // bar.
            displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
                    statusBarBottom);
        }

        sTmpRect.set(windowFrames.mFrame);
        sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
        sTmpRect.top = windowFrames.mFrame.top; // Ignore top display cutout inset
        sTmpRect.bottom = statusBarBottom; // Use collapsed status bar size
        contentFrame.set(sTmpRect);
    }

猜你喜欢

转载自blog.csdn.net/abc6368765/article/details/129727515
今日推荐