Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +9 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.service.notification.NotificationListenerService.REASON_CA import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.TRANSIT_CHANGE; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; Loading Loading @@ -1590,20 +1591,26 @@ public class BubbleController implements ConfigurationChangeListener, * Expands and selects a bubble created from a running task in a different mode. * * @param taskInfo the task. * @param dragData optional information about the task when it is being dragged into a bubble */ public void expandStackAndSelectBubble(ActivityManager.RunningTaskInfo taskInfo) { public void expandStackAndSelectBubble(ActivityManager.RunningTaskInfo taskInfo, @Nullable BubbleTransitions.DragData dragData) { if (!BubbleAnythingFlagHelper.enableBubbleToFullscreen()) return; Bubble b = mBubbleData.getOrCreateBubble(taskInfo); // Removes from overflow ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - intent=%s", taskInfo.taskId); if (b.isInflated()) { mBubbleData.setSelectedBubbleAndExpandStack(b); if (dragData != null && dragData.getPendingWct() != null) { mTransitions.startTransition(TRANSIT_CHANGE, dragData.getPendingWct(), /* handler= */ null); } } else { b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE); // Lazy init stack view when a bubble is created ensureBubbleViewsAndWindowCreated(); mBubbleTransitions.startConvertToBubble(b, taskInfo, mExpandedViewManager, mBubbleTaskViewFactory, mBubblePositioner, mStackView, mLayerView, mBubbleIconFactory, mInflateSynchronously); mBubbleIconFactory, dragData, mInflateSynchronously); } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java +57 −4 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.View.INVISIBLE; import static android.view.WindowManager.TRANSIT_CHANGE; import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; Loading Loading @@ -92,10 +94,10 @@ public class BubbleTransitions { BubbleExpandedViewManager expandedViewManager, BubbleTaskViewFactory factory, BubblePositioner positioner, BubbleStackView stackView, BubbleBarLayerView layerView, BubbleIconFactory iconFactory, boolean inflateSync) { DragData dragData, boolean inflateSync) { return new ConvertToBubble(bubble, taskInfo, mContext, expandedViewManager, factory, positioner, stackView, layerView, iconFactory, inflateSync); dragData, inflateSync); } /** Loading Loading @@ -148,6 +150,39 @@ public class BubbleTransitions { default void continueCollapse() {} } /** * Information about the task when it is being dragged to a bubble */ public static class DragData { private final Rect mBounds; private final WindowContainerTransaction mPendingWct; /** * @param bounds bounds of the dragged task when the drag was released * @param wct pending operations to be applied when finishing the drag */ public DragData(@Nullable Rect bounds, @Nullable WindowContainerTransaction wct) { mBounds = bounds; mPendingWct = wct; } /** * @return bounds of the dragged task when the drag was released */ @Nullable public Rect getBounds() { return mBounds; } /** * @return pending operations to be applied when finishing the drag */ @Nullable public WindowContainerTransaction getPendingWct() { return mPendingWct; } } /** * BubbleTransition that coordinates the process of a non-bubble task becoming a bubble. The * steps are as follows: Loading @@ -167,6 +202,7 @@ public class BubbleTransitions { class ConvertToBubble implements Transitions.TransitionHandler, BubbleTransition { final BubbleBarLayerView mLayerView; Bubble mBubble; @Nullable DragData mDragData; IBinder mTransition; Transitions.TransitionFinishCallback mFinishCb; WindowContainerTransaction mFinishWct = null; Loading @@ -182,10 +218,12 @@ public class BubbleTransitions { ConvertToBubble(Bubble bubble, TaskInfo taskInfo, Context context, BubbleExpandedViewManager expandedViewManager, BubbleTaskViewFactory factory, BubblePositioner positioner, BubbleStackView stackView, BubbleBarLayerView layerView, BubbleIconFactory iconFactory, boolean inflateSync) { BubbleBarLayerView layerView, BubbleIconFactory iconFactory, @Nullable DragData dragData, boolean inflateSync) { mBubble = bubble; mTaskInfo = taskInfo; mLayerView = layerView; mDragData = dragData; mBubble.setInflateSynchronously(inflateSync); mBubble.setPreparingTransition(this); mBubble.inflate( Loading @@ -208,6 +246,9 @@ public class BubbleTransitions { final Rect launchBounds = new Rect(); mLayerView.getExpandedViewRestBounds(launchBounds); WindowContainerTransaction wct = new WindowContainerTransaction(); if (mDragData != null && mDragData.getPendingWct() != null) { wct.merge(mDragData.getPendingWct(), true); } if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { if (mTaskInfo.getParentTaskId() != INVALID_TASK_ID) { wct.reparent(mTaskInfo.token, null, true); Loading @@ -226,7 +267,7 @@ public class BubbleTransitions { state.mVisible = true; } mTaskViewTransitions.enqueueExternal(tv.getController(), () -> { mTransition = mTransitions.startTransition(TRANSIT_CHANGE, wct, this); mTransition = mTransitions.startTransition(TRANSIT_CONVERT_TO_BUBBLE, wct, this); return mTransition; }); } Loading Loading @@ -292,6 +333,11 @@ public class BubbleTransitions { } mFinishCb = finishCallback; if (mDragData != null && mDragData.getBounds() != null) { // Override start bounds with the dragged task bounds mStartBounds.set(mDragData.getBounds()); } // Now update state (and talk to launcher) in parallel with snapshot stuff mBubbleData.notificationEntryUpdated(mBubble, /* suppressFlyout= */ true, /* showInShade= */ false); Loading @@ -303,6 +349,13 @@ public class BubbleTransitions { mStartBounds.left - info.getRoot(0).getOffset().x, mStartBounds.top - info.getRoot(0).getOffset().y); startTransaction.setLayer(mSnapshot, Integer.MAX_VALUE); BubbleBarExpandedView bbev = mBubble.getBubbleBarExpandedView(); if (bbev != null) { // Corners get reset during the animation. Add them back startTransaction.setCornerRadius(mSnapshot, bbev.getRestingCornerRadius()); } startTransaction.apply(); mTaskViewTransitions.onExternalDone(transition); Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +4 −3 Original line number Diff line number Diff line Loading @@ -915,14 +915,15 @@ public abstract class WMShellModule { Transitions transitions, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, @DynamicOverride DesktopUserRepositories desktopUserRepositories, InteractionJankMonitor interactionJankMonitor) { InteractionJankMonitor interactionJankMonitor, Optional<BubbleController> bubbleController) { return ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX.isTrue() ? new SpringDragToDesktopTransitionHandler( context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories, interactionJankMonitor) interactionJankMonitor, bubbleController) : new DefaultDragToDesktopTransitionHandler( context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories, interactionJankMonitor); interactionJankMonitor, bubbleController); } @WMSingleton Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +13 −5 Original line number Diff line number Diff line Loading @@ -2689,15 +2689,22 @@ class DesktopTasksController( } /** Requests a task be transitioned from whatever mode it's in to a bubble. */ fun requestFloat(taskInfo: RunningTaskInfo) { @JvmOverloads fun requestFloat(taskInfo: RunningTaskInfo, left: Boolean? = null) { val isDragging = dragToDesktopTransitionHandler.inProgress val shouldRequestFloat = taskInfo.isFullscreen || taskInfo.isFreeform || isDragging || taskInfo.isMultiWindow if (!shouldRequestFloat) return if (isDragging) { releaseVisualIndicator() val cancelState = if (left == true) DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_LEFT else DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_RIGHT dragToDesktopTransitionHandler.cancelDragToDesktopTransition(cancelState) } else { bubbleController.ifPresent { it.expandStackAndSelectBubble(taskInfo) } bubbleController.ifPresent { it.expandStackAndSelectBubble(taskInfo, /* dragData= */ null) } } } Loading Loading @@ -2975,10 +2982,11 @@ class DesktopTasksController( ) requestSplit(taskInfo, leftOrTop = false) } IndicatorType.TO_BUBBLE_LEFT_INDICATOR, IndicatorType.TO_BUBBLE_LEFT_INDICATOR -> { requestFloat(taskInfo, left = true) } IndicatorType.TO_BUBBLE_RIGHT_INDICATOR -> { // TODO(b/388851898): move to bubble cancelDragToDesktop(taskInfo) requestFloat(taskInfo, left = false) } } return indicatorType Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +76 −8 Original line number Diff line number Diff line Loading @@ -37,6 +37,8 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.internal.protolog.ProtoLog import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.animation.FloatProperties import com.android.wm.shell.bubbles.BubbleController import com.android.wm.shell.bubbles.BubbleTransitions import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP Loading @@ -49,10 +51,12 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UND import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE import com.android.wm.shell.transition.Transitions.TransitionHandler import com.android.wm.shell.windowdecor.MoveToDesktopAnimator import com.android.wm.shell.windowdecor.MoveToDesktopAnimator.Companion.DRAG_FREEFORM_SCALE import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener import java.util.Optional import java.util.function.Supplier import kotlin.math.max Loading @@ -72,6 +76,7 @@ sealed class DragToDesktopTransitionHandler( private val taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, private val desktopUserRepositories: DesktopUserRepositories, protected val interactionJankMonitor: InteractionJankMonitor, private val bubbleController: Optional<BubbleController>, protected val transactionSupplier: Supplier<SurfaceControl.Transaction>, ) : TransitionHandler { Loading Loading @@ -241,6 +246,20 @@ sealed class DragToDesktopTransitionHandler( state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null) requestSplitFromScaledTask(splitPosition, wct) clearState() } else if ( state.draggedTaskChange != null && (cancelState == CancelState.CANCEL_BUBBLE_LEFT || cancelState == CancelState.CANCEL_BUBBLE_RIGHT) ) { if (!bubbleController.isPresent) { startCancelAnimation() } else { // Animation is handled by BubbleController val wct = WindowContainerTransaction() restoreWindowOrder(wct, state) // TODO(b/388851898): pass along information about left or right side requestBubbleFromScaledTask(wct) } } else { // There's no dragged task, this can happen when the "cancel" happened too quickly // before the "start" transition is even ready (like on a fling gesture). The Loading @@ -256,6 +275,13 @@ sealed class DragToDesktopTransitionHandler( @SplitPosition splitPosition: Int, wct: WindowContainerTransaction, ) { val state = requireTransitionState() val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo") val animatedTaskBounds = getAnimatedTaskBounds() requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds) } private fun getAnimatedTaskBounds(): Rect { val state = requireTransitionState() val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo") val taskBounds = Rect(taskInfo.configuration.windowConfiguration.bounds) Loading @@ -264,14 +290,12 @@ sealed class DragToDesktopTransitionHandler( val scaledHeight = taskBounds.height() * taskScale val dragPosition = PointF(state.dragAnimator.position) state.dragAnimator.cancelAnimator() val animatedTaskBounds = Rect( return Rect( dragPosition.x.toInt(), dragPosition.y.toInt(), (dragPosition.x + scaledWidth).toInt(), (dragPosition.y + scaledHeight).toInt(), ) requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds) } private fun requestSplitSelect( Loading @@ -294,6 +318,25 @@ sealed class DragToDesktopTransitionHandler( splitScreenController.requestEnterSplitSelect(taskInfo, wct, splitPosition, taskBounds) } private fun requestBubbleFromScaledTask(wct: WindowContainerTransaction) { // 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() state.dragAnimator.cancelAnimator() requestBubble(wct, taskInfo, taskBounds) } private fun requestBubble( wct: WindowContainerTransaction, taskInfo: RunningTaskInfo, taskBounds: Rect = Rect(taskInfo.configuration.windowConfiguration.bounds), ) { val controller = bubbleController.orElseThrow { IllegalStateException("BubbleController not set") } controller.expandStackAndSelectBubble(taskInfo, BubbleTransitions.DragData(taskBounds, wct)) } override fun startAnimation( transition: IBinder, info: TransitionInfo, Loading Loading @@ -446,6 +489,16 @@ sealed class DragToDesktopTransitionHandler( state.startTransitionFinishTransaction?.apply() state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null) requestSplitSelect(wct, taskInfo, splitPosition) } else if ( state.cancelState == CancelState.CANCEL_BUBBLE_LEFT || state.cancelState == CancelState.CANCEL_BUBBLE_RIGHT ) { val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null task info.") val wct = WindowContainerTransaction() restoreWindowOrder(wct) // TODO(b/388851898): pass along information about left or right side requestBubble(wct, taskInfo) } return true } Loading Loading @@ -476,6 +529,13 @@ sealed class DragToDesktopTransitionHandler( clearState() return } // In case of bubble animation, finish the initial desktop drag animation, but keep the // current animation running and have bubbles take over if (info.type == TRANSIT_CONVERT_TO_BUBBLE) { state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null) clearState() return } val isCancelTransition = info.type == TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP && transition == state.cancelTransitionToken && Loading Loading @@ -869,6 +929,10 @@ sealed class DragToDesktopTransitionHandler( CANCEL_SPLIT_LEFT, /** A cancel event where the task will request to enter split on the right side. */ CANCEL_SPLIT_RIGHT, /** A cancel event where the task will request to bubble on the left side. */ CANCEL_BUBBLE_LEFT, /** A cancel event where the task will request to bubble on the right side. */ CANCEL_BUBBLE_RIGHT, } companion object { Loading @@ -887,6 +951,7 @@ constructor( taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, desktopUserRepositories: DesktopUserRepositories, interactionJankMonitor: InteractionJankMonitor, bubbleController: Optional<BubbleController>, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() }, Loading @@ -897,6 +962,7 @@ constructor( taskDisplayAreaOrganizer, desktopUserRepositories, interactionJankMonitor, bubbleController, transactionSupplier, ) { Loading Loading @@ -925,6 +991,7 @@ constructor( taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, desktopUserRepositories: DesktopUserRepositories, interactionJankMonitor: InteractionJankMonitor, bubbleController: Optional<BubbleController>, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() }, Loading @@ -935,6 +1002,7 @@ constructor( taskDisplayAreaOrganizer, desktopUserRepositories, interactionJankMonitor, bubbleController, transactionSupplier, ) { Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +9 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.service.notification.NotificationListenerService.REASON_CA import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.TRANSIT_CHANGE; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; Loading Loading @@ -1590,20 +1591,26 @@ public class BubbleController implements ConfigurationChangeListener, * Expands and selects a bubble created from a running task in a different mode. * * @param taskInfo the task. * @param dragData optional information about the task when it is being dragged into a bubble */ public void expandStackAndSelectBubble(ActivityManager.RunningTaskInfo taskInfo) { public void expandStackAndSelectBubble(ActivityManager.RunningTaskInfo taskInfo, @Nullable BubbleTransitions.DragData dragData) { if (!BubbleAnythingFlagHelper.enableBubbleToFullscreen()) return; Bubble b = mBubbleData.getOrCreateBubble(taskInfo); // Removes from overflow ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - intent=%s", taskInfo.taskId); if (b.isInflated()) { mBubbleData.setSelectedBubbleAndExpandStack(b); if (dragData != null && dragData.getPendingWct() != null) { mTransitions.startTransition(TRANSIT_CHANGE, dragData.getPendingWct(), /* handler= */ null); } } else { b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE); // Lazy init stack view when a bubble is created ensureBubbleViewsAndWindowCreated(); mBubbleTransitions.startConvertToBubble(b, taskInfo, mExpandedViewManager, mBubbleTaskViewFactory, mBubblePositioner, mStackView, mLayerView, mBubbleIconFactory, mInflateSynchronously); mBubbleIconFactory, dragData, mInflateSynchronously); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java +57 −4 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.View.INVISIBLE; import static android.view.WindowManager.TRANSIT_CHANGE; import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; Loading Loading @@ -92,10 +94,10 @@ public class BubbleTransitions { BubbleExpandedViewManager expandedViewManager, BubbleTaskViewFactory factory, BubblePositioner positioner, BubbleStackView stackView, BubbleBarLayerView layerView, BubbleIconFactory iconFactory, boolean inflateSync) { DragData dragData, boolean inflateSync) { return new ConvertToBubble(bubble, taskInfo, mContext, expandedViewManager, factory, positioner, stackView, layerView, iconFactory, inflateSync); dragData, inflateSync); } /** Loading Loading @@ -148,6 +150,39 @@ public class BubbleTransitions { default void continueCollapse() {} } /** * Information about the task when it is being dragged to a bubble */ public static class DragData { private final Rect mBounds; private final WindowContainerTransaction mPendingWct; /** * @param bounds bounds of the dragged task when the drag was released * @param wct pending operations to be applied when finishing the drag */ public DragData(@Nullable Rect bounds, @Nullable WindowContainerTransaction wct) { mBounds = bounds; mPendingWct = wct; } /** * @return bounds of the dragged task when the drag was released */ @Nullable public Rect getBounds() { return mBounds; } /** * @return pending operations to be applied when finishing the drag */ @Nullable public WindowContainerTransaction getPendingWct() { return mPendingWct; } } /** * BubbleTransition that coordinates the process of a non-bubble task becoming a bubble. The * steps are as follows: Loading @@ -167,6 +202,7 @@ public class BubbleTransitions { class ConvertToBubble implements Transitions.TransitionHandler, BubbleTransition { final BubbleBarLayerView mLayerView; Bubble mBubble; @Nullable DragData mDragData; IBinder mTransition; Transitions.TransitionFinishCallback mFinishCb; WindowContainerTransaction mFinishWct = null; Loading @@ -182,10 +218,12 @@ public class BubbleTransitions { ConvertToBubble(Bubble bubble, TaskInfo taskInfo, Context context, BubbleExpandedViewManager expandedViewManager, BubbleTaskViewFactory factory, BubblePositioner positioner, BubbleStackView stackView, BubbleBarLayerView layerView, BubbleIconFactory iconFactory, boolean inflateSync) { BubbleBarLayerView layerView, BubbleIconFactory iconFactory, @Nullable DragData dragData, boolean inflateSync) { mBubble = bubble; mTaskInfo = taskInfo; mLayerView = layerView; mDragData = dragData; mBubble.setInflateSynchronously(inflateSync); mBubble.setPreparingTransition(this); mBubble.inflate( Loading @@ -208,6 +246,9 @@ public class BubbleTransitions { final Rect launchBounds = new Rect(); mLayerView.getExpandedViewRestBounds(launchBounds); WindowContainerTransaction wct = new WindowContainerTransaction(); if (mDragData != null && mDragData.getPendingWct() != null) { wct.merge(mDragData.getPendingWct(), true); } if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { if (mTaskInfo.getParentTaskId() != INVALID_TASK_ID) { wct.reparent(mTaskInfo.token, null, true); Loading @@ -226,7 +267,7 @@ public class BubbleTransitions { state.mVisible = true; } mTaskViewTransitions.enqueueExternal(tv.getController(), () -> { mTransition = mTransitions.startTransition(TRANSIT_CHANGE, wct, this); mTransition = mTransitions.startTransition(TRANSIT_CONVERT_TO_BUBBLE, wct, this); return mTransition; }); } Loading Loading @@ -292,6 +333,11 @@ public class BubbleTransitions { } mFinishCb = finishCallback; if (mDragData != null && mDragData.getBounds() != null) { // Override start bounds with the dragged task bounds mStartBounds.set(mDragData.getBounds()); } // Now update state (and talk to launcher) in parallel with snapshot stuff mBubbleData.notificationEntryUpdated(mBubble, /* suppressFlyout= */ true, /* showInShade= */ false); Loading @@ -303,6 +349,13 @@ public class BubbleTransitions { mStartBounds.left - info.getRoot(0).getOffset().x, mStartBounds.top - info.getRoot(0).getOffset().y); startTransaction.setLayer(mSnapshot, Integer.MAX_VALUE); BubbleBarExpandedView bbev = mBubble.getBubbleBarExpandedView(); if (bbev != null) { // Corners get reset during the animation. Add them back startTransaction.setCornerRadius(mSnapshot, bbev.getRestingCornerRadius()); } startTransaction.apply(); mTaskViewTransitions.onExternalDone(transition); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +4 −3 Original line number Diff line number Diff line Loading @@ -915,14 +915,15 @@ public abstract class WMShellModule { Transitions transitions, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, @DynamicOverride DesktopUserRepositories desktopUserRepositories, InteractionJankMonitor interactionJankMonitor) { InteractionJankMonitor interactionJankMonitor, Optional<BubbleController> bubbleController) { return ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX.isTrue() ? new SpringDragToDesktopTransitionHandler( context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories, interactionJankMonitor) interactionJankMonitor, bubbleController) : new DefaultDragToDesktopTransitionHandler( context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories, interactionJankMonitor); interactionJankMonitor, bubbleController); } @WMSingleton Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +13 −5 Original line number Diff line number Diff line Loading @@ -2689,15 +2689,22 @@ class DesktopTasksController( } /** Requests a task be transitioned from whatever mode it's in to a bubble. */ fun requestFloat(taskInfo: RunningTaskInfo) { @JvmOverloads fun requestFloat(taskInfo: RunningTaskInfo, left: Boolean? = null) { val isDragging = dragToDesktopTransitionHandler.inProgress val shouldRequestFloat = taskInfo.isFullscreen || taskInfo.isFreeform || isDragging || taskInfo.isMultiWindow if (!shouldRequestFloat) return if (isDragging) { releaseVisualIndicator() val cancelState = if (left == true) DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_LEFT else DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_RIGHT dragToDesktopTransitionHandler.cancelDragToDesktopTransition(cancelState) } else { bubbleController.ifPresent { it.expandStackAndSelectBubble(taskInfo) } bubbleController.ifPresent { it.expandStackAndSelectBubble(taskInfo, /* dragData= */ null) } } } Loading Loading @@ -2975,10 +2982,11 @@ class DesktopTasksController( ) requestSplit(taskInfo, leftOrTop = false) } IndicatorType.TO_BUBBLE_LEFT_INDICATOR, IndicatorType.TO_BUBBLE_LEFT_INDICATOR -> { requestFloat(taskInfo, left = true) } IndicatorType.TO_BUBBLE_RIGHT_INDICATOR -> { // TODO(b/388851898): move to bubble cancelDragToDesktop(taskInfo) requestFloat(taskInfo, left = false) } } return indicatorType Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +76 −8 Original line number Diff line number Diff line Loading @@ -37,6 +37,8 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.internal.protolog.ProtoLog import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.animation.FloatProperties import com.android.wm.shell.bubbles.BubbleController import com.android.wm.shell.bubbles.BubbleTransitions import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP Loading @@ -49,10 +51,12 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UND import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE import com.android.wm.shell.transition.Transitions.TransitionHandler import com.android.wm.shell.windowdecor.MoveToDesktopAnimator import com.android.wm.shell.windowdecor.MoveToDesktopAnimator.Companion.DRAG_FREEFORM_SCALE import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener import java.util.Optional import java.util.function.Supplier import kotlin.math.max Loading @@ -72,6 +76,7 @@ sealed class DragToDesktopTransitionHandler( private val taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, private val desktopUserRepositories: DesktopUserRepositories, protected val interactionJankMonitor: InteractionJankMonitor, private val bubbleController: Optional<BubbleController>, protected val transactionSupplier: Supplier<SurfaceControl.Transaction>, ) : TransitionHandler { Loading Loading @@ -241,6 +246,20 @@ sealed class DragToDesktopTransitionHandler( state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null) requestSplitFromScaledTask(splitPosition, wct) clearState() } else if ( state.draggedTaskChange != null && (cancelState == CancelState.CANCEL_BUBBLE_LEFT || cancelState == CancelState.CANCEL_BUBBLE_RIGHT) ) { if (!bubbleController.isPresent) { startCancelAnimation() } else { // Animation is handled by BubbleController val wct = WindowContainerTransaction() restoreWindowOrder(wct, state) // TODO(b/388851898): pass along information about left or right side requestBubbleFromScaledTask(wct) } } else { // There's no dragged task, this can happen when the "cancel" happened too quickly // before the "start" transition is even ready (like on a fling gesture). The Loading @@ -256,6 +275,13 @@ sealed class DragToDesktopTransitionHandler( @SplitPosition splitPosition: Int, wct: WindowContainerTransaction, ) { val state = requireTransitionState() val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo") val animatedTaskBounds = getAnimatedTaskBounds() requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds) } private fun getAnimatedTaskBounds(): Rect { val state = requireTransitionState() val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo") val taskBounds = Rect(taskInfo.configuration.windowConfiguration.bounds) Loading @@ -264,14 +290,12 @@ sealed class DragToDesktopTransitionHandler( val scaledHeight = taskBounds.height() * taskScale val dragPosition = PointF(state.dragAnimator.position) state.dragAnimator.cancelAnimator() val animatedTaskBounds = Rect( return Rect( dragPosition.x.toInt(), dragPosition.y.toInt(), (dragPosition.x + scaledWidth).toInt(), (dragPosition.y + scaledHeight).toInt(), ) requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds) } private fun requestSplitSelect( Loading @@ -294,6 +318,25 @@ sealed class DragToDesktopTransitionHandler( splitScreenController.requestEnterSplitSelect(taskInfo, wct, splitPosition, taskBounds) } private fun requestBubbleFromScaledTask(wct: WindowContainerTransaction) { // 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() state.dragAnimator.cancelAnimator() requestBubble(wct, taskInfo, taskBounds) } private fun requestBubble( wct: WindowContainerTransaction, taskInfo: RunningTaskInfo, taskBounds: Rect = Rect(taskInfo.configuration.windowConfiguration.bounds), ) { val controller = bubbleController.orElseThrow { IllegalStateException("BubbleController not set") } controller.expandStackAndSelectBubble(taskInfo, BubbleTransitions.DragData(taskBounds, wct)) } override fun startAnimation( transition: IBinder, info: TransitionInfo, Loading Loading @@ -446,6 +489,16 @@ sealed class DragToDesktopTransitionHandler( state.startTransitionFinishTransaction?.apply() state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null) requestSplitSelect(wct, taskInfo, splitPosition) } else if ( state.cancelState == CancelState.CANCEL_BUBBLE_LEFT || state.cancelState == CancelState.CANCEL_BUBBLE_RIGHT ) { val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null task info.") val wct = WindowContainerTransaction() restoreWindowOrder(wct) // TODO(b/388851898): pass along information about left or right side requestBubble(wct, taskInfo) } return true } Loading Loading @@ -476,6 +529,13 @@ sealed class DragToDesktopTransitionHandler( clearState() return } // In case of bubble animation, finish the initial desktop drag animation, but keep the // current animation running and have bubbles take over if (info.type == TRANSIT_CONVERT_TO_BUBBLE) { state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null) clearState() return } val isCancelTransition = info.type == TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP && transition == state.cancelTransitionToken && Loading Loading @@ -869,6 +929,10 @@ sealed class DragToDesktopTransitionHandler( CANCEL_SPLIT_LEFT, /** A cancel event where the task will request to enter split on the right side. */ CANCEL_SPLIT_RIGHT, /** A cancel event where the task will request to bubble on the left side. */ CANCEL_BUBBLE_LEFT, /** A cancel event where the task will request to bubble on the right side. */ CANCEL_BUBBLE_RIGHT, } companion object { Loading @@ -887,6 +951,7 @@ constructor( taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, desktopUserRepositories: DesktopUserRepositories, interactionJankMonitor: InteractionJankMonitor, bubbleController: Optional<BubbleController>, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() }, Loading @@ -897,6 +962,7 @@ constructor( taskDisplayAreaOrganizer, desktopUserRepositories, interactionJankMonitor, bubbleController, transactionSupplier, ) { Loading Loading @@ -925,6 +991,7 @@ constructor( taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, desktopUserRepositories: DesktopUserRepositories, interactionJankMonitor: InteractionJankMonitor, bubbleController: Optional<BubbleController>, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() }, Loading @@ -935,6 +1002,7 @@ constructor( taskDisplayAreaOrganizer, desktopUserRepositories, interactionJankMonitor, bubbleController, transactionSupplier, ) { Loading