diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 4a7edee7beac6..583f0929120e8 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -504,6 +504,9 @@ class DisplayContent extends WindowContainer mWinRemovedSinceNullFocus = new ArrayList<>(); + /** Windows whose client's insets states are not up-to-date. */ + final ArrayList mWinInsetsChanged = new ArrayList<>(); + private ScreenRotationAnimation mScreenRotationAnimation; /** @@ -722,7 +725,10 @@ class DisplayContent extends WindowContainer= 0; i--) { mProviders.valueAt(i).onPostLayout(); } + final ArrayList winInsetsChanged = mDisplayContent.mWinInsetsChanged; if (!mLastState.equals(mState)) { mLastState.set(mState, true /* copySources */); notifyInsetsChanged(); + } else { + // The global insets state has not changed but there might be windows whose conditions + // (e.g., z-order) have changed. They can affect the insets states that we dispatch to + // the clients. + for (int i = winInsetsChanged.size() - 1; i >= 0; i--) { + winInsetsChanged.get(i).notifyInsetsChanged(); + } } + winInsetsChanged.clear(); } void onInsetsModified(InsetsControlTarget windowState, InsetsState state) { 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 db7bce4c87530..17ebe4f67377f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -32,6 +32,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; @@ -168,6 +172,45 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME)); } + @Test + public void testStripForDispatch_imeOrderChanged() { + getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null); + + // This window can be the IME target while app cannot be the IME target. + createWindow(null, TYPE_APPLICATION, "base"); + + // Send our spy window (app) into the system so that we can detect the invocation. + final WindowState win = createWindow(null, TYPE_APPLICATION, "app"); + final WindowToken parent = win.mToken; + parent.removeChild(win); + final WindowState app = spy(win); + parent.addWindow(app); + + // Adding FLAG_NOT_FOCUSABLE makes app above IME. + app.mAttrs.flags |= FLAG_NOT_FOCUSABLE; + mDisplayContent.computeImeTarget(true); + mDisplayContent.setLayoutNeeded(); + mDisplayContent.applySurfaceChangesTransaction(); + + // app won't get IME insets while above IME. + assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME)); + + // Reset invocation counter. + clearInvocations(app); + + // Removing FLAG_NOT_FOCUSABLE makes app below IME. + app.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE; + mDisplayContent.computeImeTarget(true); + mDisplayContent.setLayoutNeeded(); + mDisplayContent.applySurfaceChangesTransaction(); + + // Make sure app got notified. + verify(app, atLeast(1)).notifyInsetsChanged(); + + // app will get IME insets while below IME. + assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME)); + } + @Test public void testStripForDispatch_childWindow_altFocusable() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app");