diff options
| author | 2018-01-11 15:43:49 +0100 | |
|---|---|---|
| committer | 2018-01-17 13:46:27 +0100 | |
| commit | 4876b4a273cdefaa7dfc11d5fdaa0ee5c9ea4055 (patch) | |
| tree | d7c733cb1a0e101ed7eae68bdd759f74ad5dec3c | |
| parent | 79131f7a227eb5f2bbd4e6ea29e14d834c634101 (diff) | |
Defer hiding clients until animation is done
This is a preparation for remote animations: We used to set app
visibility state immediately after we started the animation.
However, with remote animations, we'd like to allow them drawing
until the transition is done. For that, we defer hiding the client
until the animation is done.
Instead of special-casing remote animations, we do it for all
apps, as there is no harm in doing so.
Test: Open YouTube, make sure it enters Auto-PIP when pressing
home.
Test: go/wm-smoke
Test: Open trace with open/closing a couple of apps. Make sure
app visibility gets dispatched at the correct time.
Test: WindowStateTests
Bug: 64674361
Change-Id: I8deb6a97ca1c3d8f4a70a6e045f45a6bc16604bb
3 files changed, 38 insertions, 3 deletions
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index f2098dc3ce4f..0dfef3aa63e1 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -376,7 +376,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually // been set by the app now. mHiddenSetFromTransferredStartingWindow = false; - setClientHidden(!visible); // Allow for state changes and animation to be applied if: // * token is transitioning visibility state @@ -461,6 +460,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token); } + // Update the client visibility if we are not running an animation. Otherwise, we'll + // update client visibility state in onAnimationFinished. + if (!visible && !delayed) { + setClientHidden(true); + } + // If we are hidden but there is no delay needed we immediately // apply the Surface transaction so that the ActivityManager // can have some guarantee on the Surface state following @@ -1721,6 +1726,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree "AppWindowToken"); clearThumbnail(); + setClientHidden(isHidden()); if (mService.mInputMethodTarget != null && mService.mInputMethodTarget.mAppToken == this) { getDisplayContent().computeImeTarget(true /* updateImeTarget */); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 97070bd91451..46c5ceebd180 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -189,6 +189,7 @@ import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputWindowHandle; import com.android.server.policy.WindowManagerPolicy; @@ -198,7 +199,6 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Comparator; -import java.util.LinkedList; import java.util.function.Predicate; /** A window in the window manager. */ @@ -3923,6 +3923,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return null; } + /** + * @return True if we our one of our ancestors has {@link #mAnimatingExit} set to true, false + * otherwise. + */ + @VisibleForTesting + boolean isSelfOrAncestorWindowAnimatingExit() { + WindowState window = this; + do { + if (window.mAnimatingExit) { + return true; + } + window = window.getParentWindow(); + } while (window != null); + return false; + } + void onExitAnimationDone() { if (DEBUG_ANIM) Slog.v(TAG, "onExitAnimationDone in " + this + ": exiting=" + mAnimatingExit + " remove=" + mRemoveOnExit @@ -3958,7 +3974,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(); } - if (!mAnimatingExit) { + if (!isSelfOrAncestorWindowAnimatingExit()) { return; } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java index 7be203a99391..6a4710bb06a4 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java @@ -223,6 +223,19 @@ public class WindowStateTests extends WindowTestsBase { assertFalse(app.canAffectSystemUiFlags()); } + @Test + public void testIsSelfOrAncestorWindowAnimating() throws Exception { + final WindowState root = createWindow(null, TYPE_APPLICATION, "root"); + final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1"); + final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, "child2"); + assertFalse(child2.isSelfOrAncestorWindowAnimatingExit()); + child2.mAnimatingExit = true; + assertTrue(child2.isSelfOrAncestorWindowAnimatingExit()); + child2.mAnimatingExit = false; + root.mAnimatingExit = true; + assertTrue(child2.isSelfOrAncestorWindowAnimatingExit()); + } + private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) { final WindowState root = createWindow(null, TYPE_APPLICATION, "root"); root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; |