From b2297ad376a764db9f43a724ea21cfe310e39892 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Fri, 26 Jul 2019 23:37:25 -0600 Subject: [PATCH] Wait for system decor windows on all displays during boot To prevent from showing empty content on some displays temporarily, wait for displays which support system decorations that have the expected window types to be drawn. Also correct the conditions for waiting: - isVisibleLw and !isDrawnLw are contradicted because they both check mHasSurface. - TYPE_APPLICATION must belong to an activity so it is more reasonable to check BASE_APPLICATION. Bug: 117597389 Test: atest DisplayContentTests \ #testShouldWaitForSystemDecorWindowsOnBoot_OnSecondaryDisplay Test: manual enable "Simulate secondary displays" in dev options. Reboot and check no "BOOT TIMEOUT" in log. Change-Id: Ie0890cd006da74f290ecc6cbcf1064a0b26de574 --- .../com/android/server/wm/DisplayContent.java | 66 ++++++++++--------- .../server/wm/WindowManagerService.java | 10 +-- .../server/wm/DisplayContentTests.java | 55 ++++++++++++++++ 3 files changed, 96 insertions(+), 35 deletions(-) diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 6fafa9f7360d5..6d9a00804e320 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -59,11 +59,10 @@ import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE; import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; -import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; @@ -169,6 +168,7 @@ import android.os.UserHandle; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Slog; +import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; import android.view.Display; import android.view.DisplayCutout; @@ -439,11 +439,6 @@ class DisplayContent extends WindowContainer mTapExcludeProvidingWindows = new ArraySet<>(); - private boolean mHaveBootMsg = false; - private boolean mHaveApp = false; - private boolean mHaveWallpaper = false; - private boolean mHaveKeyguard = true; - private final LinkedList mTmpUpdateAllDrawn = new LinkedList(); private final TaskForResizePointSearchResult mTmpTaskForResizePointSearchResult = @@ -3350,34 +3345,38 @@ class DisplayContent extends WindowContainer { - if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { + final WindowState visibleNotDrawnWindow = getWindow(w -> { + if (w.mViewVisibility == View.VISIBLE && !w.mObscured && !w.isDrawnLw()) { return true; } if (w.isDrawnLw()) { - if (w.mAttrs.type == TYPE_BOOT_PROGRESS) { - mHaveBootMsg = true; - } else if (w.mAttrs.type == TYPE_APPLICATION - || w.mAttrs.type == TYPE_DRAWN_APPLICATION) { - mHaveApp = true; - } else if (w.mAttrs.type == TYPE_WALLPAPER) { - mHaveWallpaper = true; - } else if (w.mAttrs.type == TYPE_STATUS_BAR) { - mHaveKeyguard = mWmService.mPolicy.isKeyguardDrawnLw(); + final int type = w.mAttrs.type; + if (type == TYPE_BOOT_PROGRESS || type == TYPE_BASE_APPLICATION + || type == TYPE_WALLPAPER) { + drawnWindowTypes.put(type, true); + } else if (type == TYPE_STATUS_BAR) { + drawnWindowTypes.put(TYPE_STATUS_BAR, mWmService.mPolicy.isKeyguardDrawnLw()); } } return false; }); - if (visibleWindow != null) { - // We have a visible window. + if (visibleNotDrawnWindow != null) { + // Wait for the visible window to be drawn. return true; } @@ -3389,22 +3388,27 @@ class DisplayContent extends WindowContainer= 0; i--) { + if (mRoot.getChildAt(i).shouldWaitForSystemDecorWindowsOnBoot()) { + return; + } + } } if (!mBootAnimationStopped) { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index ae4074275b97a..ade0b146dd9aa 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -39,6 +39,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; @@ -46,6 +47,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; import static com.android.dx.mockito.inline.extended.ExtendedMockito.same; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; @@ -396,6 +398,59 @@ public class DisplayContentTests extends WindowTestsBase { mWm.mRoot.getTopFocusedDisplayContent().getDisplayId()); } + @Test + public void testShouldWaitForSystemDecorWindowsOnBoot_OnDefaultDisplay() { + mWm.mSystemBooted = true; + final DisplayContent defaultDisplay = mWm.getDefaultDisplayContentLocked(); + final WindowState[] windows = createNotDrawnWindowsOn(defaultDisplay, + TYPE_WALLPAPER, TYPE_APPLICATION); + + // Verify waiting for windows to be drawn. + assertTrue(defaultDisplay.shouldWaitForSystemDecorWindowsOnBoot()); + + // Verify not waiting for drawn windows. + makeWindowsDrawn(windows); + assertFalse(defaultDisplay.shouldWaitForSystemDecorWindowsOnBoot()); + } + + @Test + public void testShouldWaitForSystemDecorWindowsOnBoot_OnSecondaryDisplay() { + mWm.mSystemBooted = true; + final DisplayContent secondaryDisplay = createNewDisplay(); + final WindowState[] windows = createNotDrawnWindowsOn(secondaryDisplay, + TYPE_WALLPAPER, TYPE_APPLICATION); + + // Verify not waiting for display without system decorations. + doReturn(false).when(secondaryDisplay).supportsSystemDecorations(); + assertFalse(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot()); + + // Verify waiting for non-drawn windows on display with system decorations. + reset(secondaryDisplay); + doReturn(true).when(secondaryDisplay).supportsSystemDecorations(); + assertTrue(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot()); + + // Verify not waiting for drawn windows on display with system decorations. + makeWindowsDrawn(windows); + assertFalse(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot()); + } + + private WindowState[] createNotDrawnWindowsOn(DisplayContent displayContent, int... types) { + final WindowState[] windows = new WindowState[types.length]; + for (int i = 0; i < types.length; i++) { + final int type = types[i]; + windows[i] = createWindow(null /* parent */, type, displayContent, "window-" + type); + windows[i].mHasSurface = false; + } + return windows; + } + + private static void makeWindowsDrawn(WindowState[] windows) { + for (WindowState window : windows) { + window.mHasSurface = true; + window.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; + } + } + /** * This tests setting the maximum ui width on a display. */