diff options
| author | 2016-05-13 01:58:51 +0000 | |
|---|---|---|
| committer | 2016-05-13 01:58:52 +0000 | |
| commit | a285fdeb160e822a2e1fe2fb6bd80ce91afcf181 (patch) | |
| tree | 398c8926378355c66588fff18b01f0f1d63d2bb5 | |
| parent | 36d1296cf4f074599015b424161402f9b07da8ab (diff) | |
| parent | 8e4bda9e0f7411a3bfad0c625177f67248ff8a12 (diff) | |
Merge "Fix a flicker when window is removed during entering animation" into nyc-dev
5 files changed, 149 insertions, 7 deletions
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index e490a4030644..abbb5f48c606 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -88,6 +88,11 @@ class AppWindowToken extends WindowToken { // case do not clear allDrawn until the animation completes. boolean deferClearAllDrawn; + // These are to track the app's real drawing status if there were no saved surfaces. + boolean allDrawnExcludingSaved; + int numInterestingWindowsExcludingSaved; + int numDrawnWindowsExclusingSaved; + // Is this window's surface needed? This is almost like hidden, except // it will sometimes be true a little earlier: when the token has // been shown, but is still waiting for its app transition to execute @@ -411,6 +416,39 @@ class AppWindowToken extends WindowToken { } } + /** + * Whether the app has some window that is invisible in layout, but + * animating with saved surface. + */ + boolean isAnimatingInvisibleWithSavedSurface() { + for (int i = allAppWindows.size() - 1; i >= 0; i--) { + final WindowState w = allAppWindows.get(i); + if (w.isAnimatingInvisibleWithSavedSurface()) { + return true; + } + } + return false; + } + + /** + * Hide all window surfaces that's still invisible in layout but animating + * with a saved surface, and mark them destroying. + */ + void stopUsingSavedSurfaceLocked() { + for (int i = allAppWindows.size() - 1; i >= 0; i--) { + final WindowState w = allAppWindows.get(i); + if (w.isAnimatingInvisibleWithSavedSurface()) { + if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG, + "stopUsingSavedSurfaceLocked: " + w); + w.clearAnimatingWithSavedSurface(); + w.mDestroying = true; + w.mWinAnimator.hide("stopUsingSavedSurfaceLocked"); + w.mWinAnimator.mWallpaperControllerLocked.hideWallpapers(w); + } + } + destroySurfaces(); + } + void restoreSavedSurfaces() { if (!canRestoreSurfaces()) { clearVisibleBeforeClientHidden(); @@ -456,6 +494,7 @@ class AppWindowToken extends WindowToken { void clearAllDrawn() { allDrawn = false; deferClearAllDrawn = false; + allDrawnExcludingSaved = false; } @Override diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index eae783881c9f..be060d243404 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -788,6 +788,7 @@ public class WindowAnimator { removeReplacedWindowsLocked(); } + mService.stopUsingSavedSurfaceLocked(); mService.destroyPreservedSurfaceLocked(); mService.mWindowPlacerLocked.destroyPendingSurfaces(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7bdd1b3c76ec..8fa9efbda182 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -415,6 +415,13 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>(); /** + * List of window tokens that have finished drawing their own windows and + * no longer need to show any saved surfaces. Windows that's still showing + * saved surfaces will be cleaned up after next animation pass. + */ + final ArrayList<AppWindowToken> mFinishedEarlyAnim = new ArrayList<>(); + + /** * List of app window tokens that are waiting for replacing windows. If the * replacement doesn't come in time the stale windows needs to be disposed of. */ @@ -2330,6 +2337,23 @@ public class WindowManagerService extends IWindowManager.Stub Binder.restoreCallingIdentity(origId); return; } + + if (win.isAnimatingWithSavedSurface() && !appToken.allDrawnExcludingSaved) { + // We started enter animation early with a saved surface, now the app asks to remove + // this window. If we remove it now and the app is not yet drawn, we'll show a + // flicker. Delay the removal now until it's really drawn. + if (DEBUG_ADD_REMOVE) { + Slog.d(TAG_WM, "removeWindowLocked: delay removal of " + win + + " due to early animation"); + } + // Do not set mAnimatingExit to true here, it will cause the surface to be hidden + // immediately after the enter animation is done. If the app is not yet drawn then + // it will show up as a flicker. + win.mRemoveOnExit = true; + win.mWindowRemovalAllowed = true; + Binder.restoreCallingIdentity(origId); + return; + } // If we are not currently running the exit animation, we need to see about starting one wasVisible = win.isWinVisibleLw(); @@ -8560,6 +8584,15 @@ public class WindowManagerService extends IWindowManager.Stub } mDestroyPreservedSurface.clear(); } + + void stopUsingSavedSurfaceLocked() { + for (int i = mFinishedEarlyAnim.size() - 1; i >= 0 ; i--) { + final AppWindowToken wtoken = mFinishedEarlyAnim.get(i); + wtoken.stopUsingSavedSurfaceLocked(); + } + mFinishedEarlyAnim.clear(); + } + // ------------------------------------------------------------- // IWindowManager API // ------------------------------------------------------------- diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index b66de89f6a2d..c9d945aa73ac 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -437,7 +437,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { // used to start an entering animation earlier. private boolean mSurfaceSaved = false; - // Whether we're performing an entering animation with a saved surface. + // Whether we're performing an entering animation with a saved surface. This flag is + // true during the time we're showing a window with a previously saved surface. It's + // cleared when surface is destroyed, saved, or re-drawn by the app. private boolean mAnimatingWithSavedSurface; // Whether the window was visible when we set the app to invisible last time. WM uses @@ -1256,6 +1258,32 @@ final class WindowState implements WindowManagerPolicy.WindowState { } /** + * Whether this window's drawn state might affect the drawn states of the app token. + * + * @param visibleOnly Whether we should consider only the windows that's currently + * visible in layout. If true, windows that has not relayout to VISIBLE + * would always return false. + * + * @return true if the window should be considered while evaluating allDrawn flags. + */ + boolean mightAffectAllDrawn(boolean visibleOnly) { + final boolean isViewVisible = (mViewVisibility == View.VISIBLE) + && (mAppToken == null || !mAppToken.clientHidden); + return (isOnScreenIgnoringKeyguard() && (!visibleOnly || isViewVisible) + || mWinAnimator.mAttrType == TYPE_BASE_APPLICATION) + && !mAnimatingExit && !mDestroying; + } + + /** + * Whether this window is "interesting" when evaluating allDrawn. If it's interesting, + * it must be drawn before allDrawn can become true. + */ + boolean isInteresting() { + return mAppToken != null && !mAppDied + && (!mAppToken.mAppAnimator.freezingScreen || !mAppFreezing); + } + + /** * Like isOnScreen(), but we don't return true if the window is part * of a transition that has not yet been started. */ @@ -1960,6 +1988,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { return mAnimatingWithSavedSurface; } + boolean isAnimatingInvisibleWithSavedSurface() { + return mAnimatingWithSavedSurface + && (mViewVisibility != View.VISIBLE || mWindowRemovalAllowed); + } + public void setVisibleBeforeClientHidden() { mWasVisibleBeforeClientHidden |= (mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface); @@ -2042,6 +2075,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (mWinAnimator.mSurfaceController != null) { mWinAnimator.mSurfaceController.disconnectInTransaction(); } + mAnimatingWithSavedSurface = false; } else { mWinAnimator.destroySurfaceLocked(); } diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index e20e245aa574..7e9993db4cb4 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -792,15 +792,16 @@ class WindowSurfacePlacer { + " isOnScreen=" + w.isOnScreen() + " allDrawn=" + atoken.allDrawn + " freezingScreen=" + atoken.mAppAnimator.freezingScreen); } - if (atoken != null && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) { + if (atoken != null && (!atoken.allDrawn || !atoken.allDrawnExcludingSaved + || atoken.mAppAnimator.freezingScreen)) { if (atoken.lastTransactionSequence != mService.mTransactionSequence) { atoken.lastTransactionSequence = mService.mTransactionSequence; atoken.numInterestingWindows = atoken.numDrawnWindows = 0; + atoken.numInterestingWindowsExcludingSaved = 0; + atoken.numDrawnWindowsExclusingSaved = 0; atoken.startingDisplayed = false; } - if ((w.isOnScreenIgnoringKeyguard() - || winAnimator.mAttrType == TYPE_BASE_APPLICATION) - && !w.mAnimatingExit && !w.mDestroying) { + if (!atoken.allDrawn && w.mightAffectAllDrawn(false /* visibleOnly */)) { if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) { Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw() @@ -816,13 +817,14 @@ class WindowSurfacePlacer { } } if (w != atoken.startingWindow) { - if (!w.mAppDied && - (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing)) { + if (w.isInteresting()) { atoken.numInterestingWindows++; if (w.isDrawnLw()) { atoken.numDrawnWindows++; if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: " + atoken + + " w=" + w + " numInteresting=" + + atoken.numInterestingWindows + " freezingScreen=" + atoken.mAppAnimator.freezingScreen + " mAppFreezing=" + w.mAppFreezing); @@ -834,6 +836,23 @@ class WindowSurfacePlacer { atoken.startingDisplayed = true; } } + if (!atoken.allDrawnExcludingSaved + && w.mightAffectAllDrawn(true /* visibleOnly */)) { + if (w != atoken.startingWindow && w.isInteresting()) { + atoken.numInterestingWindowsExcludingSaved++; + if (w.isDrawnLw() && !w.isAnimatingWithSavedSurface()) { + atoken.numDrawnWindowsExclusingSaved++; + if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) + Slog.v(TAG, "tokenMayBeDrawnExcludingSaved: " + atoken + + " w=" + w + " numInteresting=" + + atoken.numInterestingWindowsExcludingSaved + + " freezingScreen=" + + atoken.mAppAnimator.freezingScreen + + " mAppFreezing=" + w.mAppFreezing); + updateAllDrawn = true; + } + } + } } if (isDefaultDisplay && someoneLosingFocus && w == mService.mCurrentFocus @@ -1539,6 +1558,22 @@ class WindowSurfacePlacer { wtoken.token).sendToTarget(); } } + if (!wtoken.allDrawnExcludingSaved) { + int numInteresting = wtoken.numInterestingWindowsExcludingSaved; + if (numInteresting > 0 + && wtoken.numDrawnWindowsExclusingSaved >= numInteresting) { + if (DEBUG_VISIBILITY) + Slog.v(TAG, "allDrawnExcludingSaved: " + wtoken + + " interesting=" + numInteresting + + " drawn=" + wtoken.numDrawnWindowsExclusingSaved); + wtoken.allDrawnExcludingSaved = true; + displayContent.layoutNeeded = true; + if (wtoken.isAnimatingInvisibleWithSavedSurface() + && !mService.mFinishedEarlyAnim.contains(wtoken)) { + mService.mFinishedEarlyAnim.add(wtoken); + } + } + } } } } |