Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +11 −1 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import com.android.wm.shell.desktopmode.DesktopModeTaskRepository; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.freeform.FreeformComponents; import com.android.wm.shell.freeform.FreeformTaskListener; Loading Loading @@ -690,6 +691,7 @@ public abstract class WMShellModule { Transitions transitions, EnterDesktopTaskTransitionHandler enterDesktopTransitionHandler, ExitDesktopTaskTransitionHandler exitDesktopTransitionHandler, ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository, LaunchAdjacentController launchAdjacentController, @ShellMainThread ShellExecutor mainExecutor Loading @@ -697,7 +699,8 @@ public abstract class WMShellModule { return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController, displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler, desktopModeTaskRepository, launchAdjacentController, mainExecutor); toggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository, launchAdjacentController, mainExecutor); } @WMSingleton Loading @@ -707,6 +710,13 @@ public abstract class WMShellModule { return new EnterDesktopTaskTransitionHandler(transitions); } @WMSingleton @Provides static ToggleResizeDesktopTaskTransitionHandler provideToggleResizeDesktopTaskTransitionHandler( Transitions transitions) { return new ToggleResizeDesktopTaskTransitionHandler(transitions); } @WMSingleton @Provides static ExitDesktopTaskTransitionHandler provideExitDesktopTaskTransitionHandler( Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +54 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.graphics.Rect import android.graphics.Region import android.os.IBinder import android.os.SystemProperties import android.util.DisplayMetrics.DENSITY_DEFAULT import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE import android.view.WindowManager.TRANSIT_NONE Loading Loading @@ -78,6 +79,8 @@ class DesktopTasksController( private val transitions: Transitions, private val enterDesktopTaskTransitionHandler: EnterDesktopTaskTransitionHandler, private val exitDesktopTaskTransitionHandler: ExitDesktopTaskTransitionHandler, private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler, private val desktopModeTaskRepository: DesktopModeTaskRepository, private val launchAdjacentController: LaunchAdjacentController, @ShellMainThread private val mainExecutor: ShellExecutor Loading Loading @@ -382,6 +385,49 @@ class DesktopTasksController( } } /** Quick-resizes a desktop task, toggling between the stable bounds and the default bounds. */ fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo, windowDecor: DesktopModeWindowDecoration) { val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return val stableBounds = Rect() displayLayout.getStableBounds(stableBounds) val destinationBounds = Rect() if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) { // The desktop task is currently occupying the whole stable bounds, toggle to the // default bounds. getDefaultDesktopTaskBounds( density = taskInfo.configuration.densityDpi.toFloat() / DENSITY_DEFAULT, stableBounds = stableBounds, outBounds = destinationBounds ) } else { // Toggle to the stable bounds. destinationBounds.set(stableBounds) } val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds) if (Transitions.ENABLE_SHELL_TRANSITIONS) { toggleResizeDesktopTaskTransitionHandler.startTransition( wct, taskInfo.taskId, windowDecor ) } else { shellTaskOrganizer.applyTransaction(wct) } } private fun getDefaultDesktopTaskBounds(density: Float, stableBounds: Rect, outBounds: Rect) { val width = (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f).toInt() val height = (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f).toInt() outBounds.set(0, 0, width, height) // Center the task in stable bounds outBounds.offset( stableBounds.centerX() - outBounds.centerX(), stableBounds.centerY() - outBounds.centerY() ) } /** * Get windowing move for a given `taskId` * Loading Loading @@ -883,6 +929,14 @@ class DesktopTasksController( SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 0) private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000) // Override default freeform task width when desktop mode is enabled. In dips. private val DESKTOP_MODE_DEFAULT_WIDTH_DP = SystemProperties.getInt("persist.wm.debug.desktop_mode.default_width", 840) // Override default freeform task height when desktop mode is enabled. In dips. private val DESKTOP_MODE_DEFAULT_HEIGHT_DP = SystemProperties.getInt("persist.wm.debug.desktop_mode.default_height", 630) /** * Check if desktop density override is enabled */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt 0 → 100644 +154 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.desktopmode import android.animation.Animator import android.animation.RectEvaluator import android.animation.ValueAnimator import android.graphics.Rect import android.os.IBinder import android.util.SparseArray import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE import android.window.TransitionInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import androidx.core.animation.addListener import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration import java.util.function.Supplier /** Handles the animation of quick resizing of desktop tasks. */ class ToggleResizeDesktopTaskTransitionHandler( private val transitions: Transitions, private val transactionSupplier: Supplier<SurfaceControl.Transaction> ) : Transitions.TransitionHandler { private val rectEvaluator = RectEvaluator(Rect()) private val taskToDecorationMap = SparseArray<DesktopModeWindowDecoration>() private var boundsAnimator: Animator? = null constructor( transitions: Transitions ) : this(transitions, Supplier { SurfaceControl.Transaction() }) /** Starts a quick resize transition. */ fun startTransition( wct: WindowContainerTransaction, taskId: Int, windowDecoration: DesktopModeWindowDecoration ) { // Pause relayout until the transition animation finishes. windowDecoration.incrementRelayoutBlock() transitions.startTransition(TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE, wct, this) taskToDecorationMap.put(taskId, windowDecoration) } override fun startAnimation( transition: IBinder, info: TransitionInfo, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction, finishCallback: Transitions.TransitionFinishCallback ): Boolean { val change = findRelevantChange(info) val leash = change.leash val taskId = change.taskInfo.taskId val startBounds = change.startAbsBounds val endBounds = change.endAbsBounds val windowDecor = taskToDecorationMap.removeReturnOld(taskId) ?: throw IllegalStateException("Window decoration not found for task $taskId") val tx = transactionSupplier.get() boundsAnimator?.cancel() boundsAnimator = ValueAnimator.ofObject(rectEvaluator, startBounds, endBounds) .setDuration(RESIZE_DURATION_MS) .apply { addListener( onStart = { startTransaction .setPosition( leash, startBounds.left.toFloat(), startBounds.top.toFloat() ) .setWindowCrop(leash, startBounds.width(), startBounds.height()) .show(leash) windowDecor.showResizeVeil(startTransaction, startBounds) }, onEnd = { finishTransaction .setPosition( leash, endBounds.left.toFloat(), endBounds.top.toFloat() ) .setWindowCrop(leash, endBounds.width(), endBounds.height()) .show(leash) windowDecor.hideResizeVeil() finishCallback.onTransitionFinished(null, null) boundsAnimator = null } ) addUpdateListener { anim -> val rect = anim.animatedValue as Rect tx.setPosition(leash, rect.left.toFloat(), rect.top.toFloat()) .setWindowCrop(leash, rect.width(), rect.height()) .show(leash) windowDecor.updateResizeVeil(tx, rect) } start() } return true } override fun handleRequest( transition: IBinder, request: TransitionRequestInfo ): WindowContainerTransaction? { return null } private fun findRelevantChange(info: TransitionInfo): TransitionInfo.Change { val matchingChanges = info.changes.filter { c -> !isWallpaper(c) && isValidTaskChange(c) && c.mode == TRANSIT_CHANGE } if (matchingChanges.size != 1) { throw IllegalStateException( "Expected 1 relevant change but found: ${matchingChanges.size}" ) } return matchingChanges.first() } private fun isWallpaper(change: TransitionInfo.Change): Boolean { return (change.flags and TransitionInfo.FLAG_IS_WALLPAPER) != 0 } private fun isValidTaskChange(change: TransitionInfo.Change): Boolean { return change.taskInfo != null && change.taskInfo?.taskId != -1 } companion object { private const val RESIZE_DURATION_MS = 300L } } libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +4 −0 Original line number Diff line number Diff line Loading @@ -161,6 +161,10 @@ public class Transitions implements RemoteCallable<Transitions>, public static final int TRANSIT_CANCEL_ENTERING_DESKTOP_MODE = WindowManager.TRANSIT_FIRST_CUSTOM + 13; /** Transition type to animate the toggle resize between the max and default desktop sizes. */ public static final int TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE = WindowManager.TRANSIT_FIRST_CUSTOM + 14; private final WindowOrganizer mOrganizer; private final Context mContext; private final ShellExecutor mMainExecutor; Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +3 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import android.window.TransitionInfo; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import androidx.annotation.Nullable; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; Loading Loading @@ -258,7 +260,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { * @return {@code true} if a drag is happening; or {@code false} if it is not */ @Override public boolean handleMotionEvent(MotionEvent e) { public boolean handleMotionEvent(@Nullable View v, MotionEvent e) { final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { return false; Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +11 −1 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import com.android.wm.shell.desktopmode.DesktopModeTaskRepository; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.freeform.FreeformComponents; import com.android.wm.shell.freeform.FreeformTaskListener; Loading Loading @@ -690,6 +691,7 @@ public abstract class WMShellModule { Transitions transitions, EnterDesktopTaskTransitionHandler enterDesktopTransitionHandler, ExitDesktopTaskTransitionHandler exitDesktopTransitionHandler, ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository, LaunchAdjacentController launchAdjacentController, @ShellMainThread ShellExecutor mainExecutor Loading @@ -697,7 +699,8 @@ public abstract class WMShellModule { return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController, displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler, desktopModeTaskRepository, launchAdjacentController, mainExecutor); toggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository, launchAdjacentController, mainExecutor); } @WMSingleton Loading @@ -707,6 +710,13 @@ public abstract class WMShellModule { return new EnterDesktopTaskTransitionHandler(transitions); } @WMSingleton @Provides static ToggleResizeDesktopTaskTransitionHandler provideToggleResizeDesktopTaskTransitionHandler( Transitions transitions) { return new ToggleResizeDesktopTaskTransitionHandler(transitions); } @WMSingleton @Provides static ExitDesktopTaskTransitionHandler provideExitDesktopTaskTransitionHandler( Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +54 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.graphics.Rect import android.graphics.Region import android.os.IBinder import android.os.SystemProperties import android.util.DisplayMetrics.DENSITY_DEFAULT import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE import android.view.WindowManager.TRANSIT_NONE Loading Loading @@ -78,6 +79,8 @@ class DesktopTasksController( private val transitions: Transitions, private val enterDesktopTaskTransitionHandler: EnterDesktopTaskTransitionHandler, private val exitDesktopTaskTransitionHandler: ExitDesktopTaskTransitionHandler, private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler, private val desktopModeTaskRepository: DesktopModeTaskRepository, private val launchAdjacentController: LaunchAdjacentController, @ShellMainThread private val mainExecutor: ShellExecutor Loading Loading @@ -382,6 +385,49 @@ class DesktopTasksController( } } /** Quick-resizes a desktop task, toggling between the stable bounds and the default bounds. */ fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo, windowDecor: DesktopModeWindowDecoration) { val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return val stableBounds = Rect() displayLayout.getStableBounds(stableBounds) val destinationBounds = Rect() if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) { // The desktop task is currently occupying the whole stable bounds, toggle to the // default bounds. getDefaultDesktopTaskBounds( density = taskInfo.configuration.densityDpi.toFloat() / DENSITY_DEFAULT, stableBounds = stableBounds, outBounds = destinationBounds ) } else { // Toggle to the stable bounds. destinationBounds.set(stableBounds) } val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds) if (Transitions.ENABLE_SHELL_TRANSITIONS) { toggleResizeDesktopTaskTransitionHandler.startTransition( wct, taskInfo.taskId, windowDecor ) } else { shellTaskOrganizer.applyTransaction(wct) } } private fun getDefaultDesktopTaskBounds(density: Float, stableBounds: Rect, outBounds: Rect) { val width = (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f).toInt() val height = (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f).toInt() outBounds.set(0, 0, width, height) // Center the task in stable bounds outBounds.offset( stableBounds.centerX() - outBounds.centerX(), stableBounds.centerY() - outBounds.centerY() ) } /** * Get windowing move for a given `taskId` * Loading Loading @@ -883,6 +929,14 @@ class DesktopTasksController( SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 0) private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000) // Override default freeform task width when desktop mode is enabled. In dips. private val DESKTOP_MODE_DEFAULT_WIDTH_DP = SystemProperties.getInt("persist.wm.debug.desktop_mode.default_width", 840) // Override default freeform task height when desktop mode is enabled. In dips. private val DESKTOP_MODE_DEFAULT_HEIGHT_DP = SystemProperties.getInt("persist.wm.debug.desktop_mode.default_height", 630) /** * Check if desktop density override is enabled */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt 0 → 100644 +154 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.desktopmode import android.animation.Animator import android.animation.RectEvaluator import android.animation.ValueAnimator import android.graphics.Rect import android.os.IBinder import android.util.SparseArray import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE import android.window.TransitionInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import androidx.core.animation.addListener import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration import java.util.function.Supplier /** Handles the animation of quick resizing of desktop tasks. */ class ToggleResizeDesktopTaskTransitionHandler( private val transitions: Transitions, private val transactionSupplier: Supplier<SurfaceControl.Transaction> ) : Transitions.TransitionHandler { private val rectEvaluator = RectEvaluator(Rect()) private val taskToDecorationMap = SparseArray<DesktopModeWindowDecoration>() private var boundsAnimator: Animator? = null constructor( transitions: Transitions ) : this(transitions, Supplier { SurfaceControl.Transaction() }) /** Starts a quick resize transition. */ fun startTransition( wct: WindowContainerTransaction, taskId: Int, windowDecoration: DesktopModeWindowDecoration ) { // Pause relayout until the transition animation finishes. windowDecoration.incrementRelayoutBlock() transitions.startTransition(TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE, wct, this) taskToDecorationMap.put(taskId, windowDecoration) } override fun startAnimation( transition: IBinder, info: TransitionInfo, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction, finishCallback: Transitions.TransitionFinishCallback ): Boolean { val change = findRelevantChange(info) val leash = change.leash val taskId = change.taskInfo.taskId val startBounds = change.startAbsBounds val endBounds = change.endAbsBounds val windowDecor = taskToDecorationMap.removeReturnOld(taskId) ?: throw IllegalStateException("Window decoration not found for task $taskId") val tx = transactionSupplier.get() boundsAnimator?.cancel() boundsAnimator = ValueAnimator.ofObject(rectEvaluator, startBounds, endBounds) .setDuration(RESIZE_DURATION_MS) .apply { addListener( onStart = { startTransaction .setPosition( leash, startBounds.left.toFloat(), startBounds.top.toFloat() ) .setWindowCrop(leash, startBounds.width(), startBounds.height()) .show(leash) windowDecor.showResizeVeil(startTransaction, startBounds) }, onEnd = { finishTransaction .setPosition( leash, endBounds.left.toFloat(), endBounds.top.toFloat() ) .setWindowCrop(leash, endBounds.width(), endBounds.height()) .show(leash) windowDecor.hideResizeVeil() finishCallback.onTransitionFinished(null, null) boundsAnimator = null } ) addUpdateListener { anim -> val rect = anim.animatedValue as Rect tx.setPosition(leash, rect.left.toFloat(), rect.top.toFloat()) .setWindowCrop(leash, rect.width(), rect.height()) .show(leash) windowDecor.updateResizeVeil(tx, rect) } start() } return true } override fun handleRequest( transition: IBinder, request: TransitionRequestInfo ): WindowContainerTransaction? { return null } private fun findRelevantChange(info: TransitionInfo): TransitionInfo.Change { val matchingChanges = info.changes.filter { c -> !isWallpaper(c) && isValidTaskChange(c) && c.mode == TRANSIT_CHANGE } if (matchingChanges.size != 1) { throw IllegalStateException( "Expected 1 relevant change but found: ${matchingChanges.size}" ) } return matchingChanges.first() } private fun isWallpaper(change: TransitionInfo.Change): Boolean { return (change.flags and TransitionInfo.FLAG_IS_WALLPAPER) != 0 } private fun isValidTaskChange(change: TransitionInfo.Change): Boolean { return change.taskInfo != null && change.taskInfo?.taskId != -1 } companion object { private const val RESIZE_DURATION_MS = 300L } }
libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +4 −0 Original line number Diff line number Diff line Loading @@ -161,6 +161,10 @@ public class Transitions implements RemoteCallable<Transitions>, public static final int TRANSIT_CANCEL_ENTERING_DESKTOP_MODE = WindowManager.TRANSIT_FIRST_CUSTOM + 13; /** Transition type to animate the toggle resize between the max and default desktop sizes. */ public static final int TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE = WindowManager.TRANSIT_FIRST_CUSTOM + 14; private final WindowOrganizer mOrganizer; private final Context mContext; private final ShellExecutor mMainExecutor; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +3 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import android.window.TransitionInfo; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import androidx.annotation.Nullable; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; Loading Loading @@ -258,7 +260,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { * @return {@code true} if a drag is happening; or {@code false} if it is not */ @Override public boolean handleMotionEvent(MotionEvent e) { public boolean handleMotionEvent(@Nullable View v, MotionEvent e) { final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { return false; Loading