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

Commit 36017d8d authored by Qijing Yao's avatar Qijing Yao
Browse files

Improve robustness of DisplayLayout creation

During a window drag operation, mGlobalBoundsDp from DisplayLayout is
used to determine if the window intersects with the display and to
render an indicator surface showing the window's current position.

Previously, creating a DisplayLayout and setting its mGlobalBoundsDp
from the display topology were two separate steps. This design was
fragile, as a future developer could easily add a new call site to
create a DisplayLayou` but forget to set its global bounds.

This commit refactors display layout creation to be more robust
by coupling the creation and initialization:
1.  Consolidate Bounds Initialization: The DisplayRecord.createLayout()
    method is now responsible for both creating the DisplayLayout and
    populating its mGlobalBoundsDp.
2.  Add a Safety Net: DisplayLayout.mGlobalBoundsDp is now initialized
    to an empty RectF(). This acts as a failsafe, ensuring that if
    topology is somehow unavailable at creation time, the layout will
    not cause incorrect intersections.

Separately, this commit also removes the mUnpopulatedDisplayBounds
caching mechanism. This was originally implemented to handle a race
condition between onDisplayTopologyChanged and onDisplayAdded. It is no
longer necessary because the DisplayController now maintains a reference
to the latest DisplayTopology.

Bug: 419272794
Test: Manual test; atest WMShellUnitTests:DisplayControllerTests
Flag: com.android.window.flags.enable_connected_displays_window_drag
Change-Id: Ibfec219f1202d84ddefc78cf723a852cade1ecd5
parent f660b558
Loading
Loading
Loading
Loading
+15 −26
Original line number Diff line number Diff line
@@ -46,9 +46,7 @@ import com.android.wm.shell.shared.desktopmode.DesktopState;
import com.android.wm.shell.sysui.ShellInit;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
@@ -70,7 +68,6 @@ public class DisplayController {

    private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
    private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>();
    private final Map<Integer, RectF> mUnpopulatedDisplayBounds = new HashMap<>();
    private DisplayTopology mDisplayTopology;

    public DisplayController(Context context, IWindowManager wmService, ShellInit shellInit,
@@ -220,10 +217,6 @@ public class DisplayController {
            }
            final DisplayRecord record = new DisplayRecord(displayId, hasStatusAndNavBars);
            DisplayLayout displayLayout = record.createLayout(context, display);
            if (DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG.isTrue()
                    && mUnpopulatedDisplayBounds.containsKey(displayId)) {
                displayLayout.setGlobalBoundsDp(mUnpopulatedDisplayBounds.get(displayId));
            }
            record.setDisplayLayout(context, displayLayout);
            mDisplays.put(displayId, record);
            for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
@@ -270,17 +263,10 @@ public class DisplayController {
        }
        mDisplayTopology = topology;
        SparseArray<RectF> absoluteBounds = topology.getAbsoluteBounds();
        mUnpopulatedDisplayBounds.clear();
        for (int i = 0; i < absoluteBounds.size(); ++i) {
            int displayId = absoluteBounds.keyAt(i);
            DisplayLayout displayLayout = getDisplayLayout(displayId);
            if (displayLayout == null) {
                // onDisplayTopologyChanged can arrive before onDisplayAdded.
                // Store the bounds to be applied later in onDisplayAdded.
                Slog.d(TAG, "Storing bounds for onDisplayTopologyChanged on unknown"
                        + " display, displayId=" + displayId);
                mUnpopulatedDisplayBounds.put(displayId, absoluteBounds.valueAt(i));
            } else {
            if (displayLayout != null) {
                displayLayout.setGlobalBoundsDp(absoluteBounds.valueAt(i));
            }
        }
@@ -309,11 +295,6 @@ public class DisplayController {
                    : mContext.createDisplayContext(display);
            final Context context = perDisplayContext.createConfigurationContext(newConfig);
            final DisplayLayout displayLayout = dr.createLayout(context, display);
            if (mDisplayTopology != null) {
                displayLayout.setGlobalBoundsDp(
                        mDisplayTopology.getAbsoluteBounds().get(
                                displayId, displayLayout.globalBoundsDp()));
            }
            dr.setDisplayLayout(context, displayLayout);
            for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
                mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
@@ -395,7 +376,7 @@ public class DisplayController {
        }
    }

    private static class DisplayRecord {
    private class DisplayRecord {
        private final int mDisplayId;
        private Context mContext;
        private DisplayLayout mDisplayLayout;
@@ -408,12 +389,20 @@ public class DisplayController {
        }

        private DisplayLayout createLayout(Context context, Display display) {
            if (mDisplayId != Display.DEFAULT_DISPLAY && mHasStatusAndNavBars) {
                return new DisplayLayout(context, display, true /* hasNavigationBar */,
                        true /* hasTaskBar */);
            } else {
                return new DisplayLayout(context, display);
            final boolean shouldInitWithSystemDecorations =
                    mDisplayId != Display.DEFAULT_DISPLAY && mHasStatusAndNavBars;
            final DisplayLayout layout = shouldInitWithSystemDecorations
                    ? new DisplayLayout(
                            context, display, true /* hasNavigationBar */, true /* hasTaskBar */)
                    : new DisplayLayout(context, display);
            if (DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG.isTrue()
                    && mDisplayTopology != null) {
                final RectF globalBounds = mDisplayTopology.getAbsoluteBounds().get(mDisplayId);
                if (globalBounds != null) {
                    layout.setGlobalBoundsDp(globalBounds);
                }
            }
            return layout;
        }


+1 −1
Original line number Diff line number Diff line
@@ -214,7 +214,7 @@ public class DisplayLayout {
        mRotation = info.rotation;
        mCutout = info.displayCutout;
        mDensityDpi = info.logicalDensityDpi;
        mGlobalBoundsDp = new RectF(0, 0, pxToDp(mWidth), pxToDp(mHeight));
        mGlobalBoundsDp = new RectF();
        mHasNavigationBar = hasNavigationBar;
        mHasStatusBar = hasStatusBar;
        mAllowSeamlessRotationDespiteNavBarMoving = res.getBoolean(