Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +8 −3 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.launcher3.icons.IconProvider; import com.android.window.flags.Flags; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; Loading @@ -58,6 +59,7 @@ import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.dagger.back.ShellBackAnimationModule; import com.android.wm.shell.dagger.pip.PipModule; import com.android.wm.shell.desktopmode.DefaultDragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopModeTaskRepository; Loading @@ -68,6 +70,7 @@ import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator; import com.android.wm.shell.desktopmode.SpringDragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.GlobalDragListener; Loading Loading @@ -603,9 +606,11 @@ public abstract class WMShellModule { Context context, Transitions transitions, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, Optional<DesktopTasksLimiter> desktopTasksLimiter, InteractionJankMonitor interactionJankMonitor) { return new DragToDesktopTransitionHandler(context, transitions, return Flags.enableDesktopWindowingTransitions() ? new SpringDragToDesktopTransitionHandler(context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor) : new DefaultDragToDesktopTransitionHandler(context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +240 −127 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.view.WindowManager.TRANSIT_CLOSE import android.window.TransitionInfo import android.window.TransitionInfo.Change import android.window.TransitionRequestInfo import android.window.WindowContainerToken import android.window.WindowContainerTransaction import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE Loading Loading @@ -55,8 +54,13 @@ import java.util.function.Supplier * Handles the transition to enter desktop from fullscreen by dragging on the handle bar. It also * handles the cancellation case where the task is dragged back to the status bar area in the same * gesture. * * It's a base sealed class that delegates flag dependant logic to its subclasses: * [DefaultDragToDesktopTransitionHandler] and [SpringDragToDesktopTransitionHandler] * * TODO(b/356764679): Clean up after the full flag rollout */ class DragToDesktopTransitionHandler( sealed class DragToDesktopTransitionHandler( private val context: Context, private val transitions: Transitions, private val taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, Loading @@ -64,19 +68,6 @@ class DragToDesktopTransitionHandler( private val transactionSupplier: Supplier<SurfaceControl.Transaction>, ) : TransitionHandler { constructor( context: Context, transitions: Transitions, rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, interactionJankMonitor: InteractionJankMonitor ) : this( context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor, Supplier { SurfaceControl.Transaction() } ) private val rectEvaluator = RectEvaluator(Rect()) private val launchHomeIntent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) Loading Loading @@ -307,24 +298,18 @@ class DragToDesktopTransitionHandler( return false } // Layering: non-wallpaper, non-home tasks excluding the dragged task go at the bottom, // then Home on top of that, wallpaper on top of that and finally the dragged task on top // of everything. val appLayers = info.changes.size val homeLayers = info.changes.size * 2 val wallpaperLayers = info.changes.size * 3 val dragLayer = wallpaperLayers val layers = calculateStartDragToDesktopLayers(info) val leafTaskFilter = TransitionUtil.LeafTaskFilter() info.changes.withIndex().forEach { (i, change) -> if (TransitionUtil.isWallpaper(change)) { val layer = wallpaperLayers - i val layer = layers.wallpaperLayers - i startTransaction.apply { setLayer(change.leash, layer) show(change.leash) } } else if (isHomeChange(change)) { state.homeToken = change.container val layer = homeLayers - i state.homeChange = change val layer = layers.homeLayers - i startTransaction.apply { setLayer(change.leash, layer) show(change.leash) Loading @@ -338,11 +323,11 @@ class DragToDesktopTransitionHandler( if (state.cancelState == CancelState.NO_CANCEL) { // Normal case, split root goes to the bottom behind everything // else. appLayers - i layers.appLayers - i } else { // Cancel-early case, pretend nothing happened so split root stays // top. dragLayer layers.dragLayer } startTransaction.apply { setLayer(change.leash, layer) Loading @@ -357,7 +342,7 @@ class DragToDesktopTransitionHandler( state.draggedTaskChange = change val bounds = change.endAbsBounds startTransaction.apply { setLayer(change.leash, dragLayer) setLayer(change.leash, layers.dragLayer) setWindowCrop(change.leash, bounds.width(), bounds.height()) show(change.leash) } Loading @@ -370,7 +355,7 @@ class DragToDesktopTransitionHandler( state.otherRootChanges.add(change) val bounds = change.endAbsBounds startTransaction.apply { setLayer(change.leash, appLayers - i) setLayer(change.leash, layers.appLayers - i) setWindowCrop(change.leash, bounds.width(), bounds.height()) show(change.leash) } Loading Loading @@ -404,7 +389,7 @@ class DragToDesktopTransitionHandler( ) val bounds = change.endAbsBounds startTransaction.apply { setLayer(change.leash, dragLayer) setLayer(change.leash, layers.dragLayer) setWindowCrop(change.leash, bounds.width(), bounds.height()) show(change.leash) } Loading Loading @@ -452,6 +437,15 @@ class DragToDesktopTransitionHandler( return true } /** * Calculates start drag to desktop layers for transition [info]. The leash layer is calculated * based on its change position in the transition, e.g. `appLayer = appLayers - i`, where i is * the change index. */ protected abstract fun calculateStartDragToDesktopLayers( info: TransitionInfo ): DragToDesktopLayers override fun mergeAnimation( transition: IBinder, info: TransitionInfo, Loading Loading @@ -483,40 +477,73 @@ class DragToDesktopTransitionHandler( state.startTransitionFinishCb ?: error("Start transition expected to be waiting for merge but wasn't") if (isEndTransition) { info.changes.withIndex().forEach { (i, change) -> // If we're exiting split, hide the remaining split task. if ( state is TransitionState.FromSplit && change.taskInfo?.taskId == state.otherSplitTask ) { t.hide(change.leash) startTransactionFinishT.hide(change.leash) } if (change.mode == TRANSIT_CLOSE) { t.hide(change.leash) startTransactionFinishT.hide(change.leash) } else if (change.taskInfo?.taskId == state.draggedTaskId) { setupEndDragToDesktop( info, startTransaction = t, finishTransaction = startTransactionFinishT ) // Call finishCallback to merge animation before startTransitionFinishCb is called finishCallback.onTransitionFinished(null /* wct */) animateEndDragToDesktop(startTransaction = t, startTransitionFinishCb) } else if (isCancelTransition) { info.changes.forEach { change -> t.show(change.leash) startTransactionFinishT.show(change.leash) } t.apply() finishCallback.onTransitionFinished(null /* wct */) startTransitionFinishCb.onTransitionFinished(null /* wct */) clearState() } } protected open fun setupEndDragToDesktop( info: TransitionInfo, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction ) { val state = requireTransitionState() info.changes.forEachIndexed { i, change -> when { state is TransitionState.FromSplit && change.taskInfo?.taskId == state.otherSplitTask -> { // If we're exiting split, hide the remaining split task. startTransaction.hide(change.leash) finishTransaction.hide(change.leash) } change.mode == TRANSIT_CLOSE -> { startTransaction.hide(change.leash) finishTransaction.hide(change.leash) } change.taskInfo?.taskId == state.draggedTaskId -> { startTransaction.show(change.leash) finishTransaction.show(change.leash) state.draggedTaskChange = change } else if (change.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM) { } change.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM -> { // Other freeform tasks that are being restored go behind the dragged task. val draggedTaskLeash = state.draggedTaskChange?.leash ?: error("Expected dragged leash to be non-null") t.setRelativeLayer(change.leash, draggedTaskLeash, -i) startTransactionFinishT.setRelativeLayer(change.leash, draggedTaskLeash, -i) startTransaction.setRelativeLayer(change.leash, draggedTaskLeash, -i) finishTransaction.setRelativeLayer(change.leash, draggedTaskLeash, -i) } } } } private fun animateEndDragToDesktop( startTransaction: SurfaceControl.Transaction, startTransitionFinishCb: Transitions.TransitionFinishCallback ) { val state = requireTransitionState() val draggedTaskChange = state.draggedTaskChange ?: throw IllegalStateException("Expected non-null change of dragged task") state.draggedTaskChange ?: error("Expected non-null change of dragged task") val draggedTaskLeash = draggedTaskChange.leash val startBounds = draggedTaskChange.startAbsBounds val endBounds = draggedTaskChange.endAbsBounds // Pause any animation that may be currently playing; we will use the relevant // Cancel 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 Loading @@ -533,16 +560,15 @@ class DragToDesktopTransitionHandler( startPosition.y.toInt() + unscaledStartHeight ) dragToDesktopStateListener?.onCommitToDesktopAnimationStart(t) dragToDesktopStateListener?.onCommitToDesktopAnimationStart(startTransaction) // 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, startTransaction, unscaledStartBounds ) finishCallback.onTransitionFinished(null /* wct */) val tx: SurfaceControl.Transaction = transactionSupplier.get() ValueAnimator.ofObject(rectEvaluator, unscaledStartBounds, endBounds) .setDuration(DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS) Loading Loading @@ -581,16 +607,6 @@ class DragToDesktopTransitionHandler( ) start() } } else if (isCancelTransition) { info.changes.forEach { change -> t.show(change.leash) startTransactionFinishT.show(change.leash) } t.apply() finishCallback.onTransitionFinished(null /* wct */) startTransitionFinishCb.onTransitionFinished(null /* wct */) clearState() } } override fun handleRequest( Loading Loading @@ -707,7 +723,8 @@ class DragToDesktopTransitionHandler( wct.reorder(wc, true /* toTop */) } } val homeWc = state.homeToken ?: error("Home task should be non-null before cancelling") val homeWc = state.homeChange?.container ?: error("Home task should be non-null before cancelling") wct.restoreTransientOrder(homeWc) } Loading @@ -731,10 +748,21 @@ class DragToDesktopTransitionHandler( return splitScreenController.getTaskInfo(otherTaskPos)?.taskId } private fun requireTransitionState(): TransitionState { protected fun requireTransitionState(): TransitionState { return transitionState ?: error("Expected non-null transition state") } /** * Represents the layering (Z order) that will be given to any window based on its type during * the "start" transition of the drag-to-desktop transition */ protected data class DragToDesktopLayers( val appLayers: Int, val homeLayers: Int, val wallpaperLayers: Int, val dragLayer: Int, ) interface DragToDesktopStateListener { fun onCommitToDesktopAnimationStart(tx: SurfaceControl.Transaction) Loading @@ -748,7 +776,7 @@ class DragToDesktopTransitionHandler( abstract var startTransitionFinishCb: Transitions.TransitionFinishCallback? abstract var startTransitionFinishTransaction: SurfaceControl.Transaction? abstract var cancelTransitionToken: IBinder? abstract var homeToken: WindowContainerToken? abstract var homeChange: Change? abstract var draggedTaskChange: Change? abstract var cancelState: CancelState abstract var startAborted: Boolean Loading @@ -760,7 +788,7 @@ class DragToDesktopTransitionHandler( override var startTransitionFinishCb: Transitions.TransitionFinishCallback? = null, override var startTransitionFinishTransaction: SurfaceControl.Transaction? = null, override var cancelTransitionToken: IBinder? = null, override var homeToken: WindowContainerToken? = null, override var homeChange: Change? = null, override var draggedTaskChange: Change? = null, override var cancelState: CancelState = CancelState.NO_CANCEL, override var startAborted: Boolean = false, Loading @@ -774,7 +802,7 @@ class DragToDesktopTransitionHandler( override var startTransitionFinishCb: Transitions.TransitionFinishCallback? = null, override var startTransitionFinishTransaction: SurfaceControl.Transaction? = null, override var cancelTransitionToken: IBinder? = null, override var homeToken: WindowContainerToken? = null, override var homeChange: Change? = null, override var draggedTaskChange: Change? = null, override var cancelState: CancelState = CancelState.NO_CANCEL, override var startAborted: Boolean = false, Loading @@ -800,3 +828,88 @@ class DragToDesktopTransitionHandler( private const val DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS = 336L } } /** Enables flagged rollout of the [SpringDragToDesktopTransitionHandler] */ class DefaultDragToDesktopTransitionHandler @JvmOverloads constructor( context: Context, transitions: Transitions, taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, interactionJankMonitor: InteractionJankMonitor, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() }, ) : DragToDesktopTransitionHandler( context, transitions, taskDisplayAreaOrganizer, interactionJankMonitor, transactionSupplier ) { /** * @return layers in order: * - appLayers - non-wallpaper, non-home tasks excluding the dragged task go at the bottom * - homeLayers - home task on top of apps * - wallpaperLayers - wallpaper on top of home * - dragLayer - the dragged task on top of everything, there's only 1 dragged task */ override fun calculateStartDragToDesktopLayers(info: TransitionInfo): DragToDesktopLayers = DragToDesktopLayers( appLayers = info.changes.size, homeLayers = info.changes.size * 2, wallpaperLayers = info.changes.size * 3, dragLayer = info.changes.size * 3 ) } /** Desktop transition handler with spring based animation for the end drag to desktop transition */ class SpringDragToDesktopTransitionHandler @JvmOverloads constructor( context: Context, transitions: Transitions, taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, interactionJankMonitor: InteractionJankMonitor, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() }, ) : DragToDesktopTransitionHandler( context, transitions, taskDisplayAreaOrganizer, interactionJankMonitor, transactionSupplier ) { /** * @return layers in order: * - appLayers - below everything z < 0, effectively hides the leash * - homeLayers - home task on top of apps, z in 0..<size * - wallpaperLayers - wallpaper on top of home, z in size..<size*2 * - dragLayer - the dragged task on top of everything, z == size*2 */ override fun calculateStartDragToDesktopLayers(info: TransitionInfo): DragToDesktopLayers = DragToDesktopLayers( appLayers = -1, homeLayers = info.changes.size - 1, wallpaperLayers = info.changes.size * 2 - 1, dragLayer = info.changes.size * 2 ) override fun setupEndDragToDesktop( info: TransitionInfo, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction ) { super.setupEndDragToDesktop(info, startTransaction, finishTransaction) val state = requireTransitionState() val homeLeash = state.homeChange?.leash ?: error("Expects home leash to be non-null") // Hide home on finish to prevent flickering when wallpaper activity flag is enabled finishTransaction.hide(homeLeash) } } libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt +177 −78 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +8 −3 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.launcher3.icons.IconProvider; import com.android.window.flags.Flags; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; Loading @@ -58,6 +59,7 @@ import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.dagger.back.ShellBackAnimationModule; import com.android.wm.shell.dagger.pip.PipModule; import com.android.wm.shell.desktopmode.DefaultDragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopModeTaskRepository; Loading @@ -68,6 +70,7 @@ import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator; import com.android.wm.shell.desktopmode.SpringDragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.GlobalDragListener; Loading Loading @@ -603,9 +606,11 @@ public abstract class WMShellModule { Context context, Transitions transitions, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, Optional<DesktopTasksLimiter> desktopTasksLimiter, InteractionJankMonitor interactionJankMonitor) { return new DragToDesktopTransitionHandler(context, transitions, return Flags.enableDesktopWindowingTransitions() ? new SpringDragToDesktopTransitionHandler(context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor) : new DefaultDragToDesktopTransitionHandler(context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +240 −127 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.view.WindowManager.TRANSIT_CLOSE import android.window.TransitionInfo import android.window.TransitionInfo.Change import android.window.TransitionRequestInfo import android.window.WindowContainerToken import android.window.WindowContainerTransaction import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE Loading Loading @@ -55,8 +54,13 @@ import java.util.function.Supplier * Handles the transition to enter desktop from fullscreen by dragging on the handle bar. It also * handles the cancellation case where the task is dragged back to the status bar area in the same * gesture. * * It's a base sealed class that delegates flag dependant logic to its subclasses: * [DefaultDragToDesktopTransitionHandler] and [SpringDragToDesktopTransitionHandler] * * TODO(b/356764679): Clean up after the full flag rollout */ class DragToDesktopTransitionHandler( sealed class DragToDesktopTransitionHandler( private val context: Context, private val transitions: Transitions, private val taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, Loading @@ -64,19 +68,6 @@ class DragToDesktopTransitionHandler( private val transactionSupplier: Supplier<SurfaceControl.Transaction>, ) : TransitionHandler { constructor( context: Context, transitions: Transitions, rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, interactionJankMonitor: InteractionJankMonitor ) : this( context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor, Supplier { SurfaceControl.Transaction() } ) private val rectEvaluator = RectEvaluator(Rect()) private val launchHomeIntent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) Loading Loading @@ -307,24 +298,18 @@ class DragToDesktopTransitionHandler( return false } // Layering: non-wallpaper, non-home tasks excluding the dragged task go at the bottom, // then Home on top of that, wallpaper on top of that and finally the dragged task on top // of everything. val appLayers = info.changes.size val homeLayers = info.changes.size * 2 val wallpaperLayers = info.changes.size * 3 val dragLayer = wallpaperLayers val layers = calculateStartDragToDesktopLayers(info) val leafTaskFilter = TransitionUtil.LeafTaskFilter() info.changes.withIndex().forEach { (i, change) -> if (TransitionUtil.isWallpaper(change)) { val layer = wallpaperLayers - i val layer = layers.wallpaperLayers - i startTransaction.apply { setLayer(change.leash, layer) show(change.leash) } } else if (isHomeChange(change)) { state.homeToken = change.container val layer = homeLayers - i state.homeChange = change val layer = layers.homeLayers - i startTransaction.apply { setLayer(change.leash, layer) show(change.leash) Loading @@ -338,11 +323,11 @@ class DragToDesktopTransitionHandler( if (state.cancelState == CancelState.NO_CANCEL) { // Normal case, split root goes to the bottom behind everything // else. appLayers - i layers.appLayers - i } else { // Cancel-early case, pretend nothing happened so split root stays // top. dragLayer layers.dragLayer } startTransaction.apply { setLayer(change.leash, layer) Loading @@ -357,7 +342,7 @@ class DragToDesktopTransitionHandler( state.draggedTaskChange = change val bounds = change.endAbsBounds startTransaction.apply { setLayer(change.leash, dragLayer) setLayer(change.leash, layers.dragLayer) setWindowCrop(change.leash, bounds.width(), bounds.height()) show(change.leash) } Loading @@ -370,7 +355,7 @@ class DragToDesktopTransitionHandler( state.otherRootChanges.add(change) val bounds = change.endAbsBounds startTransaction.apply { setLayer(change.leash, appLayers - i) setLayer(change.leash, layers.appLayers - i) setWindowCrop(change.leash, bounds.width(), bounds.height()) show(change.leash) } Loading Loading @@ -404,7 +389,7 @@ class DragToDesktopTransitionHandler( ) val bounds = change.endAbsBounds startTransaction.apply { setLayer(change.leash, dragLayer) setLayer(change.leash, layers.dragLayer) setWindowCrop(change.leash, bounds.width(), bounds.height()) show(change.leash) } Loading Loading @@ -452,6 +437,15 @@ class DragToDesktopTransitionHandler( return true } /** * Calculates start drag to desktop layers for transition [info]. The leash layer is calculated * based on its change position in the transition, e.g. `appLayer = appLayers - i`, where i is * the change index. */ protected abstract fun calculateStartDragToDesktopLayers( info: TransitionInfo ): DragToDesktopLayers override fun mergeAnimation( transition: IBinder, info: TransitionInfo, Loading Loading @@ -483,40 +477,73 @@ class DragToDesktopTransitionHandler( state.startTransitionFinishCb ?: error("Start transition expected to be waiting for merge but wasn't") if (isEndTransition) { info.changes.withIndex().forEach { (i, change) -> // If we're exiting split, hide the remaining split task. if ( state is TransitionState.FromSplit && change.taskInfo?.taskId == state.otherSplitTask ) { t.hide(change.leash) startTransactionFinishT.hide(change.leash) } if (change.mode == TRANSIT_CLOSE) { t.hide(change.leash) startTransactionFinishT.hide(change.leash) } else if (change.taskInfo?.taskId == state.draggedTaskId) { setupEndDragToDesktop( info, startTransaction = t, finishTransaction = startTransactionFinishT ) // Call finishCallback to merge animation before startTransitionFinishCb is called finishCallback.onTransitionFinished(null /* wct */) animateEndDragToDesktop(startTransaction = t, startTransitionFinishCb) } else if (isCancelTransition) { info.changes.forEach { change -> t.show(change.leash) startTransactionFinishT.show(change.leash) } t.apply() finishCallback.onTransitionFinished(null /* wct */) startTransitionFinishCb.onTransitionFinished(null /* wct */) clearState() } } protected open fun setupEndDragToDesktop( info: TransitionInfo, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction ) { val state = requireTransitionState() info.changes.forEachIndexed { i, change -> when { state is TransitionState.FromSplit && change.taskInfo?.taskId == state.otherSplitTask -> { // If we're exiting split, hide the remaining split task. startTransaction.hide(change.leash) finishTransaction.hide(change.leash) } change.mode == TRANSIT_CLOSE -> { startTransaction.hide(change.leash) finishTransaction.hide(change.leash) } change.taskInfo?.taskId == state.draggedTaskId -> { startTransaction.show(change.leash) finishTransaction.show(change.leash) state.draggedTaskChange = change } else if (change.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM) { } change.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM -> { // Other freeform tasks that are being restored go behind the dragged task. val draggedTaskLeash = state.draggedTaskChange?.leash ?: error("Expected dragged leash to be non-null") t.setRelativeLayer(change.leash, draggedTaskLeash, -i) startTransactionFinishT.setRelativeLayer(change.leash, draggedTaskLeash, -i) startTransaction.setRelativeLayer(change.leash, draggedTaskLeash, -i) finishTransaction.setRelativeLayer(change.leash, draggedTaskLeash, -i) } } } } private fun animateEndDragToDesktop( startTransaction: SurfaceControl.Transaction, startTransitionFinishCb: Transitions.TransitionFinishCallback ) { val state = requireTransitionState() val draggedTaskChange = state.draggedTaskChange ?: throw IllegalStateException("Expected non-null change of dragged task") state.draggedTaskChange ?: error("Expected non-null change of dragged task") val draggedTaskLeash = draggedTaskChange.leash val startBounds = draggedTaskChange.startAbsBounds val endBounds = draggedTaskChange.endAbsBounds // Pause any animation that may be currently playing; we will use the relevant // Cancel 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 Loading @@ -533,16 +560,15 @@ class DragToDesktopTransitionHandler( startPosition.y.toInt() + unscaledStartHeight ) dragToDesktopStateListener?.onCommitToDesktopAnimationStart(t) dragToDesktopStateListener?.onCommitToDesktopAnimationStart(startTransaction) // 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, startTransaction, unscaledStartBounds ) finishCallback.onTransitionFinished(null /* wct */) val tx: SurfaceControl.Transaction = transactionSupplier.get() ValueAnimator.ofObject(rectEvaluator, unscaledStartBounds, endBounds) .setDuration(DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS) Loading Loading @@ -581,16 +607,6 @@ class DragToDesktopTransitionHandler( ) start() } } else if (isCancelTransition) { info.changes.forEach { change -> t.show(change.leash) startTransactionFinishT.show(change.leash) } t.apply() finishCallback.onTransitionFinished(null /* wct */) startTransitionFinishCb.onTransitionFinished(null /* wct */) clearState() } } override fun handleRequest( Loading Loading @@ -707,7 +723,8 @@ class DragToDesktopTransitionHandler( wct.reorder(wc, true /* toTop */) } } val homeWc = state.homeToken ?: error("Home task should be non-null before cancelling") val homeWc = state.homeChange?.container ?: error("Home task should be non-null before cancelling") wct.restoreTransientOrder(homeWc) } Loading @@ -731,10 +748,21 @@ class DragToDesktopTransitionHandler( return splitScreenController.getTaskInfo(otherTaskPos)?.taskId } private fun requireTransitionState(): TransitionState { protected fun requireTransitionState(): TransitionState { return transitionState ?: error("Expected non-null transition state") } /** * Represents the layering (Z order) that will be given to any window based on its type during * the "start" transition of the drag-to-desktop transition */ protected data class DragToDesktopLayers( val appLayers: Int, val homeLayers: Int, val wallpaperLayers: Int, val dragLayer: Int, ) interface DragToDesktopStateListener { fun onCommitToDesktopAnimationStart(tx: SurfaceControl.Transaction) Loading @@ -748,7 +776,7 @@ class DragToDesktopTransitionHandler( abstract var startTransitionFinishCb: Transitions.TransitionFinishCallback? abstract var startTransitionFinishTransaction: SurfaceControl.Transaction? abstract var cancelTransitionToken: IBinder? abstract var homeToken: WindowContainerToken? abstract var homeChange: Change? abstract var draggedTaskChange: Change? abstract var cancelState: CancelState abstract var startAborted: Boolean Loading @@ -760,7 +788,7 @@ class DragToDesktopTransitionHandler( override var startTransitionFinishCb: Transitions.TransitionFinishCallback? = null, override var startTransitionFinishTransaction: SurfaceControl.Transaction? = null, override var cancelTransitionToken: IBinder? = null, override var homeToken: WindowContainerToken? = null, override var homeChange: Change? = null, override var draggedTaskChange: Change? = null, override var cancelState: CancelState = CancelState.NO_CANCEL, override var startAborted: Boolean = false, Loading @@ -774,7 +802,7 @@ class DragToDesktopTransitionHandler( override var startTransitionFinishCb: Transitions.TransitionFinishCallback? = null, override var startTransitionFinishTransaction: SurfaceControl.Transaction? = null, override var cancelTransitionToken: IBinder? = null, override var homeToken: WindowContainerToken? = null, override var homeChange: Change? = null, override var draggedTaskChange: Change? = null, override var cancelState: CancelState = CancelState.NO_CANCEL, override var startAborted: Boolean = false, Loading @@ -800,3 +828,88 @@ class DragToDesktopTransitionHandler( private const val DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS = 336L } } /** Enables flagged rollout of the [SpringDragToDesktopTransitionHandler] */ class DefaultDragToDesktopTransitionHandler @JvmOverloads constructor( context: Context, transitions: Transitions, taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, interactionJankMonitor: InteractionJankMonitor, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() }, ) : DragToDesktopTransitionHandler( context, transitions, taskDisplayAreaOrganizer, interactionJankMonitor, transactionSupplier ) { /** * @return layers in order: * - appLayers - non-wallpaper, non-home tasks excluding the dragged task go at the bottom * - homeLayers - home task on top of apps * - wallpaperLayers - wallpaper on top of home * - dragLayer - the dragged task on top of everything, there's only 1 dragged task */ override fun calculateStartDragToDesktopLayers(info: TransitionInfo): DragToDesktopLayers = DragToDesktopLayers( appLayers = info.changes.size, homeLayers = info.changes.size * 2, wallpaperLayers = info.changes.size * 3, dragLayer = info.changes.size * 3 ) } /** Desktop transition handler with spring based animation for the end drag to desktop transition */ class SpringDragToDesktopTransitionHandler @JvmOverloads constructor( context: Context, transitions: Transitions, taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, interactionJankMonitor: InteractionJankMonitor, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() }, ) : DragToDesktopTransitionHandler( context, transitions, taskDisplayAreaOrganizer, interactionJankMonitor, transactionSupplier ) { /** * @return layers in order: * - appLayers - below everything z < 0, effectively hides the leash * - homeLayers - home task on top of apps, z in 0..<size * - wallpaperLayers - wallpaper on top of home, z in size..<size*2 * - dragLayer - the dragged task on top of everything, z == size*2 */ override fun calculateStartDragToDesktopLayers(info: TransitionInfo): DragToDesktopLayers = DragToDesktopLayers( appLayers = -1, homeLayers = info.changes.size - 1, wallpaperLayers = info.changes.size * 2 - 1, dragLayer = info.changes.size * 2 ) override fun setupEndDragToDesktop( info: TransitionInfo, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction ) { super.setupEndDragToDesktop(info, startTransaction, finishTransaction) val state = requireTransitionState() val homeLeash = state.homeChange?.leash ?: error("Expects home leash to be non-null") // Hide home on finish to prevent flickering when wallpaper activity flag is enabled finishTransaction.hide(homeLeash) } }
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt +177 −78 File changed.Preview size limit exceeded, changes collapsed. Show changes