diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-05-23 07:23:07 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-05-23 07:23:07 +0000 |
commit | 4ac63b28ced5d5b09eaae39adca68377a2a7ef5b (patch) | |
tree | 190b1a5377bf6dfc836e4be57767d0cd512c6bf2 /quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java | |
parent | 8102503413976f42f825aacda49af53a5483933b (diff) | |
parent | d00202ed3306950264be533cb2e8a171f58f7930 (diff) | |
download | android_packages_apps_Trebuchet-4ac63b28ced5d5b09eaae39adca68377a2a7ef5b.tar.gz android_packages_apps_Trebuchet-4ac63b28ced5d5b09eaae39adca68377a2a7ef5b.tar.bz2 android_packages_apps_Trebuchet-4ac63b28ced5d5b09eaae39adca68377a2a7ef5b.zip |
Snap for 4799153 from d00202ed3306950264be533cb2e8a171f58f7930 to pi-release
Change-Id: I72cfd121a4f78f4f1c44a5989a07bc9926593a2c
Diffstat (limited to 'quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java')
-rw-r--r-- | quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java | 207 |
1 files changed, 183 insertions, 24 deletions
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java index 493e9e238..8c7f104a6 100644 --- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java +++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java @@ -15,21 +15,44 @@ */ package com.android.quickstep.util; +import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_TRANSLATION_Y_FACTOR; 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 android.view.animation.Interpolator; +import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.views.BaseDragLayer; +import com.android.quickstep.RecentsModel; +import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.TaskThumbnailView; +import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.utilities.RectFEvaluator; 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 @@ -40,8 +63,8 @@ public class ClipAnimationHelper { private final RectF mSourceRect = new RectF(); // The bounds of the task view in launcher window coordinates private final RectF mTargetRect = new RectF(); - // Doesn't change after initialized, used as an anchor when changing mTargetRect - private final RectF mInitialTargetRect = new RectF(); + // Set when the final window destination is changed, such as offsetting for quick scrub + private final PointF mTargetOffset = new PointF(); // The insets to be used for clipping the app window, which can be larger than mSourceInsets // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In // app window coordinates. @@ -54,15 +77,33 @@ public class ClipAnimationHelper { private final Rect mClipRect = new Rect(); private final RectFEvaluator mRectFEvaluator = new RectFEvaluator(); private final Matrix mTmpMatrix = new Matrix(); + private final RectF mTmpRectF = new RectF(); + private float mTargetScale = 1f; + private Interpolator mInterpolator = LINEAR; + // We translate y slightly faster than the rest of the animation for quick scrub. + private Interpolator mOffsetYInterpolator = LINEAR; - public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) { - mHomeStackBounds.set(homeStackBounds); - mSourceInsets.set(target.getContentInsets()); + // Whether to boost the opening animation target layers, or the closing + private int mBoostModeTargetLayers = -1; + // Wether or not applyTransform has been called yet since prepareAnimation() + private boolean mIsFirstFrame = true; + + 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) { @@ -73,8 +114,6 @@ public class ClipAnimationHelper { mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left, mHomeStackBounds.top - mSourceStackBounds.top); - mInitialTargetRect.set(mTargetRect); - // Calculate the clip based on the target rect (since the content insets and the // launcher insets may differ, so the aspect ratio of the target rect can differ // from the source rect. The difference between the target rect (scaled to the @@ -91,12 +130,22 @@ public class ClipAnimationHelper { mSourceRect.set(scaledTargetRect); } - public void applyTransform(RemoteAnimationTargetCompat[] targets, float progress) { + public void prepareAnimation(boolean isOpening) { + mIsFirstFrame = true; + mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING; + } + + public RectF applyTransform(RemoteAnimationTargetSet targetSet, float progress) { RectF currentRect; - synchronized (mTargetRect) { - currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect); + mTmpRectF.set(mTargetRect); + Utilities.scaleRectFAboutCenter(mTmpRectF, mTargetScale); + float offsetYProgress = mOffsetYInterpolator.getInterpolation(progress); + progress = mInterpolator.getInterpolation(progress); + currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTmpRectF); + + synchronized (mTargetOffset) { // Stay lined up with the center of the target, since it moves for quick scrub. - currentRect.offset(mTargetRect.centerX() - currentRect.centerX(), 0); + currentRect.offset(mTargetOffset.x * progress, mTargetOffset.y * offsetYProgress); } mClipRect.left = (int) (mSourceWindowClipInsets.left * progress); @@ -106,30 +155,140 @@ public class ClipAnimationHelper { mClipRect.bottom = (int) (mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress)); - mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL); - TransactionCompat transaction = new TransactionCompat(); - for (RemoteAnimationTargetCompat app : targets) { - if (app.mode == MODE_CLOSING) { + if (mIsFirstFrame) { + RemoteAnimationProvider.prepareTargetsForFirstFrame(targetSet.unfilteredApps, + transaction, mBoostModeTargetLayers); + mIsFirstFrame = false; + } + for (RemoteAnimationTargetCompat app : targetSet.apps) { + if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { + mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL); mTmpMatrix.postTranslate(app.position.x, app.position.y); transaction.setMatrix(app.leash, mTmpMatrix) .setWindowCrop(app.leash, mClipRect); - if (app.isNotInRecents) { - transaction.setAlpha(app.leash, 1 - progress); - } + } - transaction.show(app.leash); + if (app.isNotInRecents + || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { + transaction.setAlpha(app.leash, 1 - progress); } + + mTaskTransformCallback.accept(transaction, app); } transaction.setEarlyWakeup(); transaction.apply(); + return currentRect; } - public void offsetTarget(float scale, float offsetX, float offsetY) { - synchronized (mTargetRect) { - mTargetRect.set(mInitialTargetRect); - Utilities.scaleRectFAboutCenter(mTargetRect, scale); - mTargetRect.offset(offsetX, offsetY); + public void setTaskTransformCallback + (BiConsumer<TransactionCompat, RemoteAnimationTargetCompat> callback) { + mTaskTransformCallback = callback; + } + + public void offsetTarget(float scale, float offsetX, float offsetY, Interpolator interpolator) { + synchronized (mTargetOffset) { + mTargetOffset.set(offsetX, offsetY); } + mTargetScale = scale; + mInterpolator = interpolator; + mOffsetYInterpolator = Interpolators.clampToProgress(mInterpolator, 0, + QUICK_SCRUB_TRANSLATION_Y_FACTOR); + } + + 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(); + + int[] pos = new int[2]; + dl.getLocationOnScreen(pos); + mHomeStackBounds.set(0, 0, dl.getWidth(), dl.getHeight()); + mHomeStackBounds.offset(pos[0], pos[1]); + + if (target != null) { + updateSourceStack(target); + } else if (rv.shouldUseMultiWindowTaskSizeStrategy()) { + updateStackBoundsToMultiWindowTaskSize(activity); + } else { + mSourceStackBounds.set(mHomeStackBounds); + mSourceInsets.set(activity.getDeviceProfile().getInsets()); + } + + Rect targetRect = new Rect(); + dl.getDescendantRectRelativeToSelf(ttv, targetRect); + updateTargetRect(targetRect); + + // Transform the clip relative to the target rect. + float scale = mTargetRect.width() / mSourceRect.width(); + mSourceWindowClipInsets.left = mSourceWindowClipInsets.left * scale; + mSourceWindowClipInsets.top = mSourceWindowClipInsets.top * scale; + mSourceWindowClipInsets.right = mSourceWindowClipInsets.right * scale; + mSourceWindowClipInsets.bottom = mSourceWindowClipInsets.bottom * scale; + } + + private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) { + ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy(); + if (sysUiProxy != null) { + try { + mSourceStackBounds.set(sysUiProxy.getNonMinimizedSplitScreenSecondaryBounds()); + return; + } catch (RemoteException e) { + // Use half screen size + } + } + + // Assume that the task size is half screen size (minus the insets and the divider size) + DeviceProfile fullDp = activity.getDeviceProfile().getFullScreenProfile(); + // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to + // account for system insets + int taskWidth = fullDp.availableWidthPx; + int taskHeight = fullDp.availableHeightPx; + int halfDividerSize = activity.getResources() + .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2; + + Rect insets = new Rect(); + WindowManagerWrapper.getInstance().getStableInsets(insets); + if (fullDp.isLandscape) { + taskWidth = taskWidth / 2 - halfDividerSize; + } else { + taskHeight = taskHeight / 2 - halfDividerSize; + } + + // Align the task to bottom left/right edge (closer to nav bar). + int left = activity.getDeviceProfile().isSeascape() ? insets.left + : (insets.left + fullDp.availableWidthPx - taskWidth); + mSourceStackBounds.set(0, 0, taskWidth, taskHeight); + mSourceStackBounds.offset(left, 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, + mSourceStackBounds.top - mHomeStackBounds.top); + mTmpMatrix.setRectToRect(mTargetRect, currentRect, ScaleToFit.FILL); + + canvas.concat(mTmpMatrix); + canvas.translate(mTargetRect.left, mTargetRect.top); + + float insetProgress = (1 - progress); + ttv.drawOnCanvas(canvas, + -mSourceWindowClipInsets.left * insetProgress, + -mSourceWindowClipInsets.top * insetProgress, + ttv.getMeasuredWidth() + mSourceWindowClipInsets.right * insetProgress, + ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress, + ttv.getCornerRadius() * progress); + } + + public RectF getTargetRect() { + return mTargetRect; + } + + public RectF getSourceRect() { + return mSourceRect; } } |