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

Commit d8e7e0af authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

Merge "Ensure finish callbacks are called after all animations finish in...

Merge "Ensure finish callbacks are called after all animations finish in SplitDecorManager" into main
parents 05e2d321 7ed65254
Loading
Loading
Loading
Loading
+65 −25
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Binder;
import android.util.Log;
import android.view.IWindow;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
@@ -50,12 +51,15 @@ import android.widget.FrameLayout;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.SurfaceUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

/**
@@ -108,6 +112,14 @@ public class SplitDecorManager extends WindowlessWindowManager {
    private int mOffsetX;
    private int mOffsetY;
    private int mRunningAnimationCount = 0;
    /**
     * Keeps track of all finish callbacks meant to be executed after all animations are finished.
     * Do not add null values.
     * <p>
     * Maps a callback to the value meant to be passed in the callback. Default value to be passed
     * to the callback is false.
     */
    private final Map<Consumer<Boolean>, Boolean> mAnimFinishCallbacks = new HashMap<>();

    public SplitDecorManager(Configuration configuration, IconProvider iconProvider) {
        super(configuration, null /* rootSurface */, null /* hostInputToken */);
@@ -325,11 +337,14 @@ public class SplitDecorManager extends WindowlessWindowManager {
    }

    /** Stops showing resizing hint. */
    public void onResized(SurfaceControl.Transaction t, Consumer<Boolean> animFinishedCallback) {
    public void onResized(SurfaceControl.Transaction t,
            @Nullable Consumer<Boolean> animFinishedCallback) {
        if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
            mScreenshotAnimator.cancel();
        }

        if (animFinishedCallback != null) {
            mAnimFinishCallbacks.put(animFinishedCallback, false);
        }
        if (mScreenshot != null) {
            t.setPosition(mScreenshot, mOffsetX, mOffsetY);

@@ -354,19 +369,14 @@ public class SplitDecorManager extends WindowlessWindowManager {
                    animT.apply();
                    animT.close();
                    mScreenshot = null;

                    if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
                        animFinishedCallback.accept(true);
                    }
                    updateCallbackStatus(true /*callbackStatus*/, animFinishedCallback);
                }
            });
            mScreenshotAnimator.start();
        }

        if (mVeilIconView == null) {
            if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
                animFinishedCallback.accept(false);
            }
            updateCallbackStatus(false /*callbackStatus*/, animFinishedCallback);
            return;
        }

@@ -386,27 +396,54 @@ public class SplitDecorManager extends WindowlessWindowManager {
                        releaseDecor(finishT);
                        finishT.apply();
                        finishT.close();
                        if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
                            animFinishedCallback.accept(true);
                        }
                        updateCallbackStatus(true /*callbackStatus*/, animFinishedCallback);
                    }
                });
                return;
            }
        }
        if (mShown) {
            fadeOutDecor(()-> {
                if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
                    animFinishedCallback.accept(true);
            if (animFinishedCallback != null) {
                // Update to return true. Will be executed when fadeOutDecor anims finish
                mAnimFinishCallbacks.put(animFinishedCallback, true);
            }
            }, false /* addDelay */);
            fadeOutDecor(()-> {}, false /* addDelay */);
        } else {
            // Decor surface is hidden so release it directly.
            releaseDecor(t);
            if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
                animFinishedCallback.accept(false);
            updateCallbackStatus(false /*callbackStatus*/, animFinishedCallback);
        }
    }

    /**
     * Updates the value for the provided {@param callback} and optionally executes the callback
     * list if no animations are in progress.
     *
     * @param callbackStatus the parameter that will be passed into the {@param callback}
     * @param callback       no-op if null, must be added to {@link #mAnimFinishCallbacks} prior to
     *                       updating via this method
     */
    private void updateCallbackStatus(boolean callbackStatus,
            @Nullable Consumer<Boolean> callback) {
        if (callback == null) {
            return;
        }
        if (mAnimFinishCallbacks.get(callback) == null) {
            Log.e(TAG, "Finish callback not found!");
            return;
        }

        mAnimFinishCallbacks.put(callback, callbackStatus);
        if (mRunningAnimationCount != 0) {
            // Not all animations finished, wait
            return;
        }

        // Run all finish callbacks
        for (Map.Entry<Consumer<Boolean>, Boolean> c : mAnimFinishCallbacks.entrySet()) {
            c.getKey().accept(c.getValue());
        }
        mAnimFinishCallbacks.clear();
    }

    /**
@@ -553,8 +590,14 @@ public class SplitDecorManager extends WindowlessWindowManager {
     *                 time to redraw.
     */
    private void startFadeAnimation(boolean show, boolean releaseSurface,
            Runnable finishedCallback, boolean addDelay) {
            @Nullable Runnable finishedCallback, boolean addDelay) {
        final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
        final Consumer<Boolean> wrappedFinishCallback = aBoolean -> {
            if (finishedCallback != null) {
                finishedCallback.run();
            }
        };
        mAnimFinishCallbacks.put(wrappedFinishCallback, false);

        mFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
        if (addDelay) {
@@ -600,10 +643,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
                }
                animT.apply();
                animT.close();

                if (mRunningAnimationCount == 0 && finishedCallback != null) {
                    finishedCallback.run();
                }
                updateCallbackStatus(true /*callbackStatus*/, wrappedFinishCallback);
            }
        });
        mFadeAnimator.start();