Keep IME above starting window.

While app window is animating-in, IME window is child of aboveAppContainers.
If app requests IME on activity resume, IME will start animating-in
above Snapshot during app window animation.
However when app window animation finishes, IME's parent is no
longer aboveAppContainers, thereby making snapshot occlude
IME briefly. This results in flashing.

The fix is to keep IME in aboveAppContainers as long as startingWindow
is not removed from hierarchy.

Bug: 137534359
Test: Manual and atest ZOrderingTests AppWindowTokenTests
Change-Id: I78c939e8d1f23144162ba9eb8d834150fdd08ae8
This commit is contained in:
Tarandeep Singh
2019-07-30 13:30:03 -07:00
parent eaadb371c5
commit 69ab104a86
3 changed files with 38 additions and 3 deletions

View File

@@ -206,6 +206,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
boolean removed;
// Information about an application starting window if displayed.
// Note: these are de-referenced before the starting window animates away.
StartingData mStartingData;
WindowState startingWindow;
StartingSurface startingSurface;
@@ -1243,6 +1244,21 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
return true;
}
/**
* @return {@code true} if starting window is in app's hierarchy.
*/
boolean hasStartingWindow() {
if (startingDisplayed || mStartingData != null) {
return true;
}
for (int i = mChildren.size() - 1; i >= 0; i--) {
if (getChildAt(i).mAttrs.type == TYPE_APPLICATION_STARTING) {
return true;
}
}
return false;
}
@Override
void addWindow(WindowState w) {
super.addWindow(w);

View File

@@ -4845,9 +4845,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
//
// In the case where we have no IME target we assign it where it's base layer would
// place it in the AboveAppWindowContainers.
if (imeTarget != null && !(imeTarget.inSplitScreenWindowingMode()
|| imeTarget.mToken.isAppAnimating())
&& (imeTarget.getSurfaceControl() != null)) {
//
// Keep IME window in mAboveAppWindowsContainers as long as app's starting window exists
// so it get's layered above the starting window.
if (imeTarget != null
&& !(imeTarget.mAppToken != null && imeTarget.mAppToken.hasStartingWindow())
&& (!(imeTarget.inSplitScreenWindowingMode() || imeTarget.mToken.isAppAnimating())
&& (imeTarget.getSurfaceControl() != null))) {
mImeWindowsContainers.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
// TODO: We need to use an extra level on the app surface to ensure
// this is always above SurfaceView but always below attached window.

View File

@@ -504,6 +504,21 @@ public class AppWindowTokenTests extends WindowTestsBase {
assertEquals(stackBounds, mToken.getAnimationBounds(STACK_CLIP_BEFORE_ANIM));
}
@Test
public void testHasStartingWindow() {
final WindowManager.LayoutParams attrs =
new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING);
final WindowTestUtils.TestWindowState startingWindow = createWindowState(attrs, mToken);
mToken.startingDisplayed = true;
mToken.addWindow(startingWindow);
assertTrue("Starting window should be present", mToken.hasStartingWindow());
mToken.startingDisplayed = false;
assertTrue("Starting window should be present", mToken.hasStartingWindow());
mToken.removeChild(startingWindow);
assertFalse("Starting window should not be present", mToken.hasStartingWindow());
}
private void assertHasStartingWindow(AppWindowToken atoken) {
assertNotNull(atoken.startingSurface);
assertNotNull(atoken.mStartingData);