From 237028ae3be891dd1dbc392a51fd768474de5df7 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 26 Jul 2016 10:39:45 -0700 Subject: [PATCH] Only restore saved surfaces in the last visible rotation. Sometimes we see a sequence like this when transitioning between apps causes rotation changes. 1. New app becomes visible, causing the orientation to change 2. Old app gets marked as invisible, at this point its window are still visible from client, so surface is marked as eligible to be saved. 3. Old app calls relayout to invisible, we save surface. Now if we restore the Surface it will be in the wrong orientation. It never had a visible layout in the new one, it was just covered up by the screenshot. To address this we track the rotation a window was last visibily laid out in. If it doesn't match our current rotation we can't use the saved surface. Bug: 30171992 Change-Id: If814131810b6d01c5112afd145072a13a30b0401 --- .../server/wm/WindowManagerService.java | 3 +++ .../com/android/server/wm/WindowState.java | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8c5481d1a4d85..6451c7492fa82 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3081,6 +3081,9 @@ public class WindowManagerService extends IWindowManager.Stub if (oldVisibility == View.GONE) { winAnimator.mEnterAnimationPending = true; } + + win.mLastVisibleLayoutRotation = mRotation; + winAnimator.mEnteringAnimation = true; if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { win.prepareWindowToDisplayDuringRelayout(outConfig); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 25ad07ef07a76..155d8d05b1ffa 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -394,6 +394,13 @@ final class WindowState implements WindowManagerPolicy.WindowState { */ boolean mOrientationChanging; + /** + * The orientation during the last visible call to relayout. If our + * current orientation is different, the window can't be ready + * to be shown. + */ + int mLastVisibleLayoutRotation = -1; + /** * How long we last kept the screen frozen. */ @@ -2095,6 +2102,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { Slog.v(TAG, "Destroying saved surface: " + this); } mWinAnimator.destroySurfaceLocked(); + mSurfaceSaved = false; } mWasVisibleBeforeClientHidden = false; } @@ -2103,7 +2111,18 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (!mSurfaceSaved) { return; } + + // Sometimes we save surfaces due to layout invisible + // directly after rotation occurs. However this means + // the surface was never laid out in the new orientation. + // We can only restore to the last rotation we were + // laid out as visible in. + if (mLastVisibleLayoutRotation != mService.mRotation) { + destroySavedSurface(); + return; + } mSurfaceSaved = false; + if (mWinAnimator.mSurfaceController != null) { setHasSurface(true); mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;