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

Commit 9170b62c authored by Chris Li's avatar Chris Li Committed by Android (Google) Code Review
Browse files

Merge "Update ActivityEmbedding split open/close animation adapter for Shell" into tm-qpr-dev

parents 48bf8456 9b1f2e42
Loading
Loading
Loading
Loading
+37 −63
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.wm.shell.activityembedding;

import static android.graphics.Matrix.MSCALE_X;
import static android.graphics.Matrix.MTRANS_X;
import static android.graphics.Matrix.MTRANS_Y;

@@ -42,31 +41,45 @@ class ActivityEmbeddingAnimationAdapter {
     */
    private static final int LAYER_NO_OVERRIDE = -1;

    @NonNull
    final Animation mAnimation;
    @NonNull
    final TransitionInfo.Change mChange;
    @NonNull
    final SurfaceControl mLeash;
    /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
    @NonNull
    private final Rect mWholeAnimationBounds = new Rect();

    @NonNull
    final Transformation mTransformation = new Transformation();
    @NonNull
    final float[] mMatrix = new float[9];
    @NonNull
    final float[] mVecs = new float[4];
    @NonNull
    final Rect mRect = new Rect();
    private boolean mIsFirstFrame = true;
    private int mOverrideLayer = LAYER_NO_OVERRIDE;

    ActivityEmbeddingAnimationAdapter(@NonNull Animation animation,
            @NonNull TransitionInfo.Change change) {
        this(animation, change, change.getLeash());
        this(animation, change, change.getLeash(), change.getEndAbsBounds());
    }

    /**
     * @param leash the surface to animate, which is not necessary the same as
     *              {@link TransitionInfo.Change#getLeash()}, it can be a screenshot for example.
     * @param wholeAnimationBounds  area in absolute coordinate that the animation surface shouldn't
     *                              go beyond.
     */
    ActivityEmbeddingAnimationAdapter(@NonNull Animation animation,
            @NonNull TransitionInfo.Change change, @NonNull SurfaceControl leash) {
            @NonNull TransitionInfo.Change change, @NonNull SurfaceControl leash,
            @NonNull Rect wholeAnimationBounds) {
        mAnimation = animation;
        mChange = change;
        mLeash = leash;
        mWholeAnimationBounds.set(wholeAnimationBounds);
    }

    /**
@@ -96,23 +109,31 @@ class ActivityEmbeddingAnimationAdapter {

    /** To be overridden by subclasses to adjust the animation surface change. */
    void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
        // Update the surface position and alpha.
        final Point offset = mChange.getEndRelOffset();
        mTransformation.getMatrix().postTranslate(offset.x, offset.y);
        t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
        t.setAlpha(mLeash, mTransformation.getAlpha());
        // Get current animation position.

        // Get current surface bounds in absolute coordinate.
        // positionX/Y are in local coordinate, so minus the local offset to get the slide amount.
        final int positionX = Math.round(mMatrix[MTRANS_X]);
        final int positionY = Math.round(mMatrix[MTRANS_Y]);
        // The exiting surface starts at position: Change#getEndRelOffset() and moves with
        // positionX varying. Offset our crop region by the amount we have slided so crop
        // regions stays exactly on the original container in split.
        final int cropOffsetX = offset.x - positionX;
        final int cropOffsetY = offset.y - positionY;
        final Rect cropRect = new Rect();
        cropRect.set(mChange.getEndAbsBounds());
        // Because window crop uses absolute position.
        cropRect.offsetTo(0, 0);
        cropRect.offset(cropOffsetX, cropOffsetY);
        final Rect cropRect = new Rect(mChange.getEndAbsBounds());
        cropRect.offset(positionX - offset.x, positionY - offset.y);

        // Store the current offset of the surface top left from (0,0) in absolute coordinate.
        final int offsetX = cropRect.left;
        final int offsetY = cropRect.top;

        // Intersect to make sure the animation happens within the whole animation bounds.
        if (!cropRect.intersect(mWholeAnimationBounds)) {
            // Hide the surface when it is outside of the animation area.
            t.setAlpha(mLeash, 0);
        }

        // cropRect is in absolute coordinate, so we need to translate it to surface top left.
        cropRect.offset(-offsetX, -offsetY);
        t.setCrop(mLeash, cropRect);
    }

@@ -126,53 +147,6 @@ class ActivityEmbeddingAnimationAdapter {
        return mAnimation.computeDurationHint();
    }

    /**
     * Should be used when the {@link TransitionInfo.Change} is in split with others, and wants to
     * animate together as one. This adapter will offset the animation leash to make the animate of
     * two windows look like a single window.
     */
    static class SplitAdapter extends ActivityEmbeddingAnimationAdapter {
        private final boolean mIsLeftHalf;
        private final int mWholeAnimationWidth;

        /**
         * @param isLeftHalf whether this is the left half of the animation.
         * @param wholeAnimationWidth the whole animation windows width.
         */
        SplitAdapter(@NonNull Animation animation, @NonNull TransitionInfo.Change change,
                boolean isLeftHalf, int wholeAnimationWidth) {
            super(animation, change);
            mIsLeftHalf = isLeftHalf;
            mWholeAnimationWidth = wholeAnimationWidth;
            if (wholeAnimationWidth == 0) {
                throw new IllegalArgumentException("SplitAdapter must provide wholeAnimationWidth");
            }
        }

        @Override
        void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
            final Point offset = mChange.getEndRelOffset();
            float posX = offset.x;
            final float posY = offset.y;
            // This window is half of the whole animation window. Offset left/right to make it
            // look as one with the other half.
            mTransformation.getMatrix().getValues(mMatrix);
            final int changeWidth = mChange.getEndAbsBounds().width();
            final float scaleX = mMatrix[MSCALE_X];
            final float totalOffset = mWholeAnimationWidth * (1 - scaleX) / 2;
            final float curOffset = changeWidth * (1 - scaleX) / 2;
            final float offsetDiff = totalOffset - curOffset;
            if (mIsLeftHalf) {
                posX += offsetDiff;
            } else {
                posX -= offsetDiff;
            }
            mTransformation.getMatrix().postTranslate(posX, posY);
            t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
            t.setAlpha(mLeash, mTransformation.getAlpha());
        }
    }

    /**
     * Should be used for the animation of the snapshot of a {@link TransitionInfo.Change} that has
     * size change.
@@ -181,7 +155,7 @@ class ActivityEmbeddingAnimationAdapter {

        SnapshotAdapter(@NonNull Animation animation, @NonNull TransitionInfo.Change change,
                @NonNull SurfaceControl snapshotLeash) {
            super(animation, change, snapshotLeash);
            super(animation, change, snapshotLeash, change.getEndAbsBounds());
        }

        @Override
+4 −22
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
import android.util.Log;
@@ -169,15 +168,12 @@ class ActivityEmbeddingAnimationRunner {
        final Rect openingWholeScreenBounds = new Rect();
        final Rect closingWholeScreenBounds = new Rect();
        for (TransitionInfo.Change change : info.getChanges()) {
            final Rect bounds = new Rect(change.getEndAbsBounds());
            final Point offset = change.getEndRelOffset();
            bounds.offsetTo(offset.x, offset.y);
            if (Transitions.isOpeningType(change.getMode())) {
                openingChanges.add(change);
                openingWholeScreenBounds.union(bounds);
                openingWholeScreenBounds.union(change.getEndAbsBounds());
            } else {
                closingChanges.add(change);
                closingWholeScreenBounds.union(bounds);
                closingWholeScreenBounds.union(change.getEndAbsBounds());
            }
        }

@@ -210,22 +206,8 @@ class ActivityEmbeddingAnimationRunner {
            @NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider,
            @NonNull Rect wholeAnimationBounds) {
        final Animation animation = animationProvider.apply(change, wholeAnimationBounds);
        final Rect bounds = new Rect(change.getEndAbsBounds());
        final Point offset = change.getEndRelOffset();
        bounds.offsetTo(offset.x, offset.y);
        if (bounds.left == wholeAnimationBounds.left
                && bounds.right != wholeAnimationBounds.right) {
            // This is the left split of the whole animation window.
            return new ActivityEmbeddingAnimationAdapter.SplitAdapter(animation, change,
                    true /* isLeftHalf */, wholeAnimationBounds.width());
        } else if (bounds.left != wholeAnimationBounds.left
                && bounds.right == wholeAnimationBounds.right) {
            // This is the right split of the whole animation window.
            return new ActivityEmbeddingAnimationAdapter.SplitAdapter(animation, change,
                    false /* isLeftHalf */, wholeAnimationBounds.width());
        }
        // Open/close window that fills the whole animation.
        return new ActivityEmbeddingAnimationAdapter(animation, change);
        return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(),
                wholeAnimationBounds);
    }

    @NonNull
+8 −4
Original line number Diff line number Diff line
@@ -185,8 +185,10 @@ class ActivityEmbeddingAnimationSpec {
        animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
                ? R.anim.task_fragment_open_enter
                : R.anim.task_fragment_open_exit);
        final Rect bounds = change.getEndAbsBounds();
        animation.initialize(bounds.width(), bounds.height(),
        // Use the whole animation bounds instead of the change bounds, so that when multiple change
        // targets are opening at the same time, the animation applied to each will be the same.
        // Otherwise, we may see gap between the activities that are launching together.
        animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
                wholeAnimationBounds.width(), wholeAnimationBounds.height());
        animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
        return animation;
@@ -203,8 +205,10 @@ class ActivityEmbeddingAnimationSpec {
        animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
                ? R.anim.task_fragment_close_enter
                : R.anim.task_fragment_close_exit);
        final Rect bounds = change.getEndAbsBounds();
        animation.initialize(bounds.width(), bounds.height(),
        // Use the whole animation bounds instead of the change bounds, so that when multiple change
        // targets are closing at the same time, the animation applied to each will be the same.
        // Otherwise, we may see gap between the activities that are finishing together.
        animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
                wholeAnimationBounds.width(), wholeAnimationBounds.height());
        animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
        return animation;