diff options
| author | 2019-07-26 23:37:25 -0600 | |
|---|---|---|
| committer | 2019-10-03 18:24:20 +0800 | |
| commit | b2297ad376a764db9f43a724ea21cfe310e39892 (patch) | |
| tree | 844c39b99267a47f298bfa07f6888a07ff7ba3b3 | |
| parent | b14c5166149192f090f2fe079843dc06499aae23 (diff) | |
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
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 6fafa9f7360d..6d9a00804e32 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<DisplayContent.DisplayChildWindowCo /** A collection of windows that provide tap exclude regions inside of them. */ final ArraySet<WindowState> mTapExcludeProvidingWindows = new ArraySet<>(); - private boolean mHaveBootMsg = false; - private boolean mHaveApp = false; - private boolean mHaveWallpaper = false; - private boolean mHaveKeyguard = true; - private final LinkedList<AppWindowToken> mTmpUpdateAllDrawn = new LinkedList(); private final TaskForResizePointSearchResult mTmpTaskForResizePointSearchResult = @@ -3350,34 +3345,38 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo }, true /* traverseTopToBottom */); } - boolean checkWaitingForWindows() { + /** @return {@code true} if there is window to wait before enabling the screen. */ + boolean shouldWaitForSystemDecorWindowsOnBoot() { + if (!isDefaultDisplay && !supportsSystemDecorations()) { + // Nothing to wait because the secondary display doesn't support system decorations, + // there is no wallpaper, keyguard (status bar) or application (home) window to show + // during booting. + return false; + } - mHaveBootMsg = false; - mHaveApp = false; - mHaveWallpaper = false; - mHaveKeyguard = true; + final SparseBooleanArray drawnWindowTypes = new SparseBooleanArray(); + // Presuppose keyguard is drawn because if its window isn't attached, we don't know if it + // wants to be shown or hidden, then it should not delay enabling the screen. + drawnWindowTypes.put(TYPE_STATUS_BAR, true); - final WindowState visibleWindow = getWindow(w -> { - 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<DisplayContent.DisplayChildWindowCo com.android.internal.R.bool.config_checkWallpaperAtBoot) && !mWmService.mOnlyCore; + final boolean haveBootMsg = drawnWindowTypes.get(TYPE_BOOT_PROGRESS); + final boolean haveApp = drawnWindowTypes.get(TYPE_BASE_APPLICATION); + final boolean haveWallpaper = drawnWindowTypes.get(TYPE_WALLPAPER); + final boolean haveKeyguard = drawnWindowTypes.get(TYPE_STATUS_BAR); + ProtoLog.i(WM_DEBUG_SCREEN_ON, - "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b " - + "wallEnabled=%b haveKeyguard=%b", - mWmService.mSystemBooted, mWmService.mShowingBootMessages, mHaveBootMsg, - mHaveApp, mHaveWallpaper, wallpaperEnabled, mHaveKeyguard); + "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b " + + "wallEnabled=%b haveKeyguard=%b", + mWmService.mSystemBooted, mWmService.mShowingBootMessages, haveBootMsg, + haveApp, haveWallpaper, wallpaperEnabled, haveKeyguard); // If we are turning on the screen to show the boot message, don't do it until the boot // message is actually displayed. - if (!mWmService.mSystemBooted && !mHaveBootMsg) { + if (!mWmService.mSystemBooted && !haveBootMsg) { return true; } // If we are turning on the screen after the boot is completed normally, don't do so until // we have the application and wallpaper. if (mWmService.mSystemBooted - && ((!mHaveApp && !mHaveKeyguard) || (wallpaperEnabled && !mHaveWallpaper))) { + && ((!haveApp && !haveKeyguard) || (wallpaperEnabled && !haveWallpaper))) { return true; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 38a22389d529..29c5a1ae913c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3290,10 +3290,12 @@ public class WindowManagerService extends IWindowManager.Stub } // Don't enable the screen until all existing windows have been drawn. - if (!mForceDisplayEnabled - // TODO(multidisplay): Expand to all displays? - && getDefaultDisplayContentLocked().checkWaitingForWindows()) { - return; + if (!mForceDisplayEnabled) { + for (int i = mRoot.getChildCount() - 1; i >= 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 ae4074275b97..ade0b146dd9a 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. */ |