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

Commit 31634ca8 authored by Matt Sziklay's avatar Matt Sziklay Committed by Android (Google) Code Review
Browse files

Merge "Handle close transitions for freeform tasks." into udc-qpr-dev

parents ebb7640f aa5f0073
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TabletopModeController;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.desktopmode.DesktopModeController;
@@ -264,8 +265,13 @@ public abstract class WMShellModule {
    static FreeformTaskTransitionHandler provideFreeformTaskTransitionHandler(
            ShellInit shellInit,
            Transitions transitions,
            WindowDecorViewModel windowDecorViewModel) {
        return new FreeformTaskTransitionHandler(shellInit, transitions, windowDecorViewModel);
            Context context,
            WindowDecorViewModel windowDecorViewModel,
            DisplayController displayController,
            @ShellMainThread ShellExecutor mainExecutor,
            @ShellAnimationThread ShellExecutor animExecutor) {
        return new FreeformTaskTransitionHandler(shellInit, transitions, context,
                windowDecorViewModel, displayController, mainExecutor, animExecutor);
    }

    @WMSingleton
+94 −10
Original line number Diff line number Diff line
@@ -19,9 +19,15 @@ package com.android.wm.shell.freeform;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
import android.content.Context;
import android.graphics.Rect;
import android.os.IBinder;
import android.util.ArrayMap;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
@@ -31,6 +37,8 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
@@ -39,23 +47,37 @@ import java.util.ArrayList;
import java.util.List;

/**
 * The {@link Transitions.TransitionHandler} that handles freeform task maximizing and restoring
 * transitions.
 * The {@link Transitions.TransitionHandler} that handles freeform task maximizing, closing, and
 * restoring transitions.
 */
public class FreeformTaskTransitionHandler
        implements Transitions.TransitionHandler, FreeformTaskTransitionStarter {

    private static final int CLOSE_ANIM_DURATION = 400;
    private final Context mContext;
    private final Transitions mTransitions;
    private final WindowDecorViewModel mWindowDecorViewModel;
    private final DisplayController mDisplayController;
    private final ShellExecutor mMainExecutor;
    private final ShellExecutor mAnimExecutor;

    private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();

    private final ArrayMap<IBinder, ArrayList<Animator>> mAnimations = new ArrayMap<>();

    public FreeformTaskTransitionHandler(
            ShellInit shellInit,
            Transitions transitions,
            WindowDecorViewModel windowDecorViewModel) {
            Context context,
            WindowDecorViewModel windowDecorViewModel,
            DisplayController displayController,
            ShellExecutor mainExecutor,
            ShellExecutor animExecutor) {
        mTransitions = transitions;
        mContext = context;
        mWindowDecorViewModel = windowDecorViewModel;
        mDisplayController = displayController;
        mMainExecutor = mainExecutor;
        mAnimExecutor = animExecutor;
        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            shellInit.addInitCallback(this::onInit, this);
        }
@@ -103,6 +125,14 @@ public class FreeformTaskTransitionHandler
            @NonNull SurfaceControl.Transaction finishT,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        boolean transitionHandled = false;
        final ArrayList<Animator> animations = new ArrayList<>();
        final Runnable onAnimFinish = () -> {
            if (!animations.isEmpty()) return;
            mMainExecutor.execute(() -> {
                mAnimations.remove(transition);
                finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
            });
        };
        for (TransitionInfo.Change change : info.getChanges()) {
            if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) {
                continue;
@@ -121,21 +151,45 @@ public class FreeformTaskTransitionHandler
                case WindowManager.TRANSIT_TO_BACK:
                    transitionHandled |= startMinimizeTransition(transition);
                    break;
                case WindowManager.TRANSIT_CLOSE:
                    if (change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_FREEFORM) {
                        transitionHandled |= startCloseTransition(transition, change,
                                finishT, animations, onAnimFinish);
                    }
                    break;
            }
        }

        mPendingTransitionTokens.remove(transition);

        if (!transitionHandled) {
            return false;
        }

        mAnimations.put(transition, animations);
        // startT must be applied before animations start.
        startT.apply();
        mTransitions.getMainExecutor().execute(
                () -> finishCallback.onTransitionFinished(null, null));
        mAnimExecutor.execute(() -> {
            for (Animator anim : animations) {
                anim.start();
            }
        });
        // Run this here in case no animators are created.
        onAnimFinish.run();
        mPendingTransitionTokens.remove(transition);
        return true;
    }

    @Override
    public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        ArrayList<Animator> animations = mAnimations.get(mergeTarget);
        if (animations == null) return;
        mAnimExecutor.execute(() -> {
            for (Animator anim : animations) {
                anim.end();
            }
        });

    }

    private boolean startChangeTransition(
            IBinder transition,
            int type,
@@ -165,6 +219,36 @@ public class FreeformTaskTransitionHandler
        return mPendingTransitionTokens.contains(transition);
    }

    private boolean startCloseTransition(IBinder transition, TransitionInfo.Change change,
            SurfaceControl.Transaction finishT, ArrayList<Animator> animations,
            Runnable onAnimFinish) {
        if (!mPendingTransitionTokens.contains(transition)) return false;
        int screenHeight = mDisplayController
                .getDisplayLayout(change.getTaskInfo().displayId).height();
        ValueAnimator animator = new ValueAnimator();
        animator.setDuration(CLOSE_ANIM_DURATION)
                .setFloatValues(0f, 1f);
        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        SurfaceControl sc = change.getLeash();
        finishT.hide(sc);
        Rect startBounds = new Rect(change.getTaskInfo().configuration.windowConfiguration
                .getBounds());
        animator.addUpdateListener(animation -> {
            t.setPosition(sc, startBounds.left,
                    startBounds.top + (animation.getAnimatedFraction() * screenHeight));
            t.apply();
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                animations.remove(animator);
                onAnimFinish.run();
            }
        });
        animations.add(animator);
        return true;
    }

    @Nullable
    @Override
    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,