Merge "Fix a flicker when window is removed during entering animation" into nyc-dev
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index e490a40..abbb5f4 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 @@
// 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 @@
}
}
+ /**
+ * 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 @@
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 eae7838..be060d2 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 @@
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 7bdd1b3..8fa9efb 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 @@
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 @@
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 @@
}
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 b66de89..c9d945a 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 @@
// 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 @@
}
/**
+ * 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 @@
return mAnimatingWithSavedSurface;
}
+ boolean isAnimatingInvisibleWithSavedSurface() {
+ return mAnimatingWithSavedSurface
+ && (mViewVisibility != View.VISIBLE || mWindowRemovalAllowed);
+ }
+
public void setVisibleBeforeClientHidden() {
mWasVisibleBeforeClientHidden |=
(mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface);
@@ -2042,6 +2075,7 @@
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 e20e245..7e9993d 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 @@
+ " 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 @@
}
}
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 @@
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 @@
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);
+ }
+ }
+ }
}
}
}