From 9214704eac0af4b0d138a195bcea6fecef523ea5 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Mon, 9 May 2016 12:47:11 -0700 Subject: [PATCH] Fixes for restoring more than one child surfaces App may have more than one windows and subwindows. Remember which ones are visible at the last setAppVisibility time, and restore only those that was visible then. If the app itself requested to hide a window before that, we don't want to use the window for early animation. Also move mAnimatingWithSavedSurface into WindowState as it needs to be tracked per window. bug: 27455025 bug: 28296945 Change-Id: I3ed1879634fa7709de699d4518d8fcfc91a85554 --- .../android/server/wm/AppWindowAnimator.java | 3 +- .../com/android/server/wm/AppWindowToken.java | 58 ++++++++++++------ .../server/wm/WindowManagerService.java | 15 +++-- .../com/android/server/wm/WindowState.java | 60 +++++++++++++++++-- .../server/wm/WindowStateAnimator.java | 18 ++---- 5 files changed, 107 insertions(+), 47 deletions(-) diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java index 49dab0a668150..a37b65ab9b64b 100644 --- a/services/core/java/com/android/server/wm/AppWindowAnimator.java +++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java @@ -185,8 +185,7 @@ public class AppWindowAnimator { clearThumbnail(); setNullAnimation(); if (mAppToken.deferClearAllDrawn) { - mAppToken.allDrawn = false; - mAppToken.deferClearAllDrawn = false; + mAppToken.clearAllDrawn(); } mStackClip = STACK_CLIP_BEFORE_ANIM; } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index de613aaa94ad2..a23424175300a 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -27,6 +27,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION; +import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; @@ -65,10 +66,6 @@ class AppWindowToken extends WindowToken { final boolean voiceInteraction; - // Whether we're performing an entering animation with a saved surface. - boolean mAnimatingWithSavedSurface; - - Task mTask; boolean appFullscreen; int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -160,6 +157,13 @@ class AppWindowToken extends WindowToken { } } + void setVisibleBeforeClientHidden() { + for (int i = allAppWindows.size() - 1; i >= 0; i--) { + final WindowState w = allAppWindows.get(i); + w.setVisibleBeforeClientHidden(); + } + } + void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) { firstWindowDrawn = true; @@ -295,7 +299,7 @@ class AppWindowToken extends WindowToken { // If we're animating with a saved surface, we're already visible. // Return true so that the alpha doesn't get cleared. if (!win.mAppFreezing - && (win.mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface + && (win.mViewVisibility == View.VISIBLE || win.isAnimatingWithSavedSurface() || (win.mWinAnimator.isAnimationSet() && !service.mAppTransition.isTransitionSet())) && !win.mDestroying @@ -347,7 +351,6 @@ class AppWindowToken extends WindowToken { win.destroyOrSaveSurface(); if (win.mRemoveOnExit) { - win.mAnimatingExit = false; service.removeWindowInnerLocked(win); } final DisplayContent displayContent = win.getDisplayContent(); @@ -391,43 +394,56 @@ class AppWindowToken extends WindowToken { return allDrawn; } - boolean hasSavedSurface() { + boolean canRestoreSurfaces() { for (int i = allAppWindows.size() -1; i >= 0; i--) { - final WindowState ws = allAppWindows.get(i); - if (ws.hasSavedSurface()) { + final WindowState w = allAppWindows.get(i); + if (w.canRestoreSurface()) { return true; } } return false; } + void clearVisibleBeforeClientHidden() { + for (int i = allAppWindows.size() - 1; i >= 0; i--) { + final WindowState w = allAppWindows.get(i); + w.clearVisibleBeforeClientHidden(); + } + } + void restoreSavedSurfaces() { - if (!hasSavedSurface()) { + if (!canRestoreSurfaces()) { + clearVisibleBeforeClientHidden(); return; } - mAnimatingWithSavedSurface = true; - // Check if we have enough drawn windows to mark allDrawn= true. int numInteresting = 0; int numDrawn = 0; for (int i = allAppWindows.size() - 1; i >= 0; i--) { WindowState w = allAppWindows.get(i); - if (w.hasSavedSurface()) { - w.restoreSavedSurface(); - } - if (w != startingWindow && !w.mAppDied + if (w != startingWindow && !w.mAppDied && w.wasVisibleBeforeClientHidden() && (!mAppAnimator.freezingScreen || !w.mAppFreezing)) { numInteresting++; + if (w.hasSavedSurface()) { + w.restoreSavedSurface(); + } if (w.isDrawnLw()) { numDrawn++; } } } - allDrawn |= (numInteresting > 0) && (numInteresting == numDrawn); + if (!allDrawn) { + allDrawn = (numInteresting > 0) && (numInteresting == numDrawn); + if (allDrawn) { + service.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget(); + } + } + clearVisibleBeforeClientHidden(); if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG, - "restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn); + "restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn + + " numInteresting=" + numInteresting + " numDrawn=" + numDrawn); } void destroySavedSurfaces() { @@ -435,7 +451,11 @@ class AppWindowToken extends WindowToken { WindowState win = allAppWindows.get(i); win.destroySavedSurface(); } - mAnimatingWithSavedSurface = false; + } + + void clearAllDrawn() { + allDrawn = false; + deferClearAllDrawn = false; } @Override diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index be888fed80bcf..2fe7b8461afa5 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2170,7 +2170,7 @@ public class WindowManagerService extends IWindowManager.Stub * Returns true if we're done setting up any transitions. */ private boolean prepareWindowReplacementTransition(AppWindowToken atoken) { - atoken.allDrawn = false; + atoken.clearAllDrawn(); WindowState replacedWindow = null; for (int i = atoken.windows.size() - 1; i >= 0 && replacedWindow == null; i--) { WindowState candidate = atoken.windows.get(i); @@ -2316,7 +2316,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Preserving " + win + " until the new one is " + "added"); // TODO: We are overloading mAnimatingExit flag to prevent the window state from - // been removed. We probably need another falg to indicate that window removal + // been removed. We probably need another flag to indicate that window removal // should be deffered vs. overloading the flag that says we are playing an exit // animation. win.mAnimatingExit = true; @@ -2464,7 +2464,7 @@ public class WindowManagerService extends IWindowManager.Stub mTokenMap.remove(token.token); } else if (atoken != null) { atoken.firstWindowDrawn = false; - atoken.allDrawn = false; + atoken.clearAllDrawn(); } } @@ -4423,6 +4423,7 @@ public class WindowManagerService extends IWindowManager.Stub // Now that the app is going invisible, we can remove it. It will be restarted // if made visible again. wtoken.removeAllDeadWindows(); + wtoken.setVisibleBeforeClientHidden(); } else if (visible) { if (!mAppTransition.isTransitionSet() && mAppTransition.isReady()) { // Add the app mOpeningApps if transition is unset but ready. This means @@ -4434,8 +4435,7 @@ public class WindowManagerService extends IWindowManager.Stub // If the token is currently hidden (should be the common case), or has been // stopped, then we need to set up to wait for its windows to be ready. if (wtoken.hidden || wtoken.mAppStopped) { - wtoken.allDrawn = false; - wtoken.deferClearAllDrawn = false; + wtoken.clearAllDrawn(); // If the app was already visible, don't reset the waitingToShow state. if (wtoken.hidden) { @@ -9233,8 +9233,7 @@ public class WindowManagerService extends IWindowManager.Stub } winAnimator.mDrawState = DRAW_PENDING; if (w.mAppToken != null) { - w.mAppToken.allDrawn = false; - w.mAppToken.deferClearAllDrawn = false; + w.mAppToken.clearAllDrawn(); } } if (!mResizingWindows.contains(w)) { @@ -9391,7 +9390,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): " + ws + " surface=" + wsa.mSurfaceController + " token=" + ws.mAppToken - + " saved=" + ws.mAppToken.hasSavedSurface()); + + " saved=" + ws.hasSavedSurface()); if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false); wsa.destroySurface(); leakedSurface = true; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index a89b4aadafa61..b66de89f6a2d2 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -435,7 +435,15 @@ final class WindowState implements WindowManagerPolicy.WindowState { // Whether the window has a saved surface from last pause, which can be // used to start an entering animation earlier. - public boolean mSurfaceSaved = false; + private boolean mSurfaceSaved = false; + + // Whether we're performing an entering animation with a saved surface. + private boolean mAnimatingWithSavedSurface; + + // Whether the window was visible when we set the app to invisible last time. WM uses + // this as a hint to restore the surface (if available) for early animation next time + // the app is brought visible. + boolean mWasVisibleBeforeClientHidden; // This window will be replaced due to relaunch. This allows window manager // to differentiate between simple removal of a window and replacement. In the latter case it @@ -1949,7 +1957,20 @@ final class WindowState implements WindowManagerPolicy.WindowState { } boolean isAnimatingWithSavedSurface() { - return mAppToken != null && mAppToken.mAnimatingWithSavedSurface; + return mAnimatingWithSavedSurface; + } + + public void setVisibleBeforeClientHidden() { + mWasVisibleBeforeClientHidden |= + (mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface); + } + + public void clearVisibleBeforeClientHidden() { + mWasVisibleBeforeClientHidden = false; + } + + public boolean wasVisibleBeforeClientHidden() { + return mWasVisibleBeforeClientHidden; } private boolean shouldSaveSurface() { @@ -1958,6 +1979,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { return false; } + if (!mWasVisibleBeforeClientHidden) { + return false; + } + if ((mAttrs.flags & FLAG_SECURE) != 0) { // We don't save secure surfaces since their content shouldn't be shown while the app // isn't on screen and content might leak through during the transition animation with @@ -2020,18 +2045,22 @@ final class WindowState implements WindowManagerPolicy.WindowState { } else { mWinAnimator.destroySurfaceLocked(); } + // Clear animating flags now, since the surface is now gone. (Note this is true even + // if the surface is saved, to outside world the surface is still NO_SURFACE.) + mAnimatingExit = false; } - public void destroySavedSurface() { + void destroySavedSurface() { if (mSurfaceSaved) { if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { Slog.v(TAG, "Destroying saved surface: " + this); } mWinAnimator.destroySurfaceLocked(); } + mWasVisibleBeforeClientHidden = false; } - public void restoreSavedSurface() { + void restoreSavedSurface() { if (!mSurfaceSaved) { return; } @@ -2039,6 +2068,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (mWinAnimator.mSurfaceController != null) { setHasSurface(true); mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW; + mAnimatingWithSavedSurface = true; if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { Slog.v(TAG, "Restoring saved surface: " + this); @@ -2051,10 +2081,30 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } - public boolean hasSavedSurface() { + boolean canRestoreSurface() { + return mWasVisibleBeforeClientHidden && mSurfaceSaved; + } + + boolean hasSavedSurface() { return mSurfaceSaved; } + void clearHasSavedSurface() { + mSurfaceSaved = false; + mAnimatingWithSavedSurface = false; + mWasVisibleBeforeClientHidden = false; + } + + void clearAnimatingWithSavedSurface() { + if (mAnimatingWithSavedSurface) { + // App has drawn something to its windows, we're no longer animating with + // the saved surfaces. + if (DEBUG_ANIM) Slog.d(TAG, + "clearAnimatingWithSavedSurface(): win=" + this); + mAnimatingWithSavedSurface = false; + } + } + @Override public boolean isDefaultDisplay() { final DisplayContent displayContent = getDisplayContent(); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index f88e30b3c5e57..f0bba4a952d54 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -584,14 +584,8 @@ class WindowStateAnimator { + drawStateToString()); } - if (mWin.mAppToken != null && mWin.mAppToken.mAnimatingWithSavedSurface) { - // App has drawn something to its windows, we're no longer animating with - // the saved surfaces. If the user exits now, we only want to save again - // if allDrawn is true. - if (DEBUG_ANIM) Slog.d(TAG, - "finishDrawingLocked: mAnimatingWithSavedSurface=false " + mWin); - mWin.mAppToken.mAnimatingWithSavedSurface = false; - } + mWin.clearAnimatingWithSavedSurface(); + if (mDrawState == DRAW_PENDING) { if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + mWin + " in " @@ -687,8 +681,7 @@ class WindowStateAnimator { mDrawState = DRAW_PENDING; if (w.mAppToken != null) { if (w.mAppToken.mAppAnimator.animation == null) { - w.mAppToken.allDrawn = false; - w.mAppToken.deferClearAllDrawn = false; + w.mAppToken.clearAllDrawn(); } else { // Currently animating, persist current state of allDrawn until animation // is complete. @@ -840,20 +833,19 @@ class WindowStateAnimator { } boolean hasSurface() { - return !mWin.mSurfaceSaved + return !mWin.hasSavedSurface() && mSurfaceController != null && mSurfaceController.hasSurface(); } void destroySurfaceLocked() { final AppWindowToken wtoken = mWin.mAppToken; if (wtoken != null) { - wtoken.mAnimatingWithSavedSurface = false; if (mWin == wtoken.startingWindow) { wtoken.startingDisplayed = false; } } - mWin.mSurfaceSaved = false; + mWin.clearHasSavedSurface(); if (mSurfaceController == null) { return;