From e067ddfc05c495eebf7e07664774a0776ec7813d Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Fri, 24 Apr 2020 18:28:25 -0700 Subject: [PATCH] Shift Primary stack as well as secondary during ime adjustment Previously, was only 'adjusting' the secondary split for ime. So the secondary had functional insets and drag/drop. However, the primary wasn't being adjusted (accorcding to WM). This caused its insets to be calculated against its originla position (which allowed ime insets to potentially overlap it) and it meant that WM didn't use its visual position when calculating drag/drop coordinates. So, this does the same with the primary stack as what was done with secondary. However, doing this required some other fixes in WM. Basically, if appbounds is explicitly overridden, just use them instead of intersecting with parent. Also, WSA doesn't apply crop for splits (maybe it shouldn't apply crop to anything anymore). Additionally, insets calculation was applying top insets to the bottom if the inset frame's top wasn't exactly equal to the window's top -- because of a catch-all else condition. So this adds checks for matching the bottoms as well. Bug: 154056542 Bug: 151862790 Test: Open two apps in split screen and open IME in secondary. Drag from secondary to primary. Change-Id: I2391783e726e4a1c8ed3150628af2f398218fe90 --- core/java/android/view/InsetsSource.java | 13 +++++-- .../systemui/stackdivider/Divider.java | 14 +++++++ .../core/java/com/android/server/wm/Task.java | 38 ++++++++++--------- .../server/wm/WindowStateAnimator.java | 4 +- .../server/wm/InsetsSourceProviderTest.java | 21 ++++++++++ 5 files changed, 68 insertions(+), 22 deletions(-) diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java index 033ccef3666db..a501779637bc7 100644 --- a/core/java/android/view/InsetsSource.java +++ b/core/java/android/view/InsetsSource.java @@ -136,20 +136,25 @@ public class InsetsSource implements Parcelable { if (mTmpFrame.width() == relativeFrame.width()) { if (mTmpFrame.top == relativeFrame.top) { return Insets.of(0, mTmpFrame.height(), 0, 0); - } else { + } else if (mTmpFrame.bottom == relativeFrame.bottom) { return Insets.of(0, 0, 0, mTmpFrame.height()); } + // TODO: remove when insets are shell-customizable. + // This is a hack that says "if this is a top-inset (eg statusbar), always apply it + // to the top". It is used when adjusting primary split for IME. + if (mTmpFrame.top == 0) { + return Insets.of(0, mTmpFrame.height(), 0, 0); + } } // Intersecting at left/right else if (mTmpFrame.height() == relativeFrame.height()) { if (mTmpFrame.left == relativeFrame.left) { return Insets.of(mTmpFrame.width(), 0, 0, 0); - } else { + } else if (mTmpFrame.right == relativeFrame.right) { return Insets.of(0, 0, mTmpFrame.width(), 0); } - } else { - return Insets.NONE; } + return Insets.NONE; } /** diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index f36f8c1318486..f08fbf1171a1d 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -263,11 +263,25 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, wct.setScreenSizeDp(mSplits.mSecondary.token, mSplits.mSecondary.configuration.screenWidthDp, mSplits.mSecondary.configuration.screenHeightDp); + + wct.setBounds(mSplits.mPrimary.token, mSplitLayout.mAdjustedPrimary); + adjustAppBounds = new Rect(mSplits.mPrimary.configuration + .windowConfiguration.getAppBounds()); + adjustAppBounds.offset(0, mSplitLayout.mAdjustedPrimary.top + - mSplitLayout.mPrimary.top); + wct.setAppBounds(mSplits.mPrimary.token, adjustAppBounds); + wct.setScreenSizeDp(mSplits.mPrimary.token, + mSplits.mPrimary.configuration.screenWidthDp, + mSplits.mPrimary.configuration.screenHeightDp); } else { wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary); wct.setAppBounds(mSplits.mSecondary.token, null); wct.setScreenSizeDp(mSplits.mSecondary.token, SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED); + wct.setBounds(mSplits.mPrimary.token, mSplitLayout.mPrimary); + wct.setAppBounds(mSplits.mPrimary.token, null); + wct.setScreenSizeDp(mSplits.mPrimary.token, + SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED); } WindowOrganizer.applyTransaction(wct); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 44049b84de403..3268fc28481cb 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -2299,27 +2299,31 @@ class Task extends WindowContainer { insideParentBounds = parentBounds.contains(resolvedBounds); } + // Non-null compatibility insets means the activity prefers to keep its original size, so + // out bounds doesn't need to be restricted by the parent or current display + final boolean customContainerPolicy = compatInsets != null; + Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); if (outAppBounds == null || outAppBounds.isEmpty()) { + // App-bounds hasn't been overridden, so calculate a value for it. inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds); outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); - } - // Non-null compatibility insets means the activity prefers to keep its original size, so - // the out bounds doesn't need to be restricted by the parent or current display. - final boolean customContainerPolicy = compatInsets != null; - if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) { - final Rect containingAppBounds; - if (insideParentBounds) { - containingAppBounds = parentConfig.windowConfiguration.getAppBounds(); - } else { - // Restrict appBounds to display non-decor rather than parent because the override - // bounds are beyond the parent. Otherwise, it won't match the overridden bounds. - final TaskDisplayArea displayArea = getDisplayArea(); - containingAppBounds = displayArea != null - ? displayArea.getWindowConfiguration().getAppBounds() : null; - } - if (containingAppBounds != null && !containingAppBounds.isEmpty()) { - outAppBounds.intersect(containingAppBounds); + + if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) { + final Rect containingAppBounds; + if (insideParentBounds) { + containingAppBounds = parentConfig.windowConfiguration.getAppBounds(); + } else { + // Restrict appBounds to display non-decor rather than parent because the + // override bounds are beyond the parent. Otherwise, it won't match the + // overridden bounds. + final TaskDisplayArea displayArea = getDisplayArea(); + containingAppBounds = displayArea != null + ? displayArea.getWindowConfiguration().getAppBounds() : null; + } + if (containingAppBounds != null && !containingAppBounds.isEmpty()) { + outAppBounds.intersect(containingAppBounds); + } } } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index bfe3b2890bc18..0e83beed6b905 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -57,6 +57,7 @@ import static com.android.server.wm.WindowStateAnimatorProto.SURFACE; import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT; import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; +import android.app.WindowConfiguration; import android.content.Context; import android.graphics.Matrix; import android.graphics.PixelFormat; @@ -787,7 +788,8 @@ class WindowStateAnimator { return false; } - if (w.getWindowConfiguration().tasksAreFloating()) { + if (w.getWindowConfiguration().tasksAreFloating() + || WindowConfiguration.isSplitScreenWindowingMode(w.getWindowingMode())) { return false; } diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index f8117573efddc..ca016761438b6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -189,4 +189,25 @@ public class InsetsSourceProviderTest extends WindowTestsBase { mProvider.onInsetsModified(target, state.getSource(ITYPE_STATUS_BAR)); assertTrue(mSource.isVisible()); } + + @Test + public void testInsetGeometries() { + final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); + statusBar.getFrameLw().set(0, 0, 500, 100); + statusBar.mHasSurface = true; + mProvider.setWindow(statusBar, null, null); + mProvider.onPostLayout(); + assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame()); + // Still apply top insets if window overlaps even if it's top doesn't exactly match + // the inset-window's top. + assertEquals(Insets.of(0, 100, 0, 0), + mProvider.getSource().calculateInsets(new Rect(0, -100, 500, 400), + false /* ignoreVisibility */)); + + // Don't apply left insets if window is left-of inset-window but still overlaps + statusBar.getFrameLw().set(100, 0, 0, 0); + assertEquals(Insets.of(0, 0, 0, 0), + mProvider.getSource().calculateInsets(new Rect(-100, 0, 400, 500), + false /* ignoreVisibility */)); + } }