diff options
| author | 2025-03-04 00:02:54 -0800 | |
|---|---|---|
| committer | 2025-03-04 00:02:54 -0800 | |
| commit | 1c413e4dbb280fc1f5b82d5b07d3425182001702 (patch) | |
| tree | 3b6bdb3d2f24d998ece5666341e5365c371100b8 | |
| parent | c8f5b457106caba889775478e7f3417c43e1e504 (diff) | |
| parent | 6d93334ff2cfcf2e63d1e105d32237029b6d4af3 (diff) | |
Merge "Add task scale to the convert to bubble animation" into main
6 files changed, 98 insertions, 50 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java index 5018fdb615da..8e78686ac13d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java @@ -83,7 +83,11 @@ public class SizeChangeAnimation { private static final int ANIMATION_RESOLUTION = 1000; public SizeChangeAnimation(Rect startBounds, Rect endBounds) { - mAnimation = buildContainerAnimation(startBounds, endBounds); + this(startBounds, endBounds, 1f); + } + + public SizeChangeAnimation(Rect startBounds, Rect endBounds, float initialScale) { + mAnimation = buildContainerAnimation(startBounds, endBounds, initialScale); mSnapshotAnim = buildSnapshotAnimation(startBounds, endBounds); } @@ -167,7 +171,8 @@ public class SizeChangeAnimation { } /** Animation for the whole container (snapshot is inside this container). */ - private static AnimationSet buildContainerAnimation(Rect startBounds, Rect endBounds) { + private static AnimationSet buildContainerAnimation(Rect startBounds, Rect endBounds, + float initialScale) { final long duration = ANIMATION_RESOLUTION; boolean growing = endBounds.width() - startBounds.width() + endBounds.height() - startBounds.height() >= 0; @@ -180,15 +185,27 @@ public class SizeChangeAnimation { final Animation scaleAnim = new ScaleAnimation(startScaleX, 1, startScaleY, 1); scaleAnim.setDuration(scalePeriod); + long scaleStartOffset = 0; if (!growing) { - scaleAnim.setStartOffset(duration - scalePeriod); + scaleStartOffset = duration - scalePeriod; } + scaleAnim.setStartOffset(scaleStartOffset); animSet.addAnimation(scaleAnim); + + if (initialScale != 1f) { + final Animation initialScaleAnim = new ScaleAnimation(initialScale, 1f, initialScale, + 1f); + initialScaleAnim.setDuration(scalePeriod); + initialScaleAnim.setStartOffset(scaleStartOffset); + animSet.addAnimation(initialScaleAnim); + } + final Animation translateAnim = new TranslateAnimation(startBounds.left, endBounds.left, startBounds.top, endBounds.top); translateAnim.setDuration(duration); animSet.addAnimation(translateAnim); Rect startClip = new Rect(startBounds); + startClip.scale(initialScale); Rect endClip = new Rect(endBounds); startClip.offsetTo(0, 0); endClip.offsetTo(0, 0); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java index 338ffe76e6ea..e7e7be9cdf6b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java @@ -30,6 +30,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.TaskInfo; import android.content.Context; +import android.graphics.PointF; import android.graphics.Rect; import android.os.IBinder; import android.util.Slog; @@ -155,28 +156,23 @@ public class BubbleTransitions { * Information about the task when it is being dragged to a bubble */ public static class DragData { - private final Rect mBounds; private final WindowContainerTransaction mPendingWct; private final boolean mReleasedOnLeft; + private final float mTaskScale; + private final PointF mDragPosition; /** - * @param bounds bounds of the dragged task when the drag was released - * @param wct pending operations to be applied when finishing the drag * @param releasedOnLeft true if the bubble was released in the left drop target + * @param taskScale the scale of the task when it was dragged to bubble + * @param dragPosition the position of the task when it was dragged to bubble + * @param wct pending operations to be applied when finishing the drag */ - public DragData(@Nullable Rect bounds, @Nullable WindowContainerTransaction wct, - boolean releasedOnLeft) { - mBounds = bounds; + public DragData(boolean releasedOnLeft, float taskScale, @Nullable PointF dragPosition, + @Nullable WindowContainerTransaction wct) { mPendingWct = wct; mReleasedOnLeft = releasedOnLeft; - } - - /** - * @return bounds of the dragged task when the drag was released - */ - @Nullable - public Rect getBounds() { - return mBounds; + mTaskScale = taskScale; + mDragPosition = dragPosition != null ? dragPosition : new PointF(0, 0); } /** @@ -193,6 +189,20 @@ public class BubbleTransitions { public boolean isReleasedOnLeft() { return mReleasedOnLeft; } + + /** + * @return the scale of the task when it was dragged to bubble + */ + public float getTaskScale() { + return mTaskScale; + } + + /** + * @return position of the task when it was dragged to bubble + */ + public PointF getDragPosition() { + return mDragPosition; + } } /** @@ -347,21 +357,24 @@ public class BubbleTransitions { } mFinishCb = finishCallback; - if (mDragData != null && mDragData.getBounds() != null) { - // Override start bounds with the dragged task bounds - mStartBounds.set(mDragData.getBounds()); + if (mDragData != null) { + mStartBounds.offsetTo((int) mDragData.getDragPosition().x, + (int) mDragData.getDragPosition().y); + startTransaction.setScale(mSnapshot, mDragData.getTaskScale(), + mDragData.getTaskScale()); } // Now update state (and talk to launcher) in parallel with snapshot stuff mBubbleData.notificationEntryUpdated(mBubble, /* suppressFlyout= */ true, /* showInShade= */ false); + final int left = mStartBounds.left - info.getRoot(0).getOffset().x; + final int top = mStartBounds.top - info.getRoot(0).getOffset().y; + startTransaction.setPosition(mTaskLeash, left, top); startTransaction.show(mSnapshot); // Move snapshot to root so that it remains visible while task is moved to taskview startTransaction.reparent(mSnapshot, info.getRoot(0).getLeash()); - startTransaction.setPosition(mSnapshot, - mStartBounds.left - info.getRoot(0).getOffset().x, - mStartBounds.top - info.getRoot(0).getOffset().y); + startTransaction.setPosition(mSnapshot, left, top); startTransaction.setLayer(mSnapshot, Integer.MAX_VALUE); BubbleBarExpandedView bbev = mBubble.getBubbleBarExpandedView(); @@ -416,6 +429,8 @@ public class BubbleTransitions { private void playAnimation(boolean animate) { final TaskViewTaskController tv = mBubble.getTaskView().getController(); final SurfaceControl.Transaction startT = new SurfaceControl.Transaction(); + // Set task position to 0,0 as it will be placed inside the TaskView + startT.setPosition(mTaskLeash, 0, 0); mTaskViewTransitions.prepareOpenAnimation(tv, true /* new */, startT, mFinishT, (ActivityManager.RunningTaskInfo) mTaskInfo, mTaskLeash, mFinishWct); @@ -424,10 +439,12 @@ public class BubbleTransitions { } if (animate) { - mLayerView.animateConvert(startT, mStartBounds, mSnapshot, mTaskLeash, () -> { - mFinishCb.onTransitionFinished(mFinishWct); - mFinishCb = null; - }); + float startScale = mDragData != null ? mDragData.getTaskScale() : 1f; + mLayerView.animateConvert(startT, mStartBounds, startScale, mSnapshot, mTaskLeash, + () -> { + mFinishCb.onTransitionFinished(mFinishWct); + mFinishCb = null; + }); } else { startT.apply(); mFinishCb.onTransitionFinished(mFinishWct); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java index 52f20646fb4a..fa22a3961002 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java @@ -580,6 +580,7 @@ public class BubbleBarAnimationHelper { public void animateConvert(BubbleViewProvider expandedBubble, @NonNull SurfaceControl.Transaction startT, @NonNull Rect origBounds, + float origScale, @NonNull SurfaceControl snapshot, @NonNull SurfaceControl taskLeash, @Nullable Runnable afterAnimation) { @@ -599,7 +600,7 @@ public class BubbleBarAnimationHelper { new SizeChangeAnimation( new Rect(origBounds.left - position.x, origBounds.top - position.y, origBounds.right - position.x, origBounds.bottom - position.y), - new Rect(0, 0, size.getWidth(), size.getHeight())); + new Rect(0, 0, size.getWidth(), size.getHeight()), origScale); sca.initialize(bbev, taskLeash, snapshot, startT); Animator a = sca.buildViewAnimator(bbev, tvSf, snapshot, /* onFinish */ (va) -> { @@ -614,6 +615,7 @@ public class BubbleBarAnimationHelper { bbev.setSurfaceZOrderedOnTop(true); a.setDuration(EXPANDED_VIEW_ANIMATE_TO_REST_DURATION); + a.setInterpolator(Interpolators.EMPHASIZED); a.start(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java index 99082f18492c..6c840f020f90 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java @@ -423,13 +423,13 @@ public class BubbleBarLayerView extends FrameLayout * @param startT A transaction with first-frame work. this *will* be applied here! */ public void animateConvert(@NonNull SurfaceControl.Transaction startT, - @NonNull Rect startBounds, @NonNull SurfaceControl snapshot, SurfaceControl taskLeash, - Runnable animFinish) { + @NonNull Rect startBounds, float startScale, @NonNull SurfaceControl snapshot, + SurfaceControl taskLeash, Runnable animFinish) { if (!mIsExpanded || mExpandedBubble == null) { throw new IllegalStateException("Can't animateExpand without expanded state"); } - mAnimationHelper.animateConvert(mExpandedBubble, startT, startBounds, snapshot, taskLeash, - animFinish); + mAnimationHelper.animateConvert(mExpandedBubble, startT, startBounds, startScale, snapshot, + taskLeash, animFinish); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt index c8f7ea9f885f..e943c42dcdfc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt @@ -281,6 +281,7 @@ sealed class DragToDesktopTransitionHandler( val state = requireTransitionState() val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo") val animatedTaskBounds = getAnimatedTaskBounds() + state.dragAnimator.cancelAnimator() requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds) } @@ -292,7 +293,6 @@ sealed class DragToDesktopTransitionHandler( val scaledWidth = taskBounds.width() * taskScale val scaledHeight = taskBounds.height() * taskScale val dragPosition = PointF(state.dragAnimator.position) - state.dragAnimator.cancelAnimator() return Rect( dragPosition.x.toInt(), dragPosition.y.toInt(), @@ -325,22 +325,24 @@ sealed class DragToDesktopTransitionHandler( // TODO(b/391928049): update density once we can drag from desktop to bubble val state = requireTransitionState() val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo") - val taskBounds = getAnimatedTaskBounds() + val dragPosition = PointF(state.dragAnimator.position) + val scale = state.dragAnimator.scale state.dragAnimator.cancelAnimator() - requestBubble(wct, taskInfo, onLeft, taskBounds) + requestBubble(wct, taskInfo, onLeft, scale, dragPosition) } private fun requestBubble( wct: WindowContainerTransaction, taskInfo: RunningTaskInfo, onLeft: Boolean, - taskBounds: Rect = Rect(taskInfo.configuration.windowConfiguration.bounds), + taskScale: Float = 1f, + dragPosition: PointF = PointF(0f, 0f), ) { val controller = bubbleController.orElseThrow { IllegalStateException("BubbleController not set") } controller.expandStackAndSelectBubble( taskInfo, - BubbleTransitions.DragData(taskBounds, wct, onLeft), + BubbleTransitions.DragData(onLeft, taskScale, dragPosition, wct), ) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java index 42310caba1c6..3c79ea7be39f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java @@ -25,6 +25,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; @@ -35,6 +36,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.graphics.PointF; import android.graphics.Rect; import android.os.IBinder; import android.view.SurfaceControl; @@ -138,13 +140,14 @@ public class BubbleTransitionsTest extends ShellTestCase { return taskInfo; } - private TransitionInfo setupFullscreenTaskTransition(ActivityManager.RunningTaskInfo taskInfo) { + private TransitionInfo setupFullscreenTaskTransition(ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl taskLeash, SurfaceControl snapshot) { final TransitionInfo info = new TransitionInfo(TRANSIT_CONVERT_TO_BUBBLE, 0); - final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token, - mock(SurfaceControl.class)); + final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token, taskLeash); chg.setTaskInfo(taskInfo); chg.setMode(TRANSIT_CHANGE); chg.setStartAbsBounds(new Rect(0, 0, FULLSCREEN_TASK_WIDTH, FULLSCREEN_TASK_HEIGHT)); + chg.setSnapshot(snapshot, /* luma= */ 0f); info.addChange(chg); info.addRoot(new TransitionInfo.Root(0, mock(SurfaceControl.class), 0, 0)); return info; @@ -172,7 +175,9 @@ public class BubbleTransitionsTest extends ShellTestCase { // Ensure we are communicating with the taskviewtransitions queue assertTrue(mTaskViewTransitions.hasPending()); - final TransitionInfo info = setupFullscreenTaskTransition(taskInfo); + SurfaceControl taskLeash = new SurfaceControl.Builder().setName("taskLeash").build(); + SurfaceControl snapshot = new SurfaceControl.Builder().setName("snapshot").build(); + final TransitionInfo info = setupFullscreenTaskTransition(taskInfo, taskLeash, snapshot); SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); final boolean[] finishCalled = new boolean[]{false}; @@ -183,7 +188,8 @@ public class BubbleTransitionsTest extends ShellTestCase { ctb.startAnimation(ctb.mTransition, info, startT, finishT, finishCb); assertFalse(mTaskViewTransitions.hasPending()); - verify(startT).setPosition(any(), eq(0f), eq(0f)); + verify(startT).setPosition(taskLeash, 0, 0); + verify(startT).setPosition(snapshot, 0, 0); verify(mBubbleData).notificationEntryUpdated(eq(mBubble), anyBoolean(), anyBoolean()); @@ -194,7 +200,7 @@ public class BubbleTransitionsTest extends ShellTestCase { // Check that preparing transition is not reset before continueExpand is called verify(mBubble, never()).setPreparingTransition(any()); ArgumentCaptor<Runnable> animCb = ArgumentCaptor.forClass(Runnable.class); - verify(mLayerView).animateConvert(any(), any(), any(), any(), animCb.capture()); + verify(mLayerView).animateConvert(any(), any(), anyFloat(), any(), any(), animCb.capture()); // continueExpand is now called, check that preparing transition is cleared ctb.continueExpand(); @@ -209,14 +215,14 @@ public class BubbleTransitionsTest extends ShellTestCase { public void testConvertToBubble_drag() { ActivityManager.RunningTaskInfo taskInfo = setupBubble(); - Rect draggedTaskBounds = new Rect(10, 20, 30, 40); WindowContainerTransaction pendingWct = new WindowContainerTransaction(); WindowContainerToken pendingDragOpToken = createMockToken(); pendingWct.reorder(pendingDragOpToken, /* onTop= */ false); + PointF dragPosition = new PointF(10f, 20f); BubbleTransitions.DragData dragData = new BubbleTransitions.DragData( - draggedTaskBounds, pendingWct, /* releasedOnLeft= */ false - ); + /* releasedOnLeft= */ false, /* taskScale= */ 0.5f, dragPosition, + pendingWct); final BubbleTransitions.BubbleTransition bt = mBubbleTransitions.startConvertToBubble( mBubble, taskInfo, mExpandedViewManager, mTaskViewFactory, mBubblePositioner, @@ -234,15 +240,19 @@ public class BubbleTransitionsTest extends ShellTestCase { == WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER && op.getContainer() == pendingDragOpToken.asBinder())).isTrue(); - final TransitionInfo info = setupFullscreenTaskTransition(taskInfo); + SurfaceControl taskLeash = new SurfaceControl.Builder().setName("taskLeash").build(); + SurfaceControl snapshot = new SurfaceControl.Builder().setName("snapshot").build(); + final TransitionInfo info = setupFullscreenTaskTransition(taskInfo, taskLeash, snapshot); SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); Transitions.TransitionFinishCallback finishCb = wct -> {}; ctb.startAnimation(ctb.mTransition, info, startT, finishT, finishCb); - // Verify that dragged task bounds are used for the position - verify(startT).setPosition(any(), eq((float) draggedTaskBounds.left), - eq((float) draggedTaskBounds.top)); + // Verify that snapshot and task are placed at where the drag ended + verify(startT).setPosition(taskLeash, dragPosition.x, dragPosition.y); + verify(startT).setPosition(snapshot, dragPosition.x, dragPosition.y); + // Snapshot has the scale of the dragged task + verify(startT).setScale(snapshot, dragData.getTaskScale(), dragData.getTaskScale()); } @Test |