diff options
| author | 2021-02-05 05:32:17 +0800 | |
|---|---|---|
| committer | 2021-02-19 03:22:40 +0800 | |
| commit | c891f22678f677a60859a1bce15e41f5f13a06ff (patch) | |
| tree | 6fd37ffa9a4df86ebf34ff9ce9ce311e25c740cf | |
| parent | d3e7d8c0dca163e28aa1600adb362b38528f01db (diff) | |
Only update mAboveInsetsState when necessary
This CL only updates mAboveInsetsState while the z-order of a window is
changed or the display info has been updated.
This can be a step to make client compute its window frame locally.
Bug: 161810301
Bug: 175861127
Test: atest DisplayPolicyTests DisplayPolicyLayoutTests
Change-Id: Ic202ca82ae3b0aeaf4d95ba6d0847970aa9896a6
11 files changed, 243 insertions, 74 deletions
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 219190f554ea..21dd1fb05615 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -20,8 +20,6 @@ import static android.view.InsetsStateProto.DISPLAY_CUTOUT; import static android.view.InsetsStateProto.DISPLAY_FRAME; import static android.view.InsetsStateProto.SOURCES; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE; -import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES; -import static android.view.WindowInsets.Type.SYSTEM_GESTURES; import static android.view.WindowInsets.Type.displayCutout; import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.indexOf; @@ -106,14 +104,11 @@ public class InsetsState implements Parcelable { public static final int ITYPE_NAVIGATION_BAR = 1; public static final int ITYPE_CAPTION_BAR = 2; - // The always visible types are visible to all windows regardless of the z-order. - public static final int FIRST_ALWAYS_VISIBLE_TYPE = 3; - public static final int ITYPE_TOP_GESTURES = FIRST_ALWAYS_VISIBLE_TYPE; + public static final int ITYPE_TOP_GESTURES = 3; public static final int ITYPE_BOTTOM_GESTURES = 4; public static final int ITYPE_LEFT_GESTURES = 5; public static final int ITYPE_RIGHT_GESTURES = 6; - /** Additional gesture inset types that map into {@link Type.MANDATORY_SYSTEM_GESTURES}. */ public static final int ITYPE_TOP_MANDATORY_GESTURES = 7; public static final int ITYPE_BOTTOM_MANDATORY_GESTURES = 8; public static final int ITYPE_LEFT_MANDATORY_GESTURES = 9; @@ -123,7 +118,6 @@ public class InsetsState implements Parcelable { public static final int ITYPE_TOP_DISPLAY_CUTOUT = 12; public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 13; public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 14; - public static final int LAST_ALWAYS_VISIBLE_TYPE = ITYPE_BOTTOM_DISPLAY_CUTOUT; public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = 15; public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 16; @@ -188,18 +182,6 @@ public class InsetsState implements Parcelable { } /** - * Mirror the always visible sources from the other state. They will share the same object for - * the always visible types. - * - * @param other the state to mirror the mirrored sources from. - */ - public void mirrorAlwaysVisibleInsetsSources(InsetsState other) { - for (int type = FIRST_ALWAYS_VISIBLE_TYPE; type <= LAST_ALWAYS_VISIBLE_TYPE; type++) { - mSources[type] = other.mSources[type]; - } - } - - /** * Calculates {@link WindowInsets} based on the current source configuration. * * @param frame The frame to calculate the insets relative to. @@ -380,14 +362,14 @@ public class InsetsState implements Parcelable { processSourceAsPublicType(source, typeInsetsMap, typeSideMap, typeVisibilityMap, insets, type); - if (type == MANDATORY_SYSTEM_GESTURES) { + if (type == Type.MANDATORY_SYSTEM_GESTURES) { // Mandatory system gestures are also system gestures. // TODO: find a way to express this more generally. One option would be to define // Type.systemGestureInsets() as NORMAL | MANDATORY, but then we lose the // ability to set systemGestureInsets() independently from // mandatorySystemGestureInsets() in the Builder. processSourceAsPublicType(source, typeInsetsMap, typeSideMap, typeVisibilityMap, - insets, SYSTEM_GESTURES); + insets, Type.SYSTEM_GESTURES); } } @@ -493,9 +475,14 @@ public class InsetsState implements Parcelable { * to the client. * * @param type The {@link InternalInsetsType} of the source to remove + * @return {@code true} if this InsetsState was modified; {@code false} otherwise. */ - public void removeSource(@InternalInsetsType int type) { + public boolean removeSource(@InternalInsetsType int type) { + if (mSources[type] == null) { + return false; + } mSources[type] = null; + return true; } /** @@ -552,6 +539,24 @@ public class InsetsState implements Parcelable { } } + /** + * Sets the values from the other InsetsState. But for sources, only specific types of source + * would be set. + * + * @param other the other InsetsState. + * @param types the only types of sources would be set. + */ + public void set(InsetsState other, @InsetsType int types) { + mDisplayFrame.set(other.mDisplayFrame); + mDisplayCutout.set(other.mDisplayCutout); + mRoundedCorners = other.getRoundedCorners(); + final ArraySet<Integer> t = toInternalType(types); + for (int i = t.size() - 1; i >= 0; i--) { + final int type = t.valueAt(i); + mSources[type] = other.mSources[type]; + } + } + public void addSource(InsetsSource source) { mSources[source.getType()] = source; } @@ -575,6 +580,18 @@ public class InsetsState implements Parcelable { if ((types & Type.CAPTION_BAR) != 0) { result.add(ITYPE_CAPTION_BAR); } + if ((types & Type.SYSTEM_GESTURES) != 0) { + result.add(ITYPE_LEFT_GESTURES); + result.add(ITYPE_TOP_GESTURES); + result.add(ITYPE_RIGHT_GESTURES); + result.add(ITYPE_BOTTOM_GESTURES); + } + if ((types & Type.MANDATORY_SYSTEM_GESTURES) != 0) { + result.add(ITYPE_LEFT_MANDATORY_GESTURES); + result.add(ITYPE_TOP_MANDATORY_GESTURES); + result.add(ITYPE_RIGHT_MANDATORY_GESTURES); + result.add(ITYPE_BOTTOM_MANDATORY_GESTURES); + } if ((types & Type.DISPLAY_CUTOUT) != 0) { result.add(ITYPE_LEFT_DISPLAY_CUTOUT); result.add(ITYPE_TOP_DISPLAY_CUTOUT); diff --git a/core/java/android/view/RoundedCorners.java b/core/java/android/view/RoundedCorners.java index 015e804da2f6..569c287901c7 100644 --- a/core/java/android/view/RoundedCorners.java +++ b/core/java/android/view/RoundedCorners.java @@ -335,7 +335,7 @@ public class RoundedCorners implements Parcelable { } if (o instanceof RoundedCorners) { RoundedCorners r = (RoundedCorners) o; - return Arrays.deepEquals(mRoundedCorners, ((RoundedCorners) o).mRoundedCorners); + return Arrays.deepEquals(mRoundedCorners, r.mRoundedCorners); } return false; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 86968ed6d175..f66c7605bcd2 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -673,10 +673,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Used in updating override configurations private final Configuration mTempConfig = new Configuration(); - // Used in performing layout, to record the insets provided by other windows above the current - // window. - private InsetsState mTmpAboveInsetsState = new InsetsState(); - /** * Used to prevent recursions when calling * {@link #ensureActivitiesVisible(ActivityRecord, int, boolean, boolean)} @@ -778,13 +774,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp + " parentHidden=" + w.isParentWindowHidden()); } - // Sets mAboveInsets for each window. Windows behind the window providing the insets can - // receive the insets. - if (!w.mAboveInsetsState.equals(mTmpAboveInsetsState)) { - w.mAboveInsetsState.set(mTmpAboveInsetsState); - mWinInsetsChanged.add(w); - } - // If this view is GONE, then skip it -- keep the current frame, and let the caller know // so they can ignore it if they want. (We do the normal layout for INVISIBLE windows, // since that means "perform layout as normal, just don't display"). @@ -818,16 +807,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp + " mContainingFrame=" + w.getContainingFrame() + " mDisplayFrame=" + w.getDisplayFrame()); } - provideInsetsByWindow(w); }; - private void provideInsetsByWindow(WindowState w) { - for (int i = 0; i < w.mProvidedInsetsSources.size(); i++) { - final InsetsSource providedSource = w.mProvidedInsetsSources.valueAt(i); - mTmpAboveInsetsState.addSource(providedSource); - } - } - private final Consumer<WindowState> mPerformLayoutAttached = w -> { if (w.mLayoutAttached) { if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame @@ -2511,8 +2492,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp void onDisplayInfoChanged() { final DisplayInfo info = mDisplayInfo; - mDisplayFrames.onDisplayInfoUpdated(info, calculateDisplayCutoutForRotation(info.rotation), - calculateRoundedCornersForRotation(info.rotation)); + if (mDisplayFrames.onDisplayInfoUpdated(info, + calculateDisplayCutoutForRotation(info.rotation), + calculateRoundedCornersForRotation(info.rotation))) { + // TODO(b/161810301): Set notifyInsetsChange to true while the server no longer performs + // layout. + mInsetsStateController.onDisplayInfoUpdated(false /* notifyInsetsChange */); + } mInputMonitor.layoutInputConsumers(info.logicalWidth, info.logicalHeight); mDisplayPolicy.onDisplayInfoChanged(info); } @@ -3767,8 +3753,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // 2. Assign window layers based on the IME surface parent to make sure it is on top of the // app. assignWindowLayers(true /* setLayoutNeeded */); - // 3. Update the IME control target to apply any inset change and animation. - // 4. Reparent the IME container surface to either the input target app, or the IME window + // 3. The z-order of IME might have been changed. Update the above insets state. + mInsetsStateController.updateAboveInsetsState( + mInputMethodWindow, true /* notifyInsetsChange */); + // 4. Update the IME control target to apply any inset change and animation. + // 5. Reparent the IME container surface to either the input target app, or the IME window // parent. updateImeControlTarget(); } @@ -4341,14 +4330,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp + " dh=" + mDisplayInfo.logicalHeight); } - // Used to indicate that we have processed the insets windows. This needs to be after - // beginLayoutLw to ensure the raw insets state display related info is initialized. - final InsetsState rawInsetsState = getInsetsStateController().getRawInsetsState(); - mTmpAboveInsetsState = new InsetsState(); - mTmpAboveInsetsState.setDisplayFrame(rawInsetsState.getDisplayFrame()); - mTmpAboveInsetsState.setDisplayCutout(rawInsetsState.getDisplayCutout()); - mTmpAboveInsetsState.mirrorAlwaysVisibleInsetsSources(rawInsetsState); - int seq = mLayoutSeq + 1; if (seq < 0) seq = 0; mLayoutSeq = seq; diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java index e4230a2c8760..a37f3f254276 100644 --- a/services/core/java/com/android/server/wm/DisplayFrames.java +++ b/services/core/java/com/android/server/wm/DisplayFrames.java @@ -21,6 +21,7 @@ import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT; import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT; import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT; +import android.annotation.NonNull; import android.graphics.Rect; import android.util.proto.ProtoOutputStream; import android.view.DisplayCutout; @@ -70,25 +71,28 @@ public class DisplayFrames { * @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 void onDisplayInfoUpdated(DisplayInfo info, WmDisplayCutout displayCutout, - RoundedCorners roundedCorners) { - mDisplayWidth = info.logicalWidth; - mDisplayHeight = info.logicalHeight; + public boolean onDisplayInfoUpdated(DisplayInfo info, @NonNull WmDisplayCutout displayCutout, + @NonNull RoundedCorners roundedCorners) { mRotation = info.rotation; - final WmDisplayCutout wmDisplayCutout = - displayCutout != null ? displayCutout : WmDisplayCutout.NO_CUTOUT; final InsetsState state = mInsetsState; - final Rect unrestricted = mUnrestricted; final Rect safe = mDisplayCutoutSafe; - final DisplayCutout cutout = wmDisplayCutout.getDisplayCutout(); + final DisplayCutout cutout = displayCutout.getDisplayCutout(); + if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight + && state.getDisplayCutout().equals(cutout) + && state.getRoundedCorners().equals(roundedCorners)) { + 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 != null ? roundedCorners - : RoundedCorners.NO_ROUNDED_CORNERS); + state.setRoundedCorners(roundedCorners); if (!cutout.isEmpty()) { if (cutout.getSafeInsetLeft() > 0) { safe.left = unrestricted.left + cutout.getSafeInsetLeft(); @@ -116,6 +120,7 @@ public class DisplayFrames { state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT); state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT); } + return true; } public void dumpDebug(ProtoOutputStream proto, long fieldId) { diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 580d3285c6a5..75176df6aaf7 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -27,6 +27,9 @@ import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_INVALID; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.view.WindowInsets.Type.displayCutout; +import static android.view.WindowInsets.Type.mandatorySystemGestures; +import static android.view.WindowInsets.Type.systemGestures; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; @@ -293,6 +296,76 @@ class InsetsStateController { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } + /** + * Updates {@link WindowState#mAboveInsetsState} for all windows in the display while the + * z-order of a window is changed. + * + * @param win The window whose z-order has changed. + * @param notifyInsetsChange {@code true} if the clients should be notified about the change. + */ + void updateAboveInsetsState(WindowState win, boolean notifyInsetsChange) { + if (win == null || win.getDisplayContent() != mDisplayContent) { + return; + } + final boolean[] aboveWin = { true }; + final InsetsState aboveInsetsState = new InsetsState(); + aboveInsetsState.set(mState, + displayCutout() | systemGestures() | mandatorySystemGestures()); + final SparseArray<InsetsSource> winProvidedSources = win.mProvidedInsetsSources; + final ArrayList<WindowState> insetsChangedWindows = new ArrayList<>(); + mDisplayContent.forAllWindows(w -> { + if (aboveWin[0]) { + if (w == win) { + aboveWin[0] = false; + if (!win.mAboveInsetsState.equals(aboveInsetsState)) { + win.mAboveInsetsState.set(aboveInsetsState); + insetsChangedWindows.add(win); + } + return winProvidedSources.size() == 0; + } else { + final SparseArray<InsetsSource> providedSources = w.mProvidedInsetsSources; + for (int i = providedSources.size() - 1; i >= 0; i--) { + aboveInsetsState.addSource(providedSources.valueAt(i)); + } + if (winProvidedSources.size() == 0) { + return false; + } + boolean changed = false; + for (int i = winProvidedSources.size() - 1; i >= 0; i--) { + changed |= w.mAboveInsetsState.removeSource(winProvidedSources.keyAt(i)); + } + if (changed) { + insetsChangedWindows.add(w); + } + } + } else { + for (int i = winProvidedSources.size() - 1; i >= 0; i--) { + w.mAboveInsetsState.addSource(winProvidedSources.valueAt(i)); + } + insetsChangedWindows.add(w); + } + return false; + }, true /* traverseTopToBottom */); + if (notifyInsetsChange) { + for (int i = insetsChangedWindows.size() - 1; i >= 0; i--) { + mDispatchInsetsChanged.accept(insetsChangedWindows.get(i)); + } + } + } + + void onDisplayInfoUpdated(boolean notifyInsetsChange) { + final ArrayList<WindowState> insetsChangedWindows = new ArrayList<>(); + mDisplayContent.forAllWindows(w -> { + w.mAboveInsetsState.set(mState, displayCutout()); + insetsChangedWindows.add(w); + }, true /* traverseTopToBottom */); + if (notifyInsetsChange) { + for (int i = insetsChangedWindows.size() - 1; i >= 0; i--) { + mDispatchInsetsChanged.accept(insetsChangedWindows.get(i)); + } + } + } + void onInsetsModified(InsetsControlTarget caller) { boolean changed = false; for (int i = mProviders.size() - 1; i >= 0; i--) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 5dc5ab767b2e..99246dd2ae54 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1874,6 +1874,10 @@ public class WindowManagerService extends IWindowManager.Stub displayContent.sendNewConfiguration(); } + // This window doesn't have a frame yet. Don't let this window cause the insets change. + displayContent.getInsetsStateController().updateAboveInsetsState( + win, false /* notifyInsetsChanged */); + getInsetsSourceControls(win, outActiveControls); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index a94b0aa9b72f..a8ab01f8f31a 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -211,11 +211,11 @@ import android.os.Trace; import android.os.WorkSource; import android.provider.Settings; import android.text.TextUtils; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.MergedConfiguration; import android.util.Slog; +import android.util.SparseArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.view.Display; @@ -648,12 +648,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP /** * The insets state of sources provided by windows above the current window. */ - InsetsState mAboveInsetsState = new InsetsState(); + final InsetsState mAboveInsetsState = new InsetsState(); /** * The insets sources provided by this window. */ - ArrayMap<Integer, InsetsSource> mProvidedInsetsSources = new ArrayMap<>(); + final SparseArray<InsetsSource> mProvidedInsetsSources = new SparseArray<>(); /** * Surface insets from the previous call to relayout(), used to track @@ -2204,7 +2204,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - @Override + @Override void removeImmediately() { super.removeImmediately(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index b1ea4a58d0f1..5a0466afa85b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -130,7 +130,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { // insets state with the global one. final InsetsState insetsState = win.getDisplayContent().getInsetsStateController().getRawInsetsState(); - win.mAboveInsetsState = insetsState; + win.mAboveInsetsState.set(insetsState); } public void setRotation(int rotation, boolean includingWindows) { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java index 2163661b7506..47cf53b621d3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; +import static android.view.RoundedCorners.NO_ROUNDED_CORNERS; import static android.view.Surface.ROTATION_0; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -37,6 +38,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT; +import static com.android.server.wm.utils.WmDisplayCutout.NO_CUTOUT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -300,9 +302,9 @@ public class DisplayPolicyTests extends WindowTestsBase { displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs); mNavBarWindow.getControllableInsetProvider().setServerVisible(true); final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState(); - mImeWindow.mAboveInsetsState = state; + mImeWindow.mAboveInsetsState.set(state); mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(), - state, displayInfo, null /* displayCutout */, null /* roundedCorners*/); + state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS); mDisplayContent.setInputMethodWindowLocked(mImeWindow); mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java index 20775e84fd8f..683ed889d283 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java @@ -117,7 +117,7 @@ public class DisplayPolicyTestsBase extends WindowTestsBase { static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation, boolean withDisplayCutout, boolean isLongEdgeCutout) { final DisplayInfo info = new DisplayInfo(); - WmDisplayCutout cutout = null; + WmDisplayCutout cutout = WmDisplayCutout.NO_CUTOUT; final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270; info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH; diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index ee293fcf70e6..be036034542e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -32,13 +32,14 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; +import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -208,7 +209,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { app.mAboveInsetsState.getSource(ITYPE_IME).setFrame(mImeWindow.getFrame()); // Make sure app got notified. - verify(app, atLeast(1)).notifyInsetsChanged(); + verify(app, atLeastOnce()).notifyInsetsChanged(); // app will get visible IME insets while below IME. assertTrue(getController().getInsetsForWindow(app).getSource(ITYPE_IME).isVisible()); @@ -336,6 +337,92 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertFalse(app.getInsetsState().getSource(ITYPE_STATUS_BAR).isVisible()); } + @Test + public void testUpdateAboveInsetsState_provideInsets() { + final WindowState app = createTestWindow("app"); + final WindowState statusBar = createTestWindow("statusBar"); + final WindowState navBar = createTestWindow("navBar"); + + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); + + assertNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR)); + assertNull(statusBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR)); + assertNull(navBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR)); + + getController().updateAboveInsetsState(statusBar, true /* notifyInsetsChange */); + + assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR)); + assertNull(statusBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR)); + assertNull(navBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR)); + + verify(app, atLeastOnce()).notifyInsetsChanged(); + } + + @Test + public void testUpdateAboveInsetsState_receiveInsets() { + final WindowState app = createTestWindow("app"); + final WindowState statusBar = createTestWindow("statusBar"); + final WindowState navBar = createTestWindow("navBar"); + + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); + getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null); + + assertNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR)); + assertNull(app.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR)); + + getController().updateAboveInsetsState(app, true /* notifyInsetsChange */); + + assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR)); + assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR)); + + verify(app, atLeastOnce()).notifyInsetsChanged(); + } + + @Test + public void testUpdateAboveInsetsState_zOrderChanged() { + final WindowState ime = createTestWindow("ime"); + final WindowState app = createTestWindow("app"); + final WindowState statusBar = createTestWindow("statusBar"); + final WindowState navBar = createTestWindow("navBar"); + + getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null); + getController().getSourceProvider(ITYPE_IME).setClientVisible(true); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); + getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null); + getController().updateAboveInsetsState(ime, false /* notifyInsetsChange */); + getController().updateAboveInsetsState(statusBar, false /* notifyInsetsChange */); + getController().updateAboveInsetsState(navBar, false /* notifyInsetsChange */); + + // ime is below others. + assertNull(app.mAboveInsetsState.peekSource(ITYPE_IME)); + assertNull(statusBar.mAboveInsetsState.peekSource(ITYPE_IME)); + assertNull(navBar.mAboveInsetsState.peekSource(ITYPE_IME)); + assertNotNull(ime.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR)); + assertNotNull(ime.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR)); + + ime.getParent().positionChildAt(POSITION_TOP, ime, true /* includingParents */); + getController().updateAboveInsetsState(ime, true /* notifyInsetsChange */); + + // ime is above others. + assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_IME)); + assertNotNull(statusBar.mAboveInsetsState.peekSource(ITYPE_IME)); + assertNotNull(navBar.mAboveInsetsState.peekSource(ITYPE_IME)); + assertNull(ime.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR)); + assertNull(ime.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR)); + + verify(ime, atLeastOnce()).notifyInsetsChanged(); + verify(app, atLeastOnce()).notifyInsetsChanged(); + verify(statusBar, atLeastOnce()).notifyInsetsChanged(); + verify(navBar, atLeastOnce()).notifyInsetsChanged(); + } + + private WindowState createTestWindow(String name) { + final WindowState win = createWindow(null, TYPE_APPLICATION, name); + win.setHasSurface(true); + spyOn(win); + return win; + } + private InsetsStateController getController() { return mDisplayContent.getInsetsStateController(); } |