Loading quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +6 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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 Loading quickstep/src/com/android/quickstep/RecentsActivity.java +4 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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() { Loading quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.javadeleted 100644 → 0 +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; } } quickstep/src/com/android/quickstep/TaskUtils.java +41 −52 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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. Loading Loading @@ -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; Loading quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java +41 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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) { Loading @@ -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(); Loading @@ -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); Loading Loading @@ -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, Loading @@ -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
quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +6 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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 Loading
quickstep/src/com/android/quickstep/RecentsActivity.java +4 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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() { Loading
quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.javadeleted 100644 → 0 +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; } }
quickstep/src/com/android/quickstep/TaskUtils.java +41 −52 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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. Loading Loading @@ -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; Loading
quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java +41 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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) { Loading @@ -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(); Loading @@ -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); Loading Loading @@ -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, Loading @@ -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; } }