Loading quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +17 −3 Original line number Diff line number Diff line Loading @@ -15,6 +15,9 @@ */ package com.android.quickstep; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static android.widget.Toast.LENGTH_SHORT; import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER; Loading Loading @@ -1065,7 +1068,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends runningTaskTarget.pictureInPictureParams) != null; if (mIsSwipingPipToHome) { mSwipePipToHomeAnimator = getSwipePipToHomeAnimator( homeAnimFactory, runningTaskTarget); homeAnimFactory, runningTaskTarget, start); mSwipePipToHomeAnimator.setDuration(SWIPE_PIP_TO_HOME_DURATION); mSwipePipToHomeAnimator.setInterpolator(interpolator); mSwipePipToHomeAnimator.setFloatValues(0f, 1f); Loading Loading @@ -1135,23 +1138,34 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends } private SwipePipToHomeAnimator getSwipePipToHomeAnimator(HomeAnimationFactory homeAnimFactory, RemoteAnimationTargetCompat runningTaskTarget) { RemoteAnimationTargetCompat runningTaskTarget, float startProgress) { // Directly animate the app to PiP (picture-in-picture) mode final ActivityManager.RunningTaskInfo taskInfo = mGestureState.getRunningTask(); final RecentsOrientedState orientationState = mTaskViewSimulator.getOrientationState(); final int windowRotation = orientationState.getDisplayRotation(); final int homeRotation = orientationState.getRecentsActivityRotation(); final Rect destinationBounds = SystemUiProxy.INSTANCE.get(mContext) .startSwipePipToHome(taskInfo.topActivity, TaskInfoCompat.getTopActivityInfo(taskInfo), runningTaskTarget.pictureInPictureParams, orientationState.getRecentsActivityRotation(), homeRotation, mDp.hotseatBarSizePx); final Rect startBounds = new Rect(); updateProgressForStartRect(new Matrix(), startProgress).round(startBounds); final SwipePipToHomeAnimator swipePipToHomeAnimator = new SwipePipToHomeAnimator( runningTaskTarget.taskId, taskInfo.topActivity, runningTaskTarget.leash.getSurfaceControl(), TaskInfoCompat.getPipSourceRectHint(runningTaskTarget.pictureInPictureParams), TaskInfoCompat.getWindowConfigurationBounds(taskInfo), startBounds, destinationBounds); // We would assume home and app window always in the same rotation While homeRotation // is not ROTATION_0 (which implies the rotation is turned on in launcher settings). if (homeRotation == ROTATION_0 && (windowRotation == ROTATION_90 || windowRotation == ROTATION_270)) { swipePipToHomeAnimator.setFromRotation(mTaskViewSimulator, windowRotation); } swipePipToHomeAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { Loading quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java +21 −8 Original line number Diff line number Diff line Loading @@ -174,6 +174,24 @@ public abstract class SwipeUpAnimationLogic { } } /** * Update with start progress for window animation to home. * @param outMatrix {@link Matrix} to map a rect in Launcher space to window space. * @param startProgress The progress of {@link #mCurrentShift} to start thw window from. * @return {@link RectF} represents the bounds as starting point in window space. */ protected RectF updateProgressForStartRect(Matrix outMatrix, float startProgress) { mCurrentShift.updateValue(startProgress); mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress)); RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect()); mTaskViewSimulator.applyWindowToHomeRotation(outMatrix); final RectF startRect = new RectF(cropRectF); mTaskViewSimulator.getCurrentMatrix().mapRect(startRect); return startRect; } /** * Creates an animation that transforms the current app window into the home app. * @param startProgress The progress of {@link #mCurrentShift} to start the window from. Loading @@ -183,16 +201,11 @@ public abstract class SwipeUpAnimationLogic { HomeAnimationFactory homeAnimationFactory) { final RectF targetRect = homeAnimationFactory.getWindowTargetRect(); mCurrentShift.updateValue(startProgress); mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress)); RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect()); // Matrix to map a rect in Launcher space to window space Matrix homeToWindowPositionMap = new Matrix(); mTaskViewSimulator.applyWindowToHomeRotation(homeToWindowPositionMap); final RectF startRect = updateProgressForStartRect( homeToWindowPositionMap, startProgress); RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect()); final RectF startRect = new RectF(cropRectF); mTaskViewSimulator.getCurrentMatrix().mapRect(startRect); // Move the startRect to Launcher space as floatingIconView runs in Launcher Matrix windowToHomePositionMap = new Matrix(); homeToWindowPositionMap.invert(windowToHomePositionMap); Loading quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java +84 −9 Original line number Diff line number Diff line Loading @@ -22,7 +22,11 @@ import android.animation.Animator; import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.content.ComponentName; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.util.Log; import android.view.Surface; import android.view.SurfaceControl; import androidx.annotation.NonNull; Loading @@ -42,9 +46,12 @@ import com.android.systemui.shared.system.InteractionJankMonitorWrapper; */ public class SwipePipToHomeAnimator extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener { private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName(); private final int mTaskId; private final ComponentName mComponentName; private final SurfaceControl mLeash; private final Rect mAppBounds = new Rect(); private final Rect mStartBounds = new Rect(); private final Rect mDestinationBounds = new Rect(); private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; Loading @@ -55,29 +62,50 @@ public class SwipePipToHomeAnimator extends ValueAnimator implements private final Rect mSourceHintRectInsets = new Rect(); private final Rect mSourceInsets = new Rect(); /** for rotation via {@link #setFromRotation(TaskViewSimulator, int)} */ private @RecentsOrientedState.SurfaceRotation int mFromRotation = Surface.ROTATION_0; private final Rect mDestinationBoundsTransformed = new Rect(); private final Rect mDestinationBoundsAnimation = new Rect(); /** * Flag to avoid the double-end problem since the leash would have been released * after the first end call and any further operations upon it would lead to NPE. */ private boolean mHasAnimationEnded; /** * @param taskId Task id associated with this animator, see also {@link #getTaskId()} * @param componentName Component associated with this animator, * see also {@link #getComponentName()} * @param leash {@link SurfaceControl} this animator operates on * @param sourceRectHint See the definition in {@link android.app.PictureInPictureParams} * @param appBounds Bounds of the application, sourceRectHint is based on this bounds * @param startBounds Bounds of the application when this animator starts. This can be * different from the appBounds if user has swiped a certain distance and * Launcher has performed transform on the leash. * @param destinationBounds Bounds of the destination this animator ends to */ public SwipePipToHomeAnimator(int taskId, @NonNull ComponentName componentName, @NonNull SurfaceControl leash, @NonNull Rect sourceRectHint, @NonNull Rect appBounds, @NonNull Rect startBounds, @NonNull Rect destinationBounds) { mTaskId = taskId; mComponentName = componentName; mLeash = leash; mAppBounds.set(appBounds); mStartBounds.set(startBounds); mDestinationBounds.set(destinationBounds); mDestinationBoundsTransformed.set(mDestinationBounds); mDestinationBoundsAnimation.set(mDestinationBounds); mSurfaceTransactionHelper = new PipSurfaceTransactionHelper(); mSourceHintRectInsets.set(sourceRectHint.left - startBounds.left, sourceRectHint.top - startBounds.top, startBounds.right - sourceRectHint.right, startBounds.bottom - sourceRectHint.bottom); mSourceHintRectInsets.set(sourceRectHint.left - appBounds.left, sourceRectHint.top - appBounds.top, appBounds.right - sourceRectHint.right, appBounds.bottom - sourceRectHint.bottom); addListener(new AnimationSuccessListener() { @Override Loading Loading @@ -106,16 +134,62 @@ public class SwipePipToHomeAnimator extends ValueAnimator implements addUpdateListener(this); } /** sets the from rotation if it's different from the target rotation. */ public void setFromRotation(TaskViewSimulator taskViewSimulator, @RecentsOrientedState.SurfaceRotation int fromRotation) { if (fromRotation != Surface.ROTATION_90 && fromRotation != Surface.ROTATION_270) { Log.wtf(TAG, "Not a supported rotation, rotation=" + fromRotation); return; } mFromRotation = fromRotation; final Matrix matrix = new Matrix(); taskViewSimulator.applyWindowToHomeRotation(matrix); // map the destination bounds into window space. mDestinationBounds is always calculated // in the final home space and the animation runs in original window space. final RectF transformed = new RectF(mDestinationBounds); matrix.mapRect(transformed, new RectF(mDestinationBounds)); transformed.round(mDestinationBoundsTransformed); // set the animation destination bounds for RectEvaluator calculation. // bounds and insets are calculated as if the transition is from mAppBounds to // mDestinationBoundsAnimation, separated from rotate / scale / position. mDestinationBoundsAnimation.set(mAppBounds.left, mAppBounds.top, mAppBounds.left + mDestinationBounds.width(), mAppBounds.top + mDestinationBounds.height()); } @Override public void onAnimationUpdate(ValueAnimator animator) { if (mHasAnimationEnded) return; final float fraction = animator.getAnimatedFraction(); final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds, mDestinationBounds); final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds, mDestinationBoundsAnimation); final Rect insets = mInsetsEvaluator.evaluate(fraction, mSourceInsets, mSourceHintRectInsets); final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mStartBounds, bounds, insets); final SurfaceControl.Transaction tx = PipSurfaceTransactionHelper.newSurfaceControlTransaction(); if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) { final float degree, positionX, positionY; if (mFromRotation == Surface.ROTATION_90) { degree = -90 * fraction; positionX = fraction * (mDestinationBoundsTransformed.left - mAppBounds.left) + mAppBounds.left; positionY = fraction * (mDestinationBoundsTransformed.bottom - mAppBounds.top) + mAppBounds.top; } else { degree = 90 * fraction; positionX = fraction * (mDestinationBoundsTransformed.right - mAppBounds.left) + mAppBounds.left; positionY = fraction * (mDestinationBoundsTransformed.top - mAppBounds.top) + mAppBounds.top; } mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets, degree, positionX, positionY); } else { mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mAppBounds, bounds, insets); } mSurfaceTransactionHelper.resetCornerRadius(tx, mLeash); tx.apply(); } Loading @@ -135,8 +209,9 @@ public class SwipePipToHomeAnimator extends ValueAnimator implements private void onAnimationEnd() { if (mHasAnimationEnded) return; final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); mSurfaceTransactionHelper.reset(tx, mLeash, mDestinationBounds); final SurfaceControl.Transaction tx = PipSurfaceTransactionHelper.newSurfaceControlTransaction(); mSurfaceTransactionHelper.reset(tx, mLeash, mDestinationBoundsTransformed, mFromRotation); tx.apply(); mHasAnimationEnded = true; } Loading Loading
quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +17 −3 Original line number Diff line number Diff line Loading @@ -15,6 +15,9 @@ */ package com.android.quickstep; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static android.widget.Toast.LENGTH_SHORT; import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER; Loading Loading @@ -1065,7 +1068,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends runningTaskTarget.pictureInPictureParams) != null; if (mIsSwipingPipToHome) { mSwipePipToHomeAnimator = getSwipePipToHomeAnimator( homeAnimFactory, runningTaskTarget); homeAnimFactory, runningTaskTarget, start); mSwipePipToHomeAnimator.setDuration(SWIPE_PIP_TO_HOME_DURATION); mSwipePipToHomeAnimator.setInterpolator(interpolator); mSwipePipToHomeAnimator.setFloatValues(0f, 1f); Loading Loading @@ -1135,23 +1138,34 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends } private SwipePipToHomeAnimator getSwipePipToHomeAnimator(HomeAnimationFactory homeAnimFactory, RemoteAnimationTargetCompat runningTaskTarget) { RemoteAnimationTargetCompat runningTaskTarget, float startProgress) { // Directly animate the app to PiP (picture-in-picture) mode final ActivityManager.RunningTaskInfo taskInfo = mGestureState.getRunningTask(); final RecentsOrientedState orientationState = mTaskViewSimulator.getOrientationState(); final int windowRotation = orientationState.getDisplayRotation(); final int homeRotation = orientationState.getRecentsActivityRotation(); final Rect destinationBounds = SystemUiProxy.INSTANCE.get(mContext) .startSwipePipToHome(taskInfo.topActivity, TaskInfoCompat.getTopActivityInfo(taskInfo), runningTaskTarget.pictureInPictureParams, orientationState.getRecentsActivityRotation(), homeRotation, mDp.hotseatBarSizePx); final Rect startBounds = new Rect(); updateProgressForStartRect(new Matrix(), startProgress).round(startBounds); final SwipePipToHomeAnimator swipePipToHomeAnimator = new SwipePipToHomeAnimator( runningTaskTarget.taskId, taskInfo.topActivity, runningTaskTarget.leash.getSurfaceControl(), TaskInfoCompat.getPipSourceRectHint(runningTaskTarget.pictureInPictureParams), TaskInfoCompat.getWindowConfigurationBounds(taskInfo), startBounds, destinationBounds); // We would assume home and app window always in the same rotation While homeRotation // is not ROTATION_0 (which implies the rotation is turned on in launcher settings). if (homeRotation == ROTATION_0 && (windowRotation == ROTATION_90 || windowRotation == ROTATION_270)) { swipePipToHomeAnimator.setFromRotation(mTaskViewSimulator, windowRotation); } swipePipToHomeAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { Loading
quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java +21 −8 Original line number Diff line number Diff line Loading @@ -174,6 +174,24 @@ public abstract class SwipeUpAnimationLogic { } } /** * Update with start progress for window animation to home. * @param outMatrix {@link Matrix} to map a rect in Launcher space to window space. * @param startProgress The progress of {@link #mCurrentShift} to start thw window from. * @return {@link RectF} represents the bounds as starting point in window space. */ protected RectF updateProgressForStartRect(Matrix outMatrix, float startProgress) { mCurrentShift.updateValue(startProgress); mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress)); RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect()); mTaskViewSimulator.applyWindowToHomeRotation(outMatrix); final RectF startRect = new RectF(cropRectF); mTaskViewSimulator.getCurrentMatrix().mapRect(startRect); return startRect; } /** * Creates an animation that transforms the current app window into the home app. * @param startProgress The progress of {@link #mCurrentShift} to start the window from. Loading @@ -183,16 +201,11 @@ public abstract class SwipeUpAnimationLogic { HomeAnimationFactory homeAnimationFactory) { final RectF targetRect = homeAnimationFactory.getWindowTargetRect(); mCurrentShift.updateValue(startProgress); mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress)); RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect()); // Matrix to map a rect in Launcher space to window space Matrix homeToWindowPositionMap = new Matrix(); mTaskViewSimulator.applyWindowToHomeRotation(homeToWindowPositionMap); final RectF startRect = updateProgressForStartRect( homeToWindowPositionMap, startProgress); RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect()); final RectF startRect = new RectF(cropRectF); mTaskViewSimulator.getCurrentMatrix().mapRect(startRect); // Move the startRect to Launcher space as floatingIconView runs in Launcher Matrix windowToHomePositionMap = new Matrix(); homeToWindowPositionMap.invert(windowToHomePositionMap); Loading
quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java +84 −9 Original line number Diff line number Diff line Loading @@ -22,7 +22,11 @@ import android.animation.Animator; import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.content.ComponentName; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.util.Log; import android.view.Surface; import android.view.SurfaceControl; import androidx.annotation.NonNull; Loading @@ -42,9 +46,12 @@ import com.android.systemui.shared.system.InteractionJankMonitorWrapper; */ public class SwipePipToHomeAnimator extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener { private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName(); private final int mTaskId; private final ComponentName mComponentName; private final SurfaceControl mLeash; private final Rect mAppBounds = new Rect(); private final Rect mStartBounds = new Rect(); private final Rect mDestinationBounds = new Rect(); private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; Loading @@ -55,29 +62,50 @@ public class SwipePipToHomeAnimator extends ValueAnimator implements private final Rect mSourceHintRectInsets = new Rect(); private final Rect mSourceInsets = new Rect(); /** for rotation via {@link #setFromRotation(TaskViewSimulator, int)} */ private @RecentsOrientedState.SurfaceRotation int mFromRotation = Surface.ROTATION_0; private final Rect mDestinationBoundsTransformed = new Rect(); private final Rect mDestinationBoundsAnimation = new Rect(); /** * Flag to avoid the double-end problem since the leash would have been released * after the first end call and any further operations upon it would lead to NPE. */ private boolean mHasAnimationEnded; /** * @param taskId Task id associated with this animator, see also {@link #getTaskId()} * @param componentName Component associated with this animator, * see also {@link #getComponentName()} * @param leash {@link SurfaceControl} this animator operates on * @param sourceRectHint See the definition in {@link android.app.PictureInPictureParams} * @param appBounds Bounds of the application, sourceRectHint is based on this bounds * @param startBounds Bounds of the application when this animator starts. This can be * different from the appBounds if user has swiped a certain distance and * Launcher has performed transform on the leash. * @param destinationBounds Bounds of the destination this animator ends to */ public SwipePipToHomeAnimator(int taskId, @NonNull ComponentName componentName, @NonNull SurfaceControl leash, @NonNull Rect sourceRectHint, @NonNull Rect appBounds, @NonNull Rect startBounds, @NonNull Rect destinationBounds) { mTaskId = taskId; mComponentName = componentName; mLeash = leash; mAppBounds.set(appBounds); mStartBounds.set(startBounds); mDestinationBounds.set(destinationBounds); mDestinationBoundsTransformed.set(mDestinationBounds); mDestinationBoundsAnimation.set(mDestinationBounds); mSurfaceTransactionHelper = new PipSurfaceTransactionHelper(); mSourceHintRectInsets.set(sourceRectHint.left - startBounds.left, sourceRectHint.top - startBounds.top, startBounds.right - sourceRectHint.right, startBounds.bottom - sourceRectHint.bottom); mSourceHintRectInsets.set(sourceRectHint.left - appBounds.left, sourceRectHint.top - appBounds.top, appBounds.right - sourceRectHint.right, appBounds.bottom - sourceRectHint.bottom); addListener(new AnimationSuccessListener() { @Override Loading Loading @@ -106,16 +134,62 @@ public class SwipePipToHomeAnimator extends ValueAnimator implements addUpdateListener(this); } /** sets the from rotation if it's different from the target rotation. */ public void setFromRotation(TaskViewSimulator taskViewSimulator, @RecentsOrientedState.SurfaceRotation int fromRotation) { if (fromRotation != Surface.ROTATION_90 && fromRotation != Surface.ROTATION_270) { Log.wtf(TAG, "Not a supported rotation, rotation=" + fromRotation); return; } mFromRotation = fromRotation; final Matrix matrix = new Matrix(); taskViewSimulator.applyWindowToHomeRotation(matrix); // map the destination bounds into window space. mDestinationBounds is always calculated // in the final home space and the animation runs in original window space. final RectF transformed = new RectF(mDestinationBounds); matrix.mapRect(transformed, new RectF(mDestinationBounds)); transformed.round(mDestinationBoundsTransformed); // set the animation destination bounds for RectEvaluator calculation. // bounds and insets are calculated as if the transition is from mAppBounds to // mDestinationBoundsAnimation, separated from rotate / scale / position. mDestinationBoundsAnimation.set(mAppBounds.left, mAppBounds.top, mAppBounds.left + mDestinationBounds.width(), mAppBounds.top + mDestinationBounds.height()); } @Override public void onAnimationUpdate(ValueAnimator animator) { if (mHasAnimationEnded) return; final float fraction = animator.getAnimatedFraction(); final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds, mDestinationBounds); final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds, mDestinationBoundsAnimation); final Rect insets = mInsetsEvaluator.evaluate(fraction, mSourceInsets, mSourceHintRectInsets); final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mStartBounds, bounds, insets); final SurfaceControl.Transaction tx = PipSurfaceTransactionHelper.newSurfaceControlTransaction(); if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) { final float degree, positionX, positionY; if (mFromRotation == Surface.ROTATION_90) { degree = -90 * fraction; positionX = fraction * (mDestinationBoundsTransformed.left - mAppBounds.left) + mAppBounds.left; positionY = fraction * (mDestinationBoundsTransformed.bottom - mAppBounds.top) + mAppBounds.top; } else { degree = 90 * fraction; positionX = fraction * (mDestinationBoundsTransformed.right - mAppBounds.left) + mAppBounds.left; positionY = fraction * (mDestinationBoundsTransformed.top - mAppBounds.top) + mAppBounds.top; } mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets, degree, positionX, positionY); } else { mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mAppBounds, bounds, insets); } mSurfaceTransactionHelper.resetCornerRadius(tx, mLeash); tx.apply(); } Loading @@ -135,8 +209,9 @@ public class SwipePipToHomeAnimator extends ValueAnimator implements private void onAnimationEnd() { if (mHasAnimationEnded) return; final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); mSurfaceTransactionHelper.reset(tx, mLeash, mDestinationBounds); final SurfaceControl.Transaction tx = PipSurfaceTransactionHelper.newSurfaceControlTransaction(); mSurfaceTransactionHelper.reset(tx, mLeash, mDestinationBoundsTransformed, mFromRotation); tx.apply(); mHasAnimationEnded = true; } Loading