Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4876b4a2 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

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
parent 79131f7a
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -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 */);
+18 −2
Original line number Diff line number Diff line
@@ -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;
        }

+13 −0
Original line number Diff line number Diff line
@@ -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;