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

Commit 6dcf142f authored by android-build-team Robot's avatar android-build-team Robot Committed by Android (Google) Code Review
Browse files

Merge "Fixing task open animation in split screen mode" into ub-launcher3-edmonton

parents fbf972e0 5fdd300e
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.views.RecentsView;
@@ -233,12 +234,16 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
            return false;
        }

        ClipAnimationHelper helper = new ClipAnimationHelper();
        target.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets, helper)
                .setDuration(RECENTS_LAUNCH_DURATION));

        Animator childStateAnimation = null;
        // Found a visible recents task that matches the opening app, lets launch the app from there
        Animator launcherAnim;
        final AnimatorListenerAdapter windowAnimEndListener;
        if (launcherClosing) {
            launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
            launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView, helper);
            launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
            launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);

@@ -258,9 +263,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
                }
            };
        }

        target.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets)
                .setDuration(RECENTS_LAUNCH_DURATION));
        target.play(launcherAnim);

        // Set the current animation first, before adding windowAnimEndListener. Setting current
+4 −2
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsRootView;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityOptionsCompat;
@@ -193,13 +194,14 @@ public class RecentsActivity extends BaseDraggingActivity {
            RemoteAnimationTargetCompat[] targets) {
        AnimatorSet target = new AnimatorSet();
        boolean activityClosing = taskIsATargetWithMode(targets, getTaskId(), MODE_CLOSING);
        target.play(getRecentsWindowAnimator(taskView, !activityClosing, targets)
        ClipAnimationHelper helper = new ClipAnimationHelper();
        target.play(getRecentsWindowAnimator(taskView, !activityClosing, targets, helper)
                .setDuration(RECENTS_LAUNCH_DURATION));

        // Found a visible recents task that matches the opening app, lets launch the app from there
        if (activityClosing) {
            Animator adjacentAnimation = mFallbackRecentsView
                    .createAdjacentPageAnimForTaskLaunch(taskView);
                    .createAdjacentPageAnimForTaskLaunch(taskView, helper);
            adjacentAnimation.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
            adjacentAnimation.setDuration(RECENTS_LAUNCH_DURATION);
            adjacentAnimation.addListener(new AnimatorListenerAdapter() {
+0 −117
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.quickstep;

import android.graphics.Rect;

import com.android.launcher3.Utilities;

/**
 * Helper class to interpolate the animation between a task view representation and an actual
 * window.
 */
public class RecentsAnimationInterpolator {

    public static class TaskWindowBounds {
        public float taskScale = 1f;
        public float taskX = 0f;
        public float taskY = 0f;

        public float winScale = 1f;
        public float winX = 0f;
        public float winY = 0f;
        public Rect winCrop = new Rect();

        @Override
        public String toString() {
            return "taskScale=" + taskScale + " taskX=" + taskX + " taskY=" + taskY
                    + " winScale=" + winScale + " winX=" + winX + " winY=" + winY
                    + " winCrop=" + winCrop;
        }
    }

    private TaskWindowBounds mTmpTaskWindowBounds = new TaskWindowBounds();
    private Rect mTmpInsets = new Rect();

    private Rect mWindow;
    private Rect mInsetWindow;
    private Rect mInsets;
    private Rect mTask;
    private Rect mTaskInsets;
    private Rect mThumbnail;

    private float mInitialTaskScale;
    private float mInitialTaskTranslationX;
    private float mFinalTaskScale;
    private Rect mScaledTask;
    private Rect mTargetTask;
    private Rect mSrcWindow;

    public RecentsAnimationInterpolator(Rect window, Rect insets, Rect task, Rect taskInsets,
            float taskScale, float taskTranslationX) {
        mWindow = window;
        mInsets = insets;
        mTask = task;
        mTaskInsets = taskInsets;
        mInsetWindow = new Rect(window);
        Utilities.insetRect(mInsetWindow, insets);

        mThumbnail = new Rect(task);
        Utilities.insetRect(mThumbnail, taskInsets);
        mInitialTaskScale = taskScale;
        mInitialTaskTranslationX = taskTranslationX;
        mFinalTaskScale = (float) mInsetWindow.width() / mThumbnail.width();
        mScaledTask = new Rect(task);
        Utilities.scaleRectAboutCenter(mScaledTask, mFinalTaskScale);
        Rect finalScaledTaskInsets = new Rect(taskInsets);
        Utilities.scaleRect(finalScaledTaskInsets, mFinalTaskScale);
        mTargetTask = new Rect(mInsetWindow);
        mTargetTask.offsetTo(window.left + insets.left - finalScaledTaskInsets.left,
                window.top + insets.top - finalScaledTaskInsets.top);

        float initialWinScale = 1f / mFinalTaskScale;
        Rect scaledWindow = new Rect(mInsetWindow);
        Utilities.scaleRectAboutCenter(scaledWindow, initialWinScale);
        Rect scaledInsets = new Rect(insets);
        Utilities.scaleRect(scaledInsets, initialWinScale);
        mSrcWindow = new Rect(scaledWindow);
        mSrcWindow.offsetTo(mThumbnail.left - scaledInsets.left,
                mThumbnail.top - scaledInsets.top);
    }

    public TaskWindowBounds interpolate(float t) {
        mTmpTaskWindowBounds.taskScale = Utilities.mapRange(t,
                mInitialTaskScale, mFinalTaskScale);
        mTmpTaskWindowBounds.taskX = Utilities.mapRange(t,
                mInitialTaskTranslationX, mTargetTask.left - mScaledTask.left);
        mTmpTaskWindowBounds.taskY = Utilities.mapRange(t,
                0, mTargetTask.top - mScaledTask.top);

        float taskScale = Utilities.mapRange(t, 1, mFinalTaskScale);
        mTmpTaskWindowBounds.winScale = taskScale / mFinalTaskScale;
        mTmpTaskWindowBounds.winX = Utilities.mapRange(t,
                mSrcWindow.left, 0);
        mTmpTaskWindowBounds.winY = Utilities.mapRange(t,
                mSrcWindow.top, 0);

        mTmpInsets.set(mInsets);
        Utilities.scaleRect(mTmpInsets, (1f - t));
        mTmpTaskWindowBounds.winCrop.set(mWindow);
        Utilities.insetRect(mTmpTaskWindowBounds.winCrop, mTmpInsets);

        return mTmpTaskWindowBounds;
    }
}
+41 −52
Original line number Diff line number Diff line
@@ -27,8 +27,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.UserHandle;
import android.util.Log;
import android.view.Surface;
@@ -36,17 +35,17 @@ import android.view.View;

import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.util.ComponentKey;
import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TransactionCompat;

/**
 * Contains helpful methods for retrieving data from {@link Task}s.
@@ -136,74 +135,64 @@ public class TaskUtils {
        return taskView;
    }


    /**
     * @return Animator that controls the window of the opening targets for the recents launch
     * animation.
     */
    public static ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
            RemoteAnimationTargetCompat[] targets) {
        final RecentsAnimationInterpolator recentsInterpolator = v.getRecentsInterpolator();

        Rect crop = new Rect();
        Matrix matrix = new Matrix();

        ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
            RemoteAnimationTargetCompat[] targets, final ClipAnimationHelper inOutHelper) {
        final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
        appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
        appAnimator.addUpdateListener(new MultiValueUpdateListener() {

            // Defer fading out the view until after the app window gets faded in
            FloatProp mViewAlpha = new FloatProp(1f, 0f, 75, 75, LINEAR);
            FloatProp mTaskAlpha = new FloatProp(0f, 1f, 0, 75, LINEAR);
            final FloatProp mViewAlpha = new FloatProp(1f, 0f, 75, 75, LINEAR);
            final FloatProp mTaskAlpha = new FloatProp(0f, 1f, 0, 75, LINEAR);

            boolean isFirstFrame = true;
            final RemoteAnimationTargetSet mTargetSet;

            @Override
            public void onUpdate(float percent) {
                final Surface surface = getSurface(v);
                final long frameNumber = surface != null ? getNextFrameNumber(surface) : -1;
                if (frameNumber == -1) {
                    // Booo, not cool! Our surface got destroyed, so no reason to animate anything.
                    Log.w(TAG, "Failed to animate, surface got destroyed.");
                    return;
                }
                TaskWindowBounds tw = recentsInterpolator.interpolate(percent);
            final RectF mThumbnailRect;
            private Surface mSurface;
            private long mFrameNumber;

            {
                mTargetSet = new RemoteAnimationTargetSet(targets, MODE_OPENING);
                inOutHelper.setTaskTransformCallback((t, app) -> {
                    t.setAlpha(app.leash, mTaskAlpha.value);

                    if (!skipViewChanges) {
                    v.setScaleX(tw.taskScale);
                    v.setScaleY(tw.taskScale);
                    v.setTranslationX(tw.taskX);
                    v.setTranslationY(tw.taskY);
                    v.setAlpha(mViewAlpha.value);
                        t.deferTransactionUntil(app.leash, mSurface, mFrameNumber);
                    }
                });

                matrix.setScale(tw.winScale, tw.winScale);
                matrix.postTranslate(tw.winX, tw.winY);
                crop.set(tw.winCrop);
                inOutHelper.prepareAnimation(true /* isOpening */);
                inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(),
                        mTargetSet.apps.length == 0 ? null : mTargetSet.apps[0]);

                TransactionCompat t = new TransactionCompat();
                if (isFirstFrame) {
                    RemoteAnimationProvider.prepareTargetsForFirstFrame(targets, t, MODE_OPENING);
                    isFirstFrame = false;
                mThumbnailRect = new RectF(inOutHelper.getTargetRect());
                mThumbnailRect.offset(-v.getTranslationX(), -v.getTranslationY());
                Utilities.scaleRectFAboutCenter(mThumbnailRect, 1 / v.getScaleX());
            }
                for (RemoteAnimationTargetCompat target : targets) {
                    if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) {
                        t.setAlpha(target.leash, mTaskAlpha.value);

                        // TODO: This isn't correct at the beginning of the animation, but better
                        // than nothing.
                        matrix.postTranslate(target.position.x, target.position.y);
                        t.setMatrix(target.leash, matrix);
                        t.setWindowCrop(target.leash, crop);
            @Override
            public void onUpdate(float percent) {
                mSurface = getSurface(v);
                mFrameNumber = mSurface != null ? getNextFrameNumber(mSurface) : -1;
                if (mFrameNumber == -1) {
                    // Booo, not cool! Our surface got destroyed, so no reason to animate anything.
                    Log.w(TAG, "Failed to animate, surface got destroyed.");
                    return;
                }

                RectF taskBounds = inOutHelper.applyTransform(mTargetSet, 1 - percent);
                if (!skipViewChanges) {
                            t.deferTransactionUntil(target.leash, surface, frameNumber);
                        }
                    }
                    float scale = taskBounds.width() / mThumbnailRect.width();
                    v.setScaleX(scale);
                    v.setScaleY(scale);
                    v.setTranslationX(taskBounds.centerX() - mThumbnailRect.centerX());
                    v.setTranslationY(taskBounds.centerY() - mThumbnailRect.centerY());
                    v.setAlpha(mViewAlpha.value);
                }
                t.apply();

                matrix.reset();
            }
        });
        return appAnimator;
+41 −5
Original line number Diff line number Diff line
@@ -20,13 +20,16 @@ import static com.android.launcher3.anim.Interpolators.SCROLL;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;

import android.annotation.TargetApi;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.os.RemoteException;
import android.support.annotation.Nullable;

import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
@@ -42,9 +45,12 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;

import java.util.function.BiConsumer;

/**
 * Utility class to handle window clip animation
 */
@TargetApi(Build.VERSION_CODES.P)
public class ClipAnimationHelper {

    // The bounds of the source app in device coordinates
@@ -78,13 +84,21 @@ public class ClipAnimationHelper {
    // Wether or not applyTransform has been called yet since prepareAnimation()
    private boolean mIsFirstFrame = true;

    public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
        mHomeStackBounds.set(homeStackBounds);
    private BiConsumer<TransactionCompat, RemoteAnimationTargetCompat> mTaskTransformCallback =
            (t, a) -> { };

    private void updateSourceStack(RemoteAnimationTargetCompat target) {
        mSourceInsets.set(target.contentInsets);
        mSourceStackBounds.set(target.sourceContainerBounds);

        // TODO: Should sourceContainerBounds already have this offset?
        mSourceStackBounds.offsetTo(target.position.x, target.position.y);

    }

    public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
        mHomeStackBounds.set(homeStackBounds);
        updateSourceStack(target);
    }

    public void updateTargetRect(Rect targetRect) {
@@ -116,7 +130,7 @@ public class ClipAnimationHelper {
        mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
    }

    public void applyTransform(RemoteAnimationTargetSet targetSet, float progress) {
    public RectF applyTransform(RemoteAnimationTargetSet targetSet, float progress) {
        RectF currentRect;
        mTmpRectF.set(mTargetRect);
        Utilities.scaleRectFAboutCenter(mTmpRectF, mTargetScale);
@@ -153,8 +167,16 @@ public class ClipAnimationHelper {
                    || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
                transaction.setAlpha(app.leash, 1 - progress);
            }

            mTaskTransformCallback.accept(transaction, app);
        }
        transaction.apply();
        return currentRect;
    }

    public void setTaskTransformCallback
            (BiConsumer<TransactionCompat, RemoteAnimationTargetCompat> callback) {
        mTaskTransformCallback = callback;
    }

    public void offsetTarget(float scale, float offsetX, float offsetY) {
@@ -165,6 +187,11 @@ public class ClipAnimationHelper {
    }

    public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv) {
        fromTaskThumbnailView(ttv, rv, null);
    }

    public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv,
            @Nullable RemoteAnimationTargetCompat target) {
        BaseDraggingActivity activity = BaseDraggingActivity.fromContext(ttv.getContext());
        BaseDragLayer dl = activity.getDragLayer();

@@ -173,7 +200,9 @@ public class ClipAnimationHelper {
        mHomeStackBounds.set(0, 0, dl.getWidth(), dl.getHeight());
        mHomeStackBounds.offset(pos[0], pos[1]);

        if (rv.shouldUseMultiWindowTaskSizeStrategy()) {
        if (target != null) {
            updateSourceStack(target);
        } else  if (rv.shouldUseMultiWindowTaskSizeStrategy()) {
            updateStackBoundsToMultiWindowTaskSize(activity);
        } else {
            mSourceStackBounds.set(mHomeStackBounds);
@@ -226,7 +255,6 @@ public class ClipAnimationHelper {
                insets.top + fullDp.availableHeightPx - taskHeight);
    }


    public void drawForProgress(TaskThumbnailView ttv, Canvas canvas, float progress) {
        RectF currentRect =  mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
        canvas.translate(mSourceStackBounds.left - mHomeStackBounds.left,
@@ -244,4 +272,12 @@ public class ClipAnimationHelper {
                ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress,
                ttv.getCornerRadius() * progress);
    }

    public RectF getTargetRect() {
        return mTargetRect;
    }

    public RectF getSourceRect() {
        return mSourceRect;
    }
}
Loading