Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/MinimizeAnimator.kt +12 −0 Original line number Diff line number Diff line Loading @@ -23,9 +23,11 @@ import android.content.Context import android.os.Handler import android.view.Choreographer import android.view.SurfaceControl.Transaction import android.window.DesktopExperienceFlags import android.window.TransitionInfo.Change import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW import com.android.internal.jank.InteractionJankMonitor import com.android.wm.shell.shared.animation.WindowAnimator.BoundsAnimationParams.AnimationBounds import java.time.Duration /** Creates minimization animation */ Loading @@ -39,6 +41,16 @@ object MinimizeAnimator { endOffsetYDp = 12f, endScale = 0.97f, interpolator = Interpolators.STANDARD_ACCELERATE, animBounds = if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { // In some cases, nav-back on the last desktop task may cause it to be reparented // into a fullscreen TDA before being minimized back into a desk by // [DesktopBackNavTransitionObserver]. The minimize animation would then occur when // the task is still fullscreen, which means it should use the start bounds for the // minimize animation. AnimationBounds.START } else { AnimationBounds.END } ) /** Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/WindowAnimator.kt +12 −3 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import android.view.Choreographer import android.view.SurfaceControl import android.view.animation.Interpolator import android.window.TransitionInfo import com.android.wm.shell.shared.animation.WindowAnimator.BoundsAnimationParams.AnimationBounds.END import com.android.wm.shell.shared.animation.WindowAnimator.BoundsAnimationParams.AnimationBounds.START /** Creates animations that can be applied to windows/surfaces. */ object WindowAnimator { Loading @@ -38,7 +40,10 @@ object WindowAnimator { val startScale: Float = 1f, val endScale: Float = 1f, val interpolator: Interpolator, ) val animBounds: AnimationBounds = END, ) { enum class AnimationBounds { START, END } } /** * Creates an animator to reposition and scale the bounds of the leash of the given change. Loading @@ -54,10 +59,14 @@ object WindowAnimator { change: TransitionInfo.Change, transaction: SurfaceControl.Transaction, ): ValueAnimator { val bounds = when (boundsAnimDef.animBounds) { START -> change.startAbsBounds END -> change.endAbsBounds } val startPos = getPosition( displayMetrics, change.endAbsBounds, bounds, boundsAnimDef.startScale, boundsAnimDef.startOffsetYDp, ) Loading @@ -65,7 +74,7 @@ object WindowAnimator { val endPos = getPosition( displayMetrics, change.endAbsBounds, bounds, boundsAnimDef.endScale, boundsAnimDef.endOffsetYDp, ) Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −0 Original line number Diff line number Diff line Loading @@ -1387,6 +1387,7 @@ public abstract class WMShellModule { Optional<DesktopMixedTransitionHandler> desktopMixedTransitionHandler, Optional<BackAnimationController> backAnimationController, DesksOrganizer desksOrganizer, Transitions transitions, DesktopState desktopState, ShellInit shellInit) { return desktopUserRepositories.flatMap( Loading @@ -1397,6 +1398,7 @@ public abstract class WMShellModule { desktopMixedTransitionHandler.get(), backAnimationController.get(), desksOrganizer, transitions, desktopState, shellInit))); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopBackNavTransitionObserver.kt +164 −70 Original line number Diff line number Diff line Loading @@ -18,11 +18,14 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.os.IBinder import android.view.WindowManager.TRANSIT_CHANGE import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_TO_BACK import android.view.WindowManager.transitTypeToString import android.window.DesktopExperienceFlags import android.window.DesktopModeFlags import android.window.TransitionInfo import android.window.WindowContainerTransaction import com.android.internal.protolog.ProtoLog import com.android.wm.shell.back.BackAnimationController import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.isExitDesktopModeTransition Loading @@ -31,6 +34,7 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.desktopmode.DesktopState import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions /** * Class responsible for updating [DesktopRepository] with back navigation related changes. Also Loading @@ -42,6 +46,7 @@ class DesktopBackNavTransitionObserver( private val desktopMixedTransitionHandler: DesktopMixedTransitionHandler, private val backAnimationController: BackAnimationController, private val desksOrganizer: DesksOrganizer, private val transitions: Transitions, desktopState: DesktopState, shellInit: ShellInit, ) { Loading Loading @@ -75,79 +80,91 @@ class DesktopBackNavTransitionObserver( val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (desktopRepository.isExitingDesktopTask(change)) { logD("removeTaskIfNeeded taskId=%d", taskInfo.taskId) desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId) } } } private fun handleBackNavigation(transition: IBinder, info: TransitionInfo) { // When default back navigation happens, transition type is TO_BACK and the change is // TO_BACK. Mark the task going to back as minimized. if (info.type == TRANSIT_TO_BACK) { for (change in info.changes) { val taskInfo = change.taskInfo if (taskInfo == null || taskInfo.taskId == -1) { continue } val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) val isInDesktop = desktopRepository.isAnyDeskActive(taskInfo.displayId) if ( isInDesktop && change.mode == TRANSIT_TO_BACK && desktopRepository.isDesktopTask(taskInfo) ) { val isLastTask = if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { desktopRepository.hasOnlyOneVisibleTask(taskInfo.displayId) } else { desktopRepository.isOnlyVisibleTask(taskInfo.taskId, taskInfo.displayId) } logD( "handleBackNavigation marking to-back taskId=%d as minimized", taskInfo.taskId, val taskToMinimize = findTaskToMinimize(info) ?: return logD("handleBackNavigation taskToMinimize=%s", taskToMinimize) desktopUserRepositories .getProfile(taskToMinimize.taskInfo.userId) .minimizeTaskInDesk( displayId = taskToMinimize.displayId, deskId = taskToMinimize.deskId, taskId = taskToMinimize.taskId, ) desktopRepository.minimizeTask(taskInfo.displayId, taskInfo.taskId) desktopMixedTransitionHandler.addPendingMixedTransition( DesktopMixedTransitionHandler.PendingMixedTransition.Minimize( transition, taskInfo.taskId, isLastTask, taskToMinimize.taskId, taskToMinimize.isLastTask, ) ) if (taskToMinimize.shouldReparentToDesk) { // The task was reparented out of the desk. Move it back into the desk, but minimized. val wct = WindowContainerTransaction() desksOrganizer.moveTaskToDesk( wct = wct, deskId = taskToMinimize.deskId, task = taskToMinimize.taskInfo, minimized = true, ) if (!wct.isEmpty) { transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) } } } } else if (info.type == TRANSIT_CLOSE) { // In some cases app will be closing as a result of back navigation but we would like // to minimize. Mark the task closing as minimized. var hasWallpaperClosing = false var minimizingTask: Int? = null for (change in info.changes) { val taskInfo = change.taskInfo if (taskInfo == null || taskInfo.taskId == -1) continue if ( TransitionUtil.isClosingMode(change.mode) && DesktopWallpaperActivity.isWallpaperTask(taskInfo) private data class TaskToMinimize( val taskId: Int, val deskId: Int, val displayId: Int, val isLastTask: Boolean, val shouldReparentToDesk: Boolean, ) { hasWallpaperClosing = true constructor( taskInfo: RunningTaskInfo, deskId: Int, isLastTask: Boolean, shouldReparentToDesk: Boolean, ) : this(taskInfo.taskId, deskId, taskInfo.displayId, isLastTask, shouldReparentToDesk) { this.taskInfo = taskInfo } if (change.mode == TRANSIT_CLOSE && minimizingTask == null) { minimizingTask = getMinimizingTaskForClosingTransition(taskInfo) } lateinit var taskInfo: RunningTaskInfo } if (minimizingTask == null) return // If the transition has wallpaper closing, it means we are moving out of desktop. logD("handleBackNavigation marking close taskId=%d as minimized", minimizingTask) desktopMixedTransitionHandler.addPendingMixedTransition( DesktopMixedTransitionHandler.PendingMixedTransition.Minimize( transition, minimizingTask, isLastTask = hasWallpaperClosing, ) ) private fun findTaskToMinimize(info: TransitionInfo): TaskToMinimize? { if (info.type != TRANSIT_TO_BACK && info.type != TRANSIT_CLOSE) return null val hasWallpaperClosing = info.taskChanges().any { change -> TransitionUtil.isClosingMode(change.mode) && DesktopWallpaperActivity.isWallpaperTask(checkNotNull(change.taskInfo)) } for (change in info.taskChanges()) { val mode = change.mode when (info.type) { TRANSIT_TO_BACK -> { val taskToMinimize = getMinimizingTaskForToBackTransition(change) if (taskToMinimize != null) { return taskToMinimize } } TRANSIT_CLOSE -> { if (mode != TRANSIT_CLOSE) continue val taskToMinimize = getMinimizingTaskForClosingTransition(change, hasWallpaperClosing) if (taskToMinimize != null) { return taskToMinimize } } else -> error("Unsupported transition type: ${transitTypeToString(info.type)}") } } return null } /** Loading @@ -162,21 +179,87 @@ class DesktopBackNavTransitionObserver( * will be rare. E.g. triggering back navigation on an app that pops up a close dialog, and * closing it will minimize it here. */ private fun getMinimizingTaskForClosingTransition(taskInfo: RunningTaskInfo): Int? { val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) val isInDesktop = desktopRepository.isAnyDeskActive(taskInfo.displayId) private fun getMinimizingTaskForClosingTransition( change: TransitionInfo.Change, hasWallpaperClosing: Boolean, ): TaskToMinimize? { val taskInfo = change.taskInfo ?: return null if (taskInfo.taskId == -1) return null val repository = desktopUserRepositories.getProfile(taskInfo.userId) if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { val deskId = repository.getActiveDeskId(taskInfo.displayId) if ( deskId != null && repository.isDesktopTask(taskInfo) && backAnimationController.latestTriggerBackTask == taskInfo.taskId && !repository.isClosingTask(taskInfo.taskId) ) { return TaskToMinimize( taskInfo = taskInfo, deskId = deskId, isLastTask = hasWallpaperClosing, shouldReparentToDesk = false, ) } return null } val deskId = repository.getDeskIdForTask(taskInfo.taskId) if ( isInDesktop && desktopRepository.isDesktopTask(taskInfo) && deskId != null && backAnimationController.latestTriggerBackTask == taskInfo.taskId && !desktopRepository.isClosingTask(taskInfo.taskId) !repository.isClosingTask(taskInfo.taskId) ) { desktopRepository.minimizeTask(taskInfo.displayId, taskInfo.taskId) return taskInfo.taskId return TaskToMinimize( taskInfo = taskInfo, deskId = deskId, isLastTask = hasWallpaperClosing, shouldReparentToDesk = false, ) } return null } /** * Given this a task in a to-back transition, a task is assumed to be closed by back navigation * if: * 1) Desktop mode is visible. * 2) It is a desktop task. * 3) Change mode is to-back. */ private fun getMinimizingTaskForToBackTransition( change: TransitionInfo.Change ): TaskToMinimize? { val taskInfo = change.taskInfo ?: return null if (taskInfo.taskId == -1) return null if (change.mode != TRANSIT_TO_BACK) return null val repository = desktopUserRepositories.getProfile(taskInfo.userId) if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { val deskId = repository.getActiveDeskId(taskInfo.displayId) if (deskId != null && repository.isDesktopTask(taskInfo)) { return TaskToMinimize( taskInfo = taskInfo, deskId = deskId, isLastTask = repository.isLastTask(taskInfo, deskId), shouldReparentToDesk = false, ) } return null } val deskId = repository.getDeskIdForTask(taskInfo.taskId) if (deskId == null) { return null } return TaskToMinimize( taskInfo = taskInfo, deskId = deskId, isLastTask = repository.isLastTask(taskInfo, deskId), // Some back navigation transitions can result in the task being reparented out of its // original desk and into the TDA. Given we want this task to end up minimized in that // same desk, check here if this happened so that we can reparent as minimized. shouldReparentToDesk = !desksOrganizer.isMinimizedInDeskAtEnd(change), ) } private fun DesktopRepository.isDesktopTask(task: RunningTaskInfo): Boolean = if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { isActiveTask(task.taskId) Loading @@ -193,6 +276,17 @@ class DesktopBackNavTransitionObserver( } } private fun DesktopRepository.isLastTask(taskInfo: RunningTaskInfo, deskId: Int): Boolean = if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { hasOnlyOneVisibleTask(taskInfo.displayId) } else { isOnlyVisibleTaskInDesk(taskInfo.taskId, deskId) } private fun TransitionInfo.taskChanges(): List<TransitionInfo.Change> { return changes.filter { change -> change.taskInfo != null && change.taskInfo?.taskId != -1 } } private fun logD(msg: String, vararg arguments: Any?) { ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandler.kt +11 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.IBinder import android.os.SystemProperties import android.view.SurfaceControl.Transaction import android.view.WindowManager.TRANSIT_TO_BACK import android.window.DesktopExperienceFlags import android.window.TransitionInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction Loading Loading @@ -98,7 +99,16 @@ class DesktopMinimizationTransitionHandler( animations += info.changes .filter { checkChangeMode(it) && it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM checkChangeMode(it) && (it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM || // Minimizing desktop tasks can be fullscreen too, such as // in some back-nav cases where the task is reparented out // into a touch-first TDA before being forcibly put back into // a desk as a minimized task by // [DesktopBackBavTransitionObserver]. // Also, fullscreen-in-desktop tasks for immersive or // fullscreen app requests. DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) } .mapNotNull { createMinimizeAnimation(it, finishTransaction, onAnimFinish, startAnimDelay) Loading Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/MinimizeAnimator.kt +12 −0 Original line number Diff line number Diff line Loading @@ -23,9 +23,11 @@ import android.content.Context import android.os.Handler import android.view.Choreographer import android.view.SurfaceControl.Transaction import android.window.DesktopExperienceFlags import android.window.TransitionInfo.Change import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW import com.android.internal.jank.InteractionJankMonitor import com.android.wm.shell.shared.animation.WindowAnimator.BoundsAnimationParams.AnimationBounds import java.time.Duration /** Creates minimization animation */ Loading @@ -39,6 +41,16 @@ object MinimizeAnimator { endOffsetYDp = 12f, endScale = 0.97f, interpolator = Interpolators.STANDARD_ACCELERATE, animBounds = if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { // In some cases, nav-back on the last desktop task may cause it to be reparented // into a fullscreen TDA before being minimized back into a desk by // [DesktopBackNavTransitionObserver]. The minimize animation would then occur when // the task is still fullscreen, which means it should use the start bounds for the // minimize animation. AnimationBounds.START } else { AnimationBounds.END } ) /** Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/WindowAnimator.kt +12 −3 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import android.view.Choreographer import android.view.SurfaceControl import android.view.animation.Interpolator import android.window.TransitionInfo import com.android.wm.shell.shared.animation.WindowAnimator.BoundsAnimationParams.AnimationBounds.END import com.android.wm.shell.shared.animation.WindowAnimator.BoundsAnimationParams.AnimationBounds.START /** Creates animations that can be applied to windows/surfaces. */ object WindowAnimator { Loading @@ -38,7 +40,10 @@ object WindowAnimator { val startScale: Float = 1f, val endScale: Float = 1f, val interpolator: Interpolator, ) val animBounds: AnimationBounds = END, ) { enum class AnimationBounds { START, END } } /** * Creates an animator to reposition and scale the bounds of the leash of the given change. Loading @@ -54,10 +59,14 @@ object WindowAnimator { change: TransitionInfo.Change, transaction: SurfaceControl.Transaction, ): ValueAnimator { val bounds = when (boundsAnimDef.animBounds) { START -> change.startAbsBounds END -> change.endAbsBounds } val startPos = getPosition( displayMetrics, change.endAbsBounds, bounds, boundsAnimDef.startScale, boundsAnimDef.startOffsetYDp, ) Loading @@ -65,7 +74,7 @@ object WindowAnimator { val endPos = getPosition( displayMetrics, change.endAbsBounds, bounds, boundsAnimDef.endScale, boundsAnimDef.endOffsetYDp, ) Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −0 Original line number Diff line number Diff line Loading @@ -1387,6 +1387,7 @@ public abstract class WMShellModule { Optional<DesktopMixedTransitionHandler> desktopMixedTransitionHandler, Optional<BackAnimationController> backAnimationController, DesksOrganizer desksOrganizer, Transitions transitions, DesktopState desktopState, ShellInit shellInit) { return desktopUserRepositories.flatMap( Loading @@ -1397,6 +1398,7 @@ public abstract class WMShellModule { desktopMixedTransitionHandler.get(), backAnimationController.get(), desksOrganizer, transitions, desktopState, shellInit))); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopBackNavTransitionObserver.kt +164 −70 Original line number Diff line number Diff line Loading @@ -18,11 +18,14 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.os.IBinder import android.view.WindowManager.TRANSIT_CHANGE import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_TO_BACK import android.view.WindowManager.transitTypeToString import android.window.DesktopExperienceFlags import android.window.DesktopModeFlags import android.window.TransitionInfo import android.window.WindowContainerTransaction import com.android.internal.protolog.ProtoLog import com.android.wm.shell.back.BackAnimationController import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.isExitDesktopModeTransition Loading @@ -31,6 +34,7 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.desktopmode.DesktopState import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions /** * Class responsible for updating [DesktopRepository] with back navigation related changes. Also Loading @@ -42,6 +46,7 @@ class DesktopBackNavTransitionObserver( private val desktopMixedTransitionHandler: DesktopMixedTransitionHandler, private val backAnimationController: BackAnimationController, private val desksOrganizer: DesksOrganizer, private val transitions: Transitions, desktopState: DesktopState, shellInit: ShellInit, ) { Loading Loading @@ -75,79 +80,91 @@ class DesktopBackNavTransitionObserver( val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (desktopRepository.isExitingDesktopTask(change)) { logD("removeTaskIfNeeded taskId=%d", taskInfo.taskId) desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId) } } } private fun handleBackNavigation(transition: IBinder, info: TransitionInfo) { // When default back navigation happens, transition type is TO_BACK and the change is // TO_BACK. Mark the task going to back as minimized. if (info.type == TRANSIT_TO_BACK) { for (change in info.changes) { val taskInfo = change.taskInfo if (taskInfo == null || taskInfo.taskId == -1) { continue } val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) val isInDesktop = desktopRepository.isAnyDeskActive(taskInfo.displayId) if ( isInDesktop && change.mode == TRANSIT_TO_BACK && desktopRepository.isDesktopTask(taskInfo) ) { val isLastTask = if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { desktopRepository.hasOnlyOneVisibleTask(taskInfo.displayId) } else { desktopRepository.isOnlyVisibleTask(taskInfo.taskId, taskInfo.displayId) } logD( "handleBackNavigation marking to-back taskId=%d as minimized", taskInfo.taskId, val taskToMinimize = findTaskToMinimize(info) ?: return logD("handleBackNavigation taskToMinimize=%s", taskToMinimize) desktopUserRepositories .getProfile(taskToMinimize.taskInfo.userId) .minimizeTaskInDesk( displayId = taskToMinimize.displayId, deskId = taskToMinimize.deskId, taskId = taskToMinimize.taskId, ) desktopRepository.minimizeTask(taskInfo.displayId, taskInfo.taskId) desktopMixedTransitionHandler.addPendingMixedTransition( DesktopMixedTransitionHandler.PendingMixedTransition.Minimize( transition, taskInfo.taskId, isLastTask, taskToMinimize.taskId, taskToMinimize.isLastTask, ) ) if (taskToMinimize.shouldReparentToDesk) { // The task was reparented out of the desk. Move it back into the desk, but minimized. val wct = WindowContainerTransaction() desksOrganizer.moveTaskToDesk( wct = wct, deskId = taskToMinimize.deskId, task = taskToMinimize.taskInfo, minimized = true, ) if (!wct.isEmpty) { transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) } } } } else if (info.type == TRANSIT_CLOSE) { // In some cases app will be closing as a result of back navigation but we would like // to minimize. Mark the task closing as minimized. var hasWallpaperClosing = false var minimizingTask: Int? = null for (change in info.changes) { val taskInfo = change.taskInfo if (taskInfo == null || taskInfo.taskId == -1) continue if ( TransitionUtil.isClosingMode(change.mode) && DesktopWallpaperActivity.isWallpaperTask(taskInfo) private data class TaskToMinimize( val taskId: Int, val deskId: Int, val displayId: Int, val isLastTask: Boolean, val shouldReparentToDesk: Boolean, ) { hasWallpaperClosing = true constructor( taskInfo: RunningTaskInfo, deskId: Int, isLastTask: Boolean, shouldReparentToDesk: Boolean, ) : this(taskInfo.taskId, deskId, taskInfo.displayId, isLastTask, shouldReparentToDesk) { this.taskInfo = taskInfo } if (change.mode == TRANSIT_CLOSE && minimizingTask == null) { minimizingTask = getMinimizingTaskForClosingTransition(taskInfo) } lateinit var taskInfo: RunningTaskInfo } if (minimizingTask == null) return // If the transition has wallpaper closing, it means we are moving out of desktop. logD("handleBackNavigation marking close taskId=%d as minimized", minimizingTask) desktopMixedTransitionHandler.addPendingMixedTransition( DesktopMixedTransitionHandler.PendingMixedTransition.Minimize( transition, minimizingTask, isLastTask = hasWallpaperClosing, ) ) private fun findTaskToMinimize(info: TransitionInfo): TaskToMinimize? { if (info.type != TRANSIT_TO_BACK && info.type != TRANSIT_CLOSE) return null val hasWallpaperClosing = info.taskChanges().any { change -> TransitionUtil.isClosingMode(change.mode) && DesktopWallpaperActivity.isWallpaperTask(checkNotNull(change.taskInfo)) } for (change in info.taskChanges()) { val mode = change.mode when (info.type) { TRANSIT_TO_BACK -> { val taskToMinimize = getMinimizingTaskForToBackTransition(change) if (taskToMinimize != null) { return taskToMinimize } } TRANSIT_CLOSE -> { if (mode != TRANSIT_CLOSE) continue val taskToMinimize = getMinimizingTaskForClosingTransition(change, hasWallpaperClosing) if (taskToMinimize != null) { return taskToMinimize } } else -> error("Unsupported transition type: ${transitTypeToString(info.type)}") } } return null } /** Loading @@ -162,21 +179,87 @@ class DesktopBackNavTransitionObserver( * will be rare. E.g. triggering back navigation on an app that pops up a close dialog, and * closing it will minimize it here. */ private fun getMinimizingTaskForClosingTransition(taskInfo: RunningTaskInfo): Int? { val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) val isInDesktop = desktopRepository.isAnyDeskActive(taskInfo.displayId) private fun getMinimizingTaskForClosingTransition( change: TransitionInfo.Change, hasWallpaperClosing: Boolean, ): TaskToMinimize? { val taskInfo = change.taskInfo ?: return null if (taskInfo.taskId == -1) return null val repository = desktopUserRepositories.getProfile(taskInfo.userId) if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { val deskId = repository.getActiveDeskId(taskInfo.displayId) if ( deskId != null && repository.isDesktopTask(taskInfo) && backAnimationController.latestTriggerBackTask == taskInfo.taskId && !repository.isClosingTask(taskInfo.taskId) ) { return TaskToMinimize( taskInfo = taskInfo, deskId = deskId, isLastTask = hasWallpaperClosing, shouldReparentToDesk = false, ) } return null } val deskId = repository.getDeskIdForTask(taskInfo.taskId) if ( isInDesktop && desktopRepository.isDesktopTask(taskInfo) && deskId != null && backAnimationController.latestTriggerBackTask == taskInfo.taskId && !desktopRepository.isClosingTask(taskInfo.taskId) !repository.isClosingTask(taskInfo.taskId) ) { desktopRepository.minimizeTask(taskInfo.displayId, taskInfo.taskId) return taskInfo.taskId return TaskToMinimize( taskInfo = taskInfo, deskId = deskId, isLastTask = hasWallpaperClosing, shouldReparentToDesk = false, ) } return null } /** * Given this a task in a to-back transition, a task is assumed to be closed by back navigation * if: * 1) Desktop mode is visible. * 2) It is a desktop task. * 3) Change mode is to-back. */ private fun getMinimizingTaskForToBackTransition( change: TransitionInfo.Change ): TaskToMinimize? { val taskInfo = change.taskInfo ?: return null if (taskInfo.taskId == -1) return null if (change.mode != TRANSIT_TO_BACK) return null val repository = desktopUserRepositories.getProfile(taskInfo.userId) if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { val deskId = repository.getActiveDeskId(taskInfo.displayId) if (deskId != null && repository.isDesktopTask(taskInfo)) { return TaskToMinimize( taskInfo = taskInfo, deskId = deskId, isLastTask = repository.isLastTask(taskInfo, deskId), shouldReparentToDesk = false, ) } return null } val deskId = repository.getDeskIdForTask(taskInfo.taskId) if (deskId == null) { return null } return TaskToMinimize( taskInfo = taskInfo, deskId = deskId, isLastTask = repository.isLastTask(taskInfo, deskId), // Some back navigation transitions can result in the task being reparented out of its // original desk and into the TDA. Given we want this task to end up minimized in that // same desk, check here if this happened so that we can reparent as minimized. shouldReparentToDesk = !desksOrganizer.isMinimizedInDeskAtEnd(change), ) } private fun DesktopRepository.isDesktopTask(task: RunningTaskInfo): Boolean = if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { isActiveTask(task.taskId) Loading @@ -193,6 +276,17 @@ class DesktopBackNavTransitionObserver( } } private fun DesktopRepository.isLastTask(taskInfo: RunningTaskInfo, deskId: Int): Boolean = if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { hasOnlyOneVisibleTask(taskInfo.displayId) } else { isOnlyVisibleTaskInDesk(taskInfo.taskId, deskId) } private fun TransitionInfo.taskChanges(): List<TransitionInfo.Change> { return changes.filter { change -> change.taskInfo != null && change.taskInfo?.taskId != -1 } } private fun logD(msg: String, vararg arguments: Any?) { ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandler.kt +11 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.IBinder import android.os.SystemProperties import android.view.SurfaceControl.Transaction import android.view.WindowManager.TRANSIT_TO_BACK import android.window.DesktopExperienceFlags import android.window.TransitionInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction Loading Loading @@ -98,7 +99,16 @@ class DesktopMinimizationTransitionHandler( animations += info.changes .filter { checkChangeMode(it) && it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM checkChangeMode(it) && (it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM || // Minimizing desktop tasks can be fullscreen too, such as // in some back-nav cases where the task is reparented out // into a touch-first TDA before being forcibly put back into // a desk as a minimized task by // [DesktopBackBavTransitionObserver]. // Also, fullscreen-in-desktop tasks for immersive or // fullscreen app requests. DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) } .mapNotNull { createMinimizeAnimation(it, finishTransaction, onAnimFinish, startAnimDelay) Loading