Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +19 −8 Original line number Diff line number Diff line Loading @@ -158,6 +158,10 @@ class DesktopTasksController( com.android.wm.shell.R.dimen.desktop_mode_transition_area_width ) /** Task id of the task currently being dragged from fullscreen/split. */ val draggingTaskId get() = dragToDesktopTransitionHandler.draggingTaskId private var recentsAnimationRunning = false private lateinit var splitScreenController: SplitScreenController Loading Loading @@ -406,6 +410,7 @@ class DesktopTasksController( fun onDesktopSplitSelectAnimComplete(taskInfo: RunningTaskInfo) { val wct = WindowContainerTransaction() wct.setBounds(taskInfo.token, Rect()) wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED) shellTaskOrganizer.applyTransaction(wct) } Loading Loading @@ -447,7 +452,9 @@ class DesktopTasksController( ) val wct = WindowContainerTransaction() wct.setBounds(task.token, Rect()) addMoveToSplitChanges(wct, task) // Rather than set windowing mode to multi-window at task level, set it to // undefined and inherit from split stage. wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED) if (Transitions.ENABLE_SHELL_TRANSITIONS) { transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */) } else { Loading @@ -462,6 +469,8 @@ class DesktopTasksController( splitScreenController.getStageOfTask(taskInfo.taskId), EXIT_REASON_DESKTOP_MODE ) splitScreenController.transitionHandler ?.onSplitToDesktop() } } Loading Loading @@ -1044,9 +1053,11 @@ class DesktopTasksController( wct: WindowContainerTransaction, taskInfo: RunningTaskInfo ) { // Explicitly setting multi-window at task level interferes with animations. // Let task inherit windowing mode once transition is complete instead. wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED) // This windowing mode is to get the transition animation started; once we complete // split select, we will change windowing mode to undefined and inherit from split stage. // Going to undefined here causes task to flicker to the top left. // Cancelling the split select flow will revert it to fullscreen. wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_MULTI_WINDOW) // The task's density may have been overridden in freeform; revert it here as we don't // want it overridden in multi-window. wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi()) Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +32 −4 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import android.animation.RectEvaluator import android.animation.ValueAnimator import android.app.ActivityOptions import android.app.ActivityOptions.SourceInfo import android.app.ActivityTaskManager.INVALID_TASK_ID import android.app.PendingIntent import android.app.PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT import android.app.PendingIntent.FLAG_MUTABLE Loading @@ -26,6 +27,9 @@ import android.window.TransitionRequestInfo import android.window.WindowContainerToken import android.window.WindowContainerTransaction import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED import com.android.wm.shell.protolog.ShellProtoLogGroup import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.splitscreen.SplitScreenController Loading Loading @@ -68,7 +72,7 @@ class DragToDesktopTransitionHandler( .addCategory(Intent.CATEGORY_HOME) private var dragToDesktopStateListener: DragToDesktopStateListener? = null private var splitScreenController: SplitScreenController? = null private lateinit var splitScreenController: SplitScreenController private var transitionState: TransitionState? = null private lateinit var onTaskResizeAnimationListener: OnTaskResizeAnimationListener Loading @@ -76,6 +80,9 @@ class DragToDesktopTransitionHandler( val inProgress: Boolean get() = transitionState != null /** The task id of the task currently being dragged from fullscreen/split. */ val draggingTaskId: Int get() = transitionState?.draggedTaskId ?: INVALID_TASK_ID /** Sets a listener to receive callback about events during the transition animation. */ fun setDragToDesktopStateListener(listener: DragToDesktopStateListener) { dragToDesktopStateListener = listener Loading Loading @@ -130,10 +137,14 @@ class DragToDesktopTransitionHandler( .startTransition(TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP, wct, this) transitionState = if (isSplitTask(taskId)) { val otherTask = getOtherSplitTask(taskId) ?: throw IllegalStateException( "Expected split task to have a counterpart." ) TransitionState.FromSplit( draggedTaskId = taskId, dragAnimator = dragToDesktopAnimator, startTransitionToken = startTransitionToken startTransitionToken = startTransitionToken, otherSplitTask = otherTask ) } else { TransitionState.FromFullscreen( Loading Loading @@ -347,6 +358,12 @@ class DragToDesktopTransitionHandler( ?: 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) Loading Loading @@ -392,7 +409,6 @@ class DragToDesktopTransitionHandler( onTaskResizeAnimationListener.onAnimationStart(state.draggedTaskId, t, 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 @@ -549,7 +565,18 @@ class DragToDesktopTransitionHandler( } private fun isSplitTask(taskId: Int): Boolean { return splitScreenController?.isTaskInSplitScreen(taskId) ?: false return splitScreenController.isTaskInSplitScreen(taskId) } private fun getOtherSplitTask(taskId: Int): Int? { val splitPos = splitScreenController.getSplitPosition(taskId) if (splitPos == SPLIT_POSITION_UNDEFINED) return null val otherTaskPos = if (splitPos == SPLIT_POSITION_BOTTOM_OR_RIGHT) { SPLIT_POSITION_TOP_OR_LEFT } else { SPLIT_POSITION_BOTTOM_OR_RIGHT } return splitScreenController.getTaskInfo(otherTaskPos)?.taskId } private fun requireTransitionState(): TransitionState { Loading Loading @@ -598,6 +625,7 @@ class DragToDesktopTransitionHandler( override var cancelled: Boolean = false, override var startAborted: Boolean = false, var splitRootChange: Change? = null, var otherSplitTask: Int ) : TransitionState() } Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +5 −0 Original line number Diff line number Diff line Loading @@ -3351,6 +3351,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, true /* reparentLeafTaskIfRelaunch */); } /** Call this when the animation from split screen to desktop is started. */ public void onSplitToDesktop() { setSplitsVisible(false); } /** Call this when the recents animation finishes by doing pair-to-pair switch. */ public void onRecentsPairToPairAnimationFinish(WindowContainerTransaction finishWct) { ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRecentsPairToPairAnimationFinish"); Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +9 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.windowdecor; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; Loading @@ -34,6 +35,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.compatui.AppCompatUtils.isSingleTopActivityTranslucent; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; import android.annotation.NonNull; import android.app.ActivityManager; Loading Loading @@ -272,10 +274,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mSplitScreenController.registerSplitScreenListener(new SplitScreen.SplitScreenListener() { @Override public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) { if (visible) { if (visible && stage != STAGE_TYPE_UNDEFINED) { DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(taskId); if (decor != null && DesktopModeStatus.isEnabled() && decor.mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { if (decor != null && DesktopModeStatus.isEnabled()) { mDesktopTasksController.moveToSplit(decor.mTaskInfo); } } Loading Loading @@ -915,6 +916,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { @Nullable private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) { // If we are mid-transition, dragged task's decor is always relevant. final int draggedTaskId = mDesktopTasksController.getDraggingTaskId(); if (draggedTaskId != INVALID_TASK_ID) { return mWindowDecorByTaskId.get(draggedTaskId); } final DesktopModeWindowDecoration focusedDecor = getFocusedDecor(); if (focusedDecor == null) { return null; Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +19 −8 Original line number Diff line number Diff line Loading @@ -158,6 +158,10 @@ class DesktopTasksController( com.android.wm.shell.R.dimen.desktop_mode_transition_area_width ) /** Task id of the task currently being dragged from fullscreen/split. */ val draggingTaskId get() = dragToDesktopTransitionHandler.draggingTaskId private var recentsAnimationRunning = false private lateinit var splitScreenController: SplitScreenController Loading Loading @@ -406,6 +410,7 @@ class DesktopTasksController( fun onDesktopSplitSelectAnimComplete(taskInfo: RunningTaskInfo) { val wct = WindowContainerTransaction() wct.setBounds(taskInfo.token, Rect()) wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED) shellTaskOrganizer.applyTransaction(wct) } Loading Loading @@ -447,7 +452,9 @@ class DesktopTasksController( ) val wct = WindowContainerTransaction() wct.setBounds(task.token, Rect()) addMoveToSplitChanges(wct, task) // Rather than set windowing mode to multi-window at task level, set it to // undefined and inherit from split stage. wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED) if (Transitions.ENABLE_SHELL_TRANSITIONS) { transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */) } else { Loading @@ -462,6 +469,8 @@ class DesktopTasksController( splitScreenController.getStageOfTask(taskInfo.taskId), EXIT_REASON_DESKTOP_MODE ) splitScreenController.transitionHandler ?.onSplitToDesktop() } } Loading Loading @@ -1044,9 +1053,11 @@ class DesktopTasksController( wct: WindowContainerTransaction, taskInfo: RunningTaskInfo ) { // Explicitly setting multi-window at task level interferes with animations. // Let task inherit windowing mode once transition is complete instead. wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED) // This windowing mode is to get the transition animation started; once we complete // split select, we will change windowing mode to undefined and inherit from split stage. // Going to undefined here causes task to flicker to the top left. // Cancelling the split select flow will revert it to fullscreen. wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_MULTI_WINDOW) // The task's density may have been overridden in freeform; revert it here as we don't // want it overridden in multi-window. wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi()) Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +32 −4 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import android.animation.RectEvaluator import android.animation.ValueAnimator import android.app.ActivityOptions import android.app.ActivityOptions.SourceInfo import android.app.ActivityTaskManager.INVALID_TASK_ID import android.app.PendingIntent import android.app.PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT import android.app.PendingIntent.FLAG_MUTABLE Loading @@ -26,6 +27,9 @@ import android.window.TransitionRequestInfo import android.window.WindowContainerToken import android.window.WindowContainerTransaction import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED import com.android.wm.shell.protolog.ShellProtoLogGroup import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.splitscreen.SplitScreenController Loading Loading @@ -68,7 +72,7 @@ class DragToDesktopTransitionHandler( .addCategory(Intent.CATEGORY_HOME) private var dragToDesktopStateListener: DragToDesktopStateListener? = null private var splitScreenController: SplitScreenController? = null private lateinit var splitScreenController: SplitScreenController private var transitionState: TransitionState? = null private lateinit var onTaskResizeAnimationListener: OnTaskResizeAnimationListener Loading @@ -76,6 +80,9 @@ class DragToDesktopTransitionHandler( val inProgress: Boolean get() = transitionState != null /** The task id of the task currently being dragged from fullscreen/split. */ val draggingTaskId: Int get() = transitionState?.draggedTaskId ?: INVALID_TASK_ID /** Sets a listener to receive callback about events during the transition animation. */ fun setDragToDesktopStateListener(listener: DragToDesktopStateListener) { dragToDesktopStateListener = listener Loading Loading @@ -130,10 +137,14 @@ class DragToDesktopTransitionHandler( .startTransition(TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP, wct, this) transitionState = if (isSplitTask(taskId)) { val otherTask = getOtherSplitTask(taskId) ?: throw IllegalStateException( "Expected split task to have a counterpart." ) TransitionState.FromSplit( draggedTaskId = taskId, dragAnimator = dragToDesktopAnimator, startTransitionToken = startTransitionToken startTransitionToken = startTransitionToken, otherSplitTask = otherTask ) } else { TransitionState.FromFullscreen( Loading Loading @@ -347,6 +358,12 @@ class DragToDesktopTransitionHandler( ?: 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) Loading Loading @@ -392,7 +409,6 @@ class DragToDesktopTransitionHandler( onTaskResizeAnimationListener.onAnimationStart(state.draggedTaskId, t, 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 @@ -549,7 +565,18 @@ class DragToDesktopTransitionHandler( } private fun isSplitTask(taskId: Int): Boolean { return splitScreenController?.isTaskInSplitScreen(taskId) ?: false return splitScreenController.isTaskInSplitScreen(taskId) } private fun getOtherSplitTask(taskId: Int): Int? { val splitPos = splitScreenController.getSplitPosition(taskId) if (splitPos == SPLIT_POSITION_UNDEFINED) return null val otherTaskPos = if (splitPos == SPLIT_POSITION_BOTTOM_OR_RIGHT) { SPLIT_POSITION_TOP_OR_LEFT } else { SPLIT_POSITION_BOTTOM_OR_RIGHT } return splitScreenController.getTaskInfo(otherTaskPos)?.taskId } private fun requireTransitionState(): TransitionState { Loading Loading @@ -598,6 +625,7 @@ class DragToDesktopTransitionHandler( override var cancelled: Boolean = false, override var startAborted: Boolean = false, var splitRootChange: Change? = null, var otherSplitTask: Int ) : TransitionState() } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +5 −0 Original line number Diff line number Diff line Loading @@ -3351,6 +3351,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, true /* reparentLeafTaskIfRelaunch */); } /** Call this when the animation from split screen to desktop is started. */ public void onSplitToDesktop() { setSplitsVisible(false); } /** Call this when the recents animation finishes by doing pair-to-pair switch. */ public void onRecentsPairToPairAnimationFinish(WindowContainerTransaction finishWct) { ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRecentsPairToPairAnimationFinish"); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +9 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.windowdecor; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; Loading @@ -34,6 +35,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.compatui.AppCompatUtils.isSingleTopActivityTranslucent; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; import android.annotation.NonNull; import android.app.ActivityManager; Loading Loading @@ -272,10 +274,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mSplitScreenController.registerSplitScreenListener(new SplitScreen.SplitScreenListener() { @Override public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) { if (visible) { if (visible && stage != STAGE_TYPE_UNDEFINED) { DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(taskId); if (decor != null && DesktopModeStatus.isEnabled() && decor.mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { if (decor != null && DesktopModeStatus.isEnabled()) { mDesktopTasksController.moveToSplit(decor.mTaskInfo); } } Loading Loading @@ -915,6 +916,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { @Nullable private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) { // If we are mid-transition, dragged task's decor is always relevant. final int draggedTaskId = mDesktopTasksController.getDraggingTaskId(); if (draggedTaskId != INVALID_TASK_ID) { return mWindowDecorByTaskId.get(draggedTaskId); } final DesktopModeWindowDecoration focusedDecor = getFocusedDecor(); if (focusedDecor == null) { return null; Loading