From c91ef50257cf60db280dd3811bef976c075232a3 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Wed, 23 Nov 2022 14:15:07 -0800 Subject: [PATCH] Animate split confirmation after second app selection from workspace Fixes: 239824922 Test: https://recall.googleplex.com/projects/f46cfe9c-8076-4efe-bf8a-b1cc4f1f5e1b/sessions/099acb31-1e05-4d00-a670-590c177a846e Change-Id: Ifb769afcaf694a1157444f273da69331db15ab1a --- .../popup/QuickstepSystemShortcut.java | 14 +++- .../logging/StatsLogCompatManager.java | 4 + .../util/SplitToWorkspaceController.java | 77 ++++++++++++++++++- 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java index 7cf8201767..c65fa5fd90 100644 --- a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java +++ b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java @@ -19,6 +19,8 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSP import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition; import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Rect; @@ -115,13 +117,19 @@ public interface QuickstepSystemShortcut { PendingAnimation anim = new PendingAnimation(TABLET_HOME_TO_SPLIT.getDuration()); RectF startingTaskRect = new RectF(); - FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(mTarget, - source.view, null /* thumbnail */, - source.drawable, startingTaskRect); + final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(mTarget, + source.view, null /* thumbnail */, source.drawable, startingTaskRect); floatingTaskView.setAlpha(1); floatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect, false /* fadeWithThumbnail */, true /* isStagedTask */); controller.setFirstFloatingTaskView(floatingTaskView); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + mTarget.getDragLayer().removeView(floatingTaskView); + controller.resetState(); + } + }); anim.buildAnim().start(); } } diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 0ef4597c47..0a155cbd47 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -342,6 +342,10 @@ public class StatsLogCompatManager extends StatsLogManager { return; } + if (mItemInfo == null) { + return; + } + if (mItemInfo.container < 0 || appState == null) { // Write log on the model thread so that logs do not go out of order // (for eg: drop comes after drag) diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java index e8a4b0a324..e5c74dc2e3 100644 --- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java +++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java @@ -19,21 +19,39 @@ package com.android.quickstep.util; import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS; import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.content.Intent; +import android.graphics.Rect; +import android.graphics.RectF; import android.view.View; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; +import com.android.launcher3.R; +import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.quickstep.views.FloatingTaskView; +import com.android.quickstep.views.RecentsView; +import com.android.systemui.shared.system.InteractionJankMonitorWrapper; /** Handles when the stage split lands on the home screen. */ public class SplitToWorkspaceController { private final Launcher mLauncher; + private final DeviceProfile mDP; private final SplitSelectStateController mController; + private final int mHalfDividerSize; + public SplitToWorkspaceController(Launcher launcher, SplitSelectStateController controller) { mLauncher = launcher; + mDP = mLauncher.getDeviceProfile(); mController = controller; + + mHalfDividerSize = mLauncher.getResources().getDimensionPixelSize( + R.dimen.multi_window_task_divider_size) / 2; } /** @@ -48,19 +66,74 @@ public class SplitToWorkspaceController { } Object tag = view.getTag(); Intent intent; + BitmapInfo bitmapInfo; if (tag instanceof WorkspaceItemInfo) { final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) tag; intent = workspaceItemInfo.intent; + bitmapInfo = workspaceItemInfo.bitmap; } else if (tag instanceof com.android.launcher3.model.data.AppInfo) { final com.android.launcher3.model.data.AppInfo appInfo = (com.android.launcher3.model.data.AppInfo) tag; intent = appInfo.intent; + bitmapInfo = appInfo.bitmap; } else { return false; } + mController.setSecondTask(intent); - mController.launchSplitTasks(aBoolean -> mLauncher.getDragLayer().removeView( - mController.getFirstFloatingTaskView())); + + boolean isTablet = mLauncher.getDeviceProfile().isTablet; + SplitAnimationTimings timings = AnimUtils.getDeviceSplitToConfirmTimings(isTablet); + PendingAnimation pendingAnimation = new PendingAnimation(timings.getDuration()); + + Rect firstTaskStartingBounds = new Rect(); + Rect firstTaskEndingBounds = new Rect(); + RectF secondTaskStartingBounds = new RectF(); + Rect secondTaskEndingBounds = new Rect(); + + RecentsView recentsView = mLauncher.getOverviewPanel(); + recentsView.getPagedOrientationHandler().getFinalSplitPlaceholderBounds(mHalfDividerSize, + mDP, mController.getActiveSplitStagePosition(), firstTaskEndingBounds, + secondTaskEndingBounds); + + FloatingTaskView firstFloatingTaskView = mController.getFirstFloatingTaskView(); + firstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds); + firstFloatingTaskView.addConfirmAnimation(pendingAnimation, + new RectF(firstTaskStartingBounds), firstTaskEndingBounds, + false /* fadeWithThumbnail */, true /* isStagedTask */); + + FloatingTaskView secondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mLauncher, + view, null /* thumbnail */, bitmapInfo.newIcon(mLauncher), + secondTaskStartingBounds); + secondFloatingTaskView.setAlpha(1); + secondFloatingTaskView.addConfirmAnimation(pendingAnimation, secondTaskStartingBounds, + secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isStagedTask */); + + pendingAnimation.addListener(new AnimatorListenerAdapter() { + private boolean mIsCancelled = false; + + @Override + public void onAnimationCancel(Animator animation) { + mIsCancelled = true; + cleanUp(); + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!mIsCancelled) { + mController.launchSplitTasks(aBoolean -> cleanUp()); + InteractionJankMonitorWrapper.end( + InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER); + } + } + + private void cleanUp() { + mLauncher.getDragLayer().removeView(firstFloatingTaskView); + mLauncher.getDragLayer().removeView(secondFloatingTaskView); + mController.resetState(); + } + }); + pendingAnimation.buildAnim().start(); return true; } }