Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +31 −50 Original line number Diff line number Diff line Loading @@ -369,58 +369,41 @@ class DragToDesktopTransitionHandler( val startBounds = draggedTaskChange.startAbsBounds val endBounds = draggedTaskChange.endAbsBounds // TODO(b/301106941): Instead of forcing-finishing the animation that scales the // surface down and then starting another that scales it back up to the final size, // blend the two animations. state.dragAnimator.endAnimator() // Using [DRAG_FREEFORM_SCALE] to calculate animated width/height is possible because // it is known that the animation scale is finished because the animation was // force-ended above. This won't be true when the two animations are blended. val animStartWidth = (startBounds.width() * DRAG_FREEFORM_SCALE).toInt() val animStartHeight = (startBounds.height() * DRAG_FREEFORM_SCALE).toInt() // Using end bounds here to find the left/top also assumes the center animation has // finished and the surface is placed exactly in the center of the screen which matches // the end/default bounds of the now freeform task. val animStartLeft = endBounds.centerX() - (animStartWidth / 2) val animStartTop = endBounds.centerY() - (animStartHeight / 2) val animStartBounds = Rect( animStartLeft, animStartTop, animStartLeft + animStartWidth, animStartTop + animStartHeight // Pause any animation that may be currently playing; we will use the relevant // details of that animation here. state.dragAnimator.cancelAnimator() // We still apply scale to task bounds; as we animate the bounds to their // end value, animate scale to 1. val startScale = state.dragAnimator.scale val startPosition = state.dragAnimator.position val unscaledStartWidth = startBounds.width() val unscaledStartHeight = startBounds.height() val unscaledStartBounds = Rect( startPosition.x.toInt(), startPosition.y.toInt(), startPosition.x.toInt() + unscaledStartWidth, startPosition.y.toInt() + unscaledStartHeight ) dragToDesktopStateListener?.onCommitToDesktopAnimationStart(t) t.apply { setScale(draggedTaskLeash, 1f, 1f) setPosition( draggedTaskLeash, animStartBounds.left.toFloat(), animStartBounds.top.toFloat() ) setWindowCrop( draggedTaskLeash, animStartBounds.width(), animStartBounds.height() ) } // Accept the merge by applying the merging transaction (applied by #showResizeVeil) // and finish callback. Show the veil and position the task at the first frame before // starting the final animation. onTaskResizeAnimationListener.onAnimationStart(state.draggedTaskId, t, animStartBounds) onTaskResizeAnimationListener.onAnimationStart(state.draggedTaskId, t, unscaledStartBounds) finishCallback.onTransitionFinished(null /* wct */) // Because the task surface was scaled down during the drag, we must use the animated // bounds instead of the [startAbsBounds]. val tx: SurfaceControl.Transaction = transactionSupplier.get() ValueAnimator.ofObject(rectEvaluator, animStartBounds, endBounds) ValueAnimator.ofObject(rectEvaluator, unscaledStartBounds, endBounds) .setDuration(DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS) .apply { addUpdateListener { animator -> val animBounds = animator.animatedValue as Rect val animFraction = animator.animatedFraction // Progress scale from starting value to 1 as animation plays. val animScale = startScale + animFraction * (1 - startScale) tx.apply { setScale(draggedTaskLeash, 1f, 1f) setScale(draggedTaskLeash, animScale, animScale) setPosition( draggedTaskLeash, animBounds.left.toFloat(), Loading Loading @@ -493,10 +476,8 @@ class DragToDesktopTransitionHandler( val draggedTaskChange = state.draggedTaskChange ?: throw IllegalStateException("Expected non-null task change") val sc = draggedTaskChange.leash // TODO(b/301106941): Don't end the animation and start one to scale it back, merge them // instead. // End the animation that shrinks the window when task is first dragged from fullscreen dragToDesktopAnimator.endAnimator() // Pause the animation that shrinks the window when task is first dragged from fullscreen dragToDesktopAnimator.cancelAnimator() // Then animate the scaled window back to its original bounds. val x: Float = dragToDesktopAnimator.position.x val y: Float = dragToDesktopAnimator.position.y Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +6 −70 Original line number Diff line number Diff line Loading @@ -33,16 +33,8 @@ import static android.view.WindowInsets.Type.statusBars; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.compatui.AppCompatUtils.isSingleTopActivityTranslucent; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR; import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION; import static com.android.wm.shell.windowdecor.MoveToDesktopAnimator.DRAG_FREEFORM_SCALE; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; Loading Loading @@ -858,26 +850,18 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } case MotionEvent.ACTION_UP: { if (mTransitionDragActive) { final DesktopModeVisualIndicator.IndicatorType indicatorType = mDesktopTasksController.updateVisualIndicator(relevantDecor.mTaskInfo, relevantDecor.mTaskSurface, ev.getRawX(), ev.getRawY()); mTransitionDragActive = false; if (indicatorType == TO_DESKTOP_INDICATOR || indicatorType == TO_SPLIT_LEFT_INDICATOR || indicatorType == TO_SPLIT_RIGHT_INDICATOR) { if (DesktopModeStatus.isEnabled()) { animateToDesktop(relevantDecor, ev); } mMoveToDesktopAnimator = null; return; } else if (mMoveToDesktopAnimator != null) { if (mMoveToDesktopAnimator != null) { // Though this isn't a hover event, we need to update handle's hover state // as it likely will change. relevantDecor.updateHoverAndPressStatus(ev); mDesktopTasksController.onDragPositioningEndThroughStatusBar( new PointF(ev.getRawX(), ev.getRawY()), relevantDecor.mTaskInfo, calculateFreeformBounds(ev.getDisplayId(), DRAG_FREEFORM_SCALE)); calculateFreeformBounds(ev.getDisplayId(), DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE)); mMoveToDesktopAnimator = null; return; } else { Loading Loading @@ -946,54 +930,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { (int) (screenHeight * (adjustmentPercentage + scale))); } /** * Blocks relayout until transition is finished and transitions to Desktop */ private void animateToDesktop(DesktopModeWindowDecoration relevantDecor, MotionEvent ev) { centerAndMoveToDesktopWithAnimation(relevantDecor, ev); } /** * Animates a window to the center, grows to freeform size, and transitions to Desktop Mode. * @param relevantDecor the window decor of the task to be animated * @param ev the motion event that triggers the animation * TODO(b/315527000): This animation needs to be adjusted to allow snap left/right cases. * Currently fullscreen -> split snap still animates to center screen before readjusting. */ private void centerAndMoveToDesktopWithAnimation(DesktopModeWindowDecoration relevantDecor, MotionEvent ev) { ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); animator.setDuration(FREEFORM_ANIMATION_DURATION); final SurfaceControl sc = relevantDecor.mTaskSurface; final Rect endBounds = calculateFreeformBounds(ev.getDisplayId(), DRAG_FREEFORM_SCALE); final Transaction t = mTransactionFactory.get(); final float diffX = endBounds.centerX() - ev.getRawX(); final float diffY = endBounds.top - ev.getRawY(); final float startingX = ev.getRawX() - DRAG_FREEFORM_SCALE * mDragToDesktopAnimationStartBounds.width() / 2; animator.addUpdateListener(animation -> { final float animatorValue = (float) animation.getAnimatedValue(); final float x = startingX + diffX * animatorValue; final float y = ev.getRawY() + diffY * animatorValue; t.setPosition(sc, x, y); t.apply(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mDesktopTasksController.onDragPositioningEndThroughStatusBar( new PointF(ev.getRawX(), ev.getRawY()), relevantDecor.mTaskInfo, calculateFreeformBounds(ev.getDisplayId(), DesktopTasksController .DESKTOP_MODE_INITIAL_BOUNDS_SCALE)); } }); animator.start(); } @Nullable private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) { final DesktopModeWindowDecoration focusedDecor = getFocusedDecor(); Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt +7 −6 Original line number Diff line number Diff line Loading @@ -31,15 +31,16 @@ class MoveToDesktopAnimator @JvmOverloads constructor( private val animatedTaskWidth get() = dragToDesktopAnimator.animatedValue as Float * startBounds.width() val scale: Float get() = dragToDesktopAnimator.animatedValue as Float private val dragToDesktopAnimator: ValueAnimator = ValueAnimator.ofFloat(1f, DRAG_FREEFORM_SCALE) .setDuration(ANIMATION_DURATION.toLong()) .apply { val t = SurfaceControl.Transaction() val cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) addUpdateListener { animation -> val animatorValue = animation.animatedValue as Float t.setScale(taskSurface, animatorValue, animatorValue) addUpdateListener { t.setScale(taskSurface, scale, scale) .setCornerRadius(taskSurface, cornerRadius) .apply() } Loading Loading @@ -90,9 +91,9 @@ class MoveToDesktopAnimator @JvmOverloads constructor( } /** * Ends the animation, setting the scale and position to the final animation value * Cancels the animation, intended to be used when another animator will take over. */ fun endAnimator() { dragToDesktopAnimator.end() fun cancelAnimator() { dragToDesktopAnimator.cancel() } } No newline at end of file libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt +1 −1 Original line number Diff line number Diff line Loading @@ -190,7 +190,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { handler.cancelDragToDesktopTransition() // Cancel animation should run since it had already started. verify(dragAnimator).endAnimator() verify(dragAnimator).cancelAnimator() } @Test Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +31 −50 Original line number Diff line number Diff line Loading @@ -369,58 +369,41 @@ class DragToDesktopTransitionHandler( val startBounds = draggedTaskChange.startAbsBounds val endBounds = draggedTaskChange.endAbsBounds // TODO(b/301106941): Instead of forcing-finishing the animation that scales the // surface down and then starting another that scales it back up to the final size, // blend the two animations. state.dragAnimator.endAnimator() // Using [DRAG_FREEFORM_SCALE] to calculate animated width/height is possible because // it is known that the animation scale is finished because the animation was // force-ended above. This won't be true when the two animations are blended. val animStartWidth = (startBounds.width() * DRAG_FREEFORM_SCALE).toInt() val animStartHeight = (startBounds.height() * DRAG_FREEFORM_SCALE).toInt() // Using end bounds here to find the left/top also assumes the center animation has // finished and the surface is placed exactly in the center of the screen which matches // the end/default bounds of the now freeform task. val animStartLeft = endBounds.centerX() - (animStartWidth / 2) val animStartTop = endBounds.centerY() - (animStartHeight / 2) val animStartBounds = Rect( animStartLeft, animStartTop, animStartLeft + animStartWidth, animStartTop + animStartHeight // Pause any animation that may be currently playing; we will use the relevant // details of that animation here. state.dragAnimator.cancelAnimator() // We still apply scale to task bounds; as we animate the bounds to their // end value, animate scale to 1. val startScale = state.dragAnimator.scale val startPosition = state.dragAnimator.position val unscaledStartWidth = startBounds.width() val unscaledStartHeight = startBounds.height() val unscaledStartBounds = Rect( startPosition.x.toInt(), startPosition.y.toInt(), startPosition.x.toInt() + unscaledStartWidth, startPosition.y.toInt() + unscaledStartHeight ) dragToDesktopStateListener?.onCommitToDesktopAnimationStart(t) t.apply { setScale(draggedTaskLeash, 1f, 1f) setPosition( draggedTaskLeash, animStartBounds.left.toFloat(), animStartBounds.top.toFloat() ) setWindowCrop( draggedTaskLeash, animStartBounds.width(), animStartBounds.height() ) } // Accept the merge by applying the merging transaction (applied by #showResizeVeil) // and finish callback. Show the veil and position the task at the first frame before // starting the final animation. onTaskResizeAnimationListener.onAnimationStart(state.draggedTaskId, t, animStartBounds) onTaskResizeAnimationListener.onAnimationStart(state.draggedTaskId, t, unscaledStartBounds) finishCallback.onTransitionFinished(null /* wct */) // Because the task surface was scaled down during the drag, we must use the animated // bounds instead of the [startAbsBounds]. val tx: SurfaceControl.Transaction = transactionSupplier.get() ValueAnimator.ofObject(rectEvaluator, animStartBounds, endBounds) ValueAnimator.ofObject(rectEvaluator, unscaledStartBounds, endBounds) .setDuration(DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS) .apply { addUpdateListener { animator -> val animBounds = animator.animatedValue as Rect val animFraction = animator.animatedFraction // Progress scale from starting value to 1 as animation plays. val animScale = startScale + animFraction * (1 - startScale) tx.apply { setScale(draggedTaskLeash, 1f, 1f) setScale(draggedTaskLeash, animScale, animScale) setPosition( draggedTaskLeash, animBounds.left.toFloat(), Loading Loading @@ -493,10 +476,8 @@ class DragToDesktopTransitionHandler( val draggedTaskChange = state.draggedTaskChange ?: throw IllegalStateException("Expected non-null task change") val sc = draggedTaskChange.leash // TODO(b/301106941): Don't end the animation and start one to scale it back, merge them // instead. // End the animation that shrinks the window when task is first dragged from fullscreen dragToDesktopAnimator.endAnimator() // Pause the animation that shrinks the window when task is first dragged from fullscreen dragToDesktopAnimator.cancelAnimator() // Then animate the scaled window back to its original bounds. val x: Float = dragToDesktopAnimator.position.x val y: Float = dragToDesktopAnimator.position.y Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +6 −70 Original line number Diff line number Diff line Loading @@ -33,16 +33,8 @@ import static android.view.WindowInsets.Type.statusBars; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.compatui.AppCompatUtils.isSingleTopActivityTranslucent; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR; import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION; import static com.android.wm.shell.windowdecor.MoveToDesktopAnimator.DRAG_FREEFORM_SCALE; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; Loading Loading @@ -858,26 +850,18 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } case MotionEvent.ACTION_UP: { if (mTransitionDragActive) { final DesktopModeVisualIndicator.IndicatorType indicatorType = mDesktopTasksController.updateVisualIndicator(relevantDecor.mTaskInfo, relevantDecor.mTaskSurface, ev.getRawX(), ev.getRawY()); mTransitionDragActive = false; if (indicatorType == TO_DESKTOP_INDICATOR || indicatorType == TO_SPLIT_LEFT_INDICATOR || indicatorType == TO_SPLIT_RIGHT_INDICATOR) { if (DesktopModeStatus.isEnabled()) { animateToDesktop(relevantDecor, ev); } mMoveToDesktopAnimator = null; return; } else if (mMoveToDesktopAnimator != null) { if (mMoveToDesktopAnimator != null) { // Though this isn't a hover event, we need to update handle's hover state // as it likely will change. relevantDecor.updateHoverAndPressStatus(ev); mDesktopTasksController.onDragPositioningEndThroughStatusBar( new PointF(ev.getRawX(), ev.getRawY()), relevantDecor.mTaskInfo, calculateFreeformBounds(ev.getDisplayId(), DRAG_FREEFORM_SCALE)); calculateFreeformBounds(ev.getDisplayId(), DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE)); mMoveToDesktopAnimator = null; return; } else { Loading Loading @@ -946,54 +930,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { (int) (screenHeight * (adjustmentPercentage + scale))); } /** * Blocks relayout until transition is finished and transitions to Desktop */ private void animateToDesktop(DesktopModeWindowDecoration relevantDecor, MotionEvent ev) { centerAndMoveToDesktopWithAnimation(relevantDecor, ev); } /** * Animates a window to the center, grows to freeform size, and transitions to Desktop Mode. * @param relevantDecor the window decor of the task to be animated * @param ev the motion event that triggers the animation * TODO(b/315527000): This animation needs to be adjusted to allow snap left/right cases. * Currently fullscreen -> split snap still animates to center screen before readjusting. */ private void centerAndMoveToDesktopWithAnimation(DesktopModeWindowDecoration relevantDecor, MotionEvent ev) { ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); animator.setDuration(FREEFORM_ANIMATION_DURATION); final SurfaceControl sc = relevantDecor.mTaskSurface; final Rect endBounds = calculateFreeformBounds(ev.getDisplayId(), DRAG_FREEFORM_SCALE); final Transaction t = mTransactionFactory.get(); final float diffX = endBounds.centerX() - ev.getRawX(); final float diffY = endBounds.top - ev.getRawY(); final float startingX = ev.getRawX() - DRAG_FREEFORM_SCALE * mDragToDesktopAnimationStartBounds.width() / 2; animator.addUpdateListener(animation -> { final float animatorValue = (float) animation.getAnimatedValue(); final float x = startingX + diffX * animatorValue; final float y = ev.getRawY() + diffY * animatorValue; t.setPosition(sc, x, y); t.apply(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mDesktopTasksController.onDragPositioningEndThroughStatusBar( new PointF(ev.getRawX(), ev.getRawY()), relevantDecor.mTaskInfo, calculateFreeformBounds(ev.getDisplayId(), DesktopTasksController .DESKTOP_MODE_INITIAL_BOUNDS_SCALE)); } }); animator.start(); } @Nullable private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) { final DesktopModeWindowDecoration focusedDecor = getFocusedDecor(); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt +7 −6 Original line number Diff line number Diff line Loading @@ -31,15 +31,16 @@ class MoveToDesktopAnimator @JvmOverloads constructor( private val animatedTaskWidth get() = dragToDesktopAnimator.animatedValue as Float * startBounds.width() val scale: Float get() = dragToDesktopAnimator.animatedValue as Float private val dragToDesktopAnimator: ValueAnimator = ValueAnimator.ofFloat(1f, DRAG_FREEFORM_SCALE) .setDuration(ANIMATION_DURATION.toLong()) .apply { val t = SurfaceControl.Transaction() val cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) addUpdateListener { animation -> val animatorValue = animation.animatedValue as Float t.setScale(taskSurface, animatorValue, animatorValue) addUpdateListener { t.setScale(taskSurface, scale, scale) .setCornerRadius(taskSurface, cornerRadius) .apply() } Loading Loading @@ -90,9 +91,9 @@ class MoveToDesktopAnimator @JvmOverloads constructor( } /** * Ends the animation, setting the scale and position to the final animation value * Cancels the animation, intended to be used when another animator will take over. */ fun endAnimator() { dragToDesktopAnimator.end() fun cancelAnimator() { dragToDesktopAnimator.cancel() } } No newline at end of file
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt +1 −1 Original line number Diff line number Diff line Loading @@ -190,7 +190,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { handler.cancelDragToDesktopTransition() // Cancel animation should run since it had already started. verify(dragAnimator).endAnimator() verify(dragAnimator).cancelAnimator() } @Test Loading