Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +4 −2 Original line number Diff line number Diff line Loading @@ -1213,7 +1213,8 @@ public abstract class WMShellModule { ShellTaskOrganizer shellTaskOrganizer, TaskStackListenerImpl taskStackListener, ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, @DynamicOverride DesktopUserRepositories desktopUserRepositories) { @DynamicOverride DesktopUserRepositories desktopUserRepositories, DisplayController displayController) { if (DesktopModeStatus.canEnterDesktopMode(context)) { return Optional.of( new DesktopActivityOrientationChangeHandler( Loading @@ -1222,7 +1223,8 @@ public abstract class WMShellModule { shellTaskOrganizer, taskStackListener, toggleResizeDesktopTaskTransitionHandler, desktopUserRepositories)); desktopUserRepositories, displayController)); } return Optional.empty(); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandler.kt +18 −5 Original line number Diff line number Diff line Loading @@ -23,10 +23,10 @@ import android.content.pm.ActivityInfo.ScreenOrientation import android.content.res.Configuration.ORIENTATION_LANDSCAPE import android.content.res.Configuration.ORIENTATION_PORTRAIT import android.graphics.Rect import android.util.Size import android.window.WindowContainerTransaction import com.android.window.flags.Flags import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.TaskStackListenerCallback import com.android.wm.shell.common.TaskStackListenerImpl import com.android.wm.shell.shared.desktopmode.DesktopModeStatus Loading @@ -40,6 +40,7 @@ class DesktopActivityOrientationChangeHandler( private val taskStackListener: TaskStackListenerImpl, private val resizeHandler: ToggleResizeDesktopTaskTransitionHandler, private val desktopUserRepositories: DesktopUserRepositories, private val displayController: DisplayController, ) { init { Loading Loading @@ -101,12 +102,24 @@ class DesktopActivityOrientationChangeHandler( orientation == ORIENTATION_LANDSCAPE && ActivityInfo.isFixedOrientationPortrait(requestedOrientation) ) { val displayLayout = displayController.getDisplayLayout(task.displayId) ?: return val captionInsets = task.configuration.windowConfiguration.appBounds?.let { it.top - task.configuration.windowConfiguration.bounds.top } ?: 0 val newOrientationBounds = calculateInitialBounds( displayLayout = displayLayout, taskInfo = task, captionInsets = captionInsets, requestedScreenOrientation = requestedOrientation, ) val finalSize = Size(taskHeight, taskWidth) // Use the center x as the resizing anchor point. val left = taskBounds.centerX() - finalSize.width / 2 val right = left + finalSize.width val finalBounds = Rect(left, taskBounds.top, right, taskBounds.top + finalSize.height) val left = taskBounds.centerX() - newOrientationBounds.width() / 2 val right = left + newOrientationBounds.width() val finalBounds = Rect(left, taskBounds.top, right, taskBounds.top + newOrientationBounds.height()) val wct = WindowContainerTransaction().setBounds(task.token, finalBounds) resizeHandler.startTransition(wct) Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +20 −8 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ fun calculateInitialBounds( taskInfo: RunningTaskInfo, scale: Float = DESKTOP_MODE_INITIAL_BOUNDS_SCALE, captionInsets: Int = 0, requestedScreenOrientation: Int? = null, ): Rect { val screenBounds = Rect(0, 0, displayLayout.width(), displayLayout.height()) val appAspectRatio = calculateAspectRatio(taskInfo) Loading @@ -85,12 +86,13 @@ fun calculateInitialBounds( } val topActivityInfo = taskInfo.topActivityInfo ?: return positionInScreen(idealSize, stableBounds) val screenOrientation = requestedScreenOrientation ?: topActivityInfo.screenOrientation val initialSize: Size = when (taskInfo.configuration.orientation) { ORIENTATION_LANDSCAPE -> { if (taskInfo.canChangeAspectRatio) { if (isFixedOrientationPortrait(topActivityInfo.screenOrientation)) { if (isFixedOrientationPortrait(screenOrientation)) { // For portrait resizeable activities, respect apps fullscreen width but // apply ideal size height. Size( Loading @@ -104,14 +106,20 @@ fun calculateInitialBounds( } else { // If activity is unresizeable, regardless of orientation, calculate maximum // size (within the ideal size) maintaining original aspect ratio. maximizeSizeGivenAspectRatio(taskInfo, idealSize, appAspectRatio, captionInsets) maximizeSizeGivenAspectRatio( taskInfo, idealSize, appAspectRatio, captionInsets, screenOrientation, ) } } ORIENTATION_PORTRAIT -> { val customPortraitWidthForLandscapeApp = screenBounds.width() - (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2) if (taskInfo.canChangeAspectRatio) { if (isFixedOrientationLandscape(topActivityInfo.screenOrientation)) { if (isFixedOrientationLandscape(screenOrientation)) { // For landscape resizeable activities, respect apps fullscreen height and // apply custom app width. Size( Loading @@ -123,7 +131,7 @@ fun calculateInitialBounds( idealSize } } else { if (isFixedOrientationLandscape(topActivityInfo.screenOrientation)) { if (isFixedOrientationLandscape(screenOrientation)) { // For landscape unresizeable activities, apply custom app width to ideal // size and calculate maximum size with this area while maintaining original // aspect ratio. Loading @@ -132,6 +140,7 @@ fun calculateInitialBounds( Size(customPortraitWidthForLandscapeApp, idealSize.height), appAspectRatio, captionInsets, screenOrientation, ) } else { // For portrait unresizeable activities, calculate maximum size (within the Loading @@ -141,6 +150,7 @@ fun calculateInitialBounds( idealSize, appAspectRatio, captionInsets, screenOrientation, ) } } Loading Loading @@ -190,13 +200,16 @@ fun maximizeSizeGivenAspectRatio( targetArea: Size, aspectRatio: Float, captionInsets: Int = 0, requestedScreenOrientation: Int? = null, ): Size { val targetHeight = targetArea.height - captionInsets val targetWidth = targetArea.width val finalHeight: Int val finalWidth: Int // Get orientation either through top activity or task's orientation if (taskInfo.hasPortraitTopActivity()) { val screenOrientation = requestedScreenOrientation ?: taskInfo.topActivityInfo?.screenOrientation if (taskInfo.hasPortraitTopActivity(screenOrientation)) { val tempWidth = ceil(targetHeight / aspectRatio).toInt() if (tempWidth <= targetWidth) { finalHeight = targetHeight Loading Loading @@ -354,9 +367,8 @@ fun centerInArea(desiredSize: Size, areaBounds: Rect, leftStart: Int, topStart: return Rect(newLeft, newTop, newRight, newBottom) } private fun TaskInfo.hasPortraitTopActivity(): Boolean { val topActivityScreenOrientation = topActivityInfo?.screenOrientation ?: SCREEN_ORIENTATION_UNSPECIFIED private fun TaskInfo.hasPortraitTopActivity(screenOrientation: Int?): Boolean { val topActivityScreenOrientation = screenOrientation ?: SCREEN_ORIENTATION_UNSPECIFIED val appBounds = configuration.windowConfiguration.appBounds return when { Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt +18 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,8 @@ import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE import com.android.window.flags.Flags.FLAG_RESPECT_ORIENTATION_CHANGE_FOR_UNRESIZEABLE import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.TaskStackListenerImpl import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask Loading Loading @@ -96,12 +98,15 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer @Mock lateinit var userManager: UserManager @Mock lateinit var shellController: ShellController @Mock lateinit var displayController: DisplayController @Mock lateinit var displayLayout: DisplayLayout private lateinit var mockitoSession: StaticMockitoSession private lateinit var handler: DesktopActivityOrientationChangeHandler private lateinit var shellInit: ShellInit private lateinit var userRepositories: DesktopUserRepositories private lateinit var testScope: CoroutineScope // Mock running tasks are registered here so we can get the list from mock shell task organizer. private val runningTasks = mutableListOf<RunningTaskInfo>() Loading Loading @@ -131,6 +136,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() } whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }) .thenReturn(Desktop.getDefaultInstance()) whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout) handler = DesktopActivityOrientationChangeHandler( Loading @@ -140,6 +146,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { taskStackListener, resizeTransitionHandler, userRepositories, displayController, ) shellInit.init() Loading Loading @@ -171,6 +178,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { taskStackListener, resizeTransitionHandler, userRepositories, displayController, ) verify(shellInit, never()) Loading Loading @@ -251,6 +259,11 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { val oldBounds = task.configuration.windowConfiguration.bounds val newTask = setUpFreeformTask(isResizeable = false, orientation = SCREEN_ORIENTATION_LANDSCAPE) whenever(displayLayout.height()).thenReturn(800) whenever(displayLayout.width()).thenReturn(2000) whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> (i.arguments.first() as Rect).set(Rect(0, 0, 2000, 800)) } handler.handleActivityOrientationChange(task, newTask) Loading Loading @@ -279,6 +292,11 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { bounds = oldBounds, ) val newTask = setUpFreeformTask(isResizeable = false, bounds = oldBounds) whenever(displayLayout.height()).thenReturn(2000) whenever(displayLayout.width()).thenReturn(800) whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> (i.arguments.first() as Rect).set(Rect(0, 0, 800, 2000)) } handler.handleActivityOrientationChange(task, newTask) Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +4 −2 Original line number Diff line number Diff line Loading @@ -1213,7 +1213,8 @@ public abstract class WMShellModule { ShellTaskOrganizer shellTaskOrganizer, TaskStackListenerImpl taskStackListener, ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, @DynamicOverride DesktopUserRepositories desktopUserRepositories) { @DynamicOverride DesktopUserRepositories desktopUserRepositories, DisplayController displayController) { if (DesktopModeStatus.canEnterDesktopMode(context)) { return Optional.of( new DesktopActivityOrientationChangeHandler( Loading @@ -1222,7 +1223,8 @@ public abstract class WMShellModule { shellTaskOrganizer, taskStackListener, toggleResizeDesktopTaskTransitionHandler, desktopUserRepositories)); desktopUserRepositories, displayController)); } return Optional.empty(); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandler.kt +18 −5 Original line number Diff line number Diff line Loading @@ -23,10 +23,10 @@ import android.content.pm.ActivityInfo.ScreenOrientation import android.content.res.Configuration.ORIENTATION_LANDSCAPE import android.content.res.Configuration.ORIENTATION_PORTRAIT import android.graphics.Rect import android.util.Size import android.window.WindowContainerTransaction import com.android.window.flags.Flags import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.TaskStackListenerCallback import com.android.wm.shell.common.TaskStackListenerImpl import com.android.wm.shell.shared.desktopmode.DesktopModeStatus Loading @@ -40,6 +40,7 @@ class DesktopActivityOrientationChangeHandler( private val taskStackListener: TaskStackListenerImpl, private val resizeHandler: ToggleResizeDesktopTaskTransitionHandler, private val desktopUserRepositories: DesktopUserRepositories, private val displayController: DisplayController, ) { init { Loading Loading @@ -101,12 +102,24 @@ class DesktopActivityOrientationChangeHandler( orientation == ORIENTATION_LANDSCAPE && ActivityInfo.isFixedOrientationPortrait(requestedOrientation) ) { val displayLayout = displayController.getDisplayLayout(task.displayId) ?: return val captionInsets = task.configuration.windowConfiguration.appBounds?.let { it.top - task.configuration.windowConfiguration.bounds.top } ?: 0 val newOrientationBounds = calculateInitialBounds( displayLayout = displayLayout, taskInfo = task, captionInsets = captionInsets, requestedScreenOrientation = requestedOrientation, ) val finalSize = Size(taskHeight, taskWidth) // Use the center x as the resizing anchor point. val left = taskBounds.centerX() - finalSize.width / 2 val right = left + finalSize.width val finalBounds = Rect(left, taskBounds.top, right, taskBounds.top + finalSize.height) val left = taskBounds.centerX() - newOrientationBounds.width() / 2 val right = left + newOrientationBounds.width() val finalBounds = Rect(left, taskBounds.top, right, taskBounds.top + newOrientationBounds.height()) val wct = WindowContainerTransaction().setBounds(task.token, finalBounds) resizeHandler.startTransition(wct) Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +20 −8 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ fun calculateInitialBounds( taskInfo: RunningTaskInfo, scale: Float = DESKTOP_MODE_INITIAL_BOUNDS_SCALE, captionInsets: Int = 0, requestedScreenOrientation: Int? = null, ): Rect { val screenBounds = Rect(0, 0, displayLayout.width(), displayLayout.height()) val appAspectRatio = calculateAspectRatio(taskInfo) Loading @@ -85,12 +86,13 @@ fun calculateInitialBounds( } val topActivityInfo = taskInfo.topActivityInfo ?: return positionInScreen(idealSize, stableBounds) val screenOrientation = requestedScreenOrientation ?: topActivityInfo.screenOrientation val initialSize: Size = when (taskInfo.configuration.orientation) { ORIENTATION_LANDSCAPE -> { if (taskInfo.canChangeAspectRatio) { if (isFixedOrientationPortrait(topActivityInfo.screenOrientation)) { if (isFixedOrientationPortrait(screenOrientation)) { // For portrait resizeable activities, respect apps fullscreen width but // apply ideal size height. Size( Loading @@ -104,14 +106,20 @@ fun calculateInitialBounds( } else { // If activity is unresizeable, regardless of orientation, calculate maximum // size (within the ideal size) maintaining original aspect ratio. maximizeSizeGivenAspectRatio(taskInfo, idealSize, appAspectRatio, captionInsets) maximizeSizeGivenAspectRatio( taskInfo, idealSize, appAspectRatio, captionInsets, screenOrientation, ) } } ORIENTATION_PORTRAIT -> { val customPortraitWidthForLandscapeApp = screenBounds.width() - (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2) if (taskInfo.canChangeAspectRatio) { if (isFixedOrientationLandscape(topActivityInfo.screenOrientation)) { if (isFixedOrientationLandscape(screenOrientation)) { // For landscape resizeable activities, respect apps fullscreen height and // apply custom app width. Size( Loading @@ -123,7 +131,7 @@ fun calculateInitialBounds( idealSize } } else { if (isFixedOrientationLandscape(topActivityInfo.screenOrientation)) { if (isFixedOrientationLandscape(screenOrientation)) { // For landscape unresizeable activities, apply custom app width to ideal // size and calculate maximum size with this area while maintaining original // aspect ratio. Loading @@ -132,6 +140,7 @@ fun calculateInitialBounds( Size(customPortraitWidthForLandscapeApp, idealSize.height), appAspectRatio, captionInsets, screenOrientation, ) } else { // For portrait unresizeable activities, calculate maximum size (within the Loading @@ -141,6 +150,7 @@ fun calculateInitialBounds( idealSize, appAspectRatio, captionInsets, screenOrientation, ) } } Loading Loading @@ -190,13 +200,16 @@ fun maximizeSizeGivenAspectRatio( targetArea: Size, aspectRatio: Float, captionInsets: Int = 0, requestedScreenOrientation: Int? = null, ): Size { val targetHeight = targetArea.height - captionInsets val targetWidth = targetArea.width val finalHeight: Int val finalWidth: Int // Get orientation either through top activity or task's orientation if (taskInfo.hasPortraitTopActivity()) { val screenOrientation = requestedScreenOrientation ?: taskInfo.topActivityInfo?.screenOrientation if (taskInfo.hasPortraitTopActivity(screenOrientation)) { val tempWidth = ceil(targetHeight / aspectRatio).toInt() if (tempWidth <= targetWidth) { finalHeight = targetHeight Loading Loading @@ -354,9 +367,8 @@ fun centerInArea(desiredSize: Size, areaBounds: Rect, leftStart: Int, topStart: return Rect(newLeft, newTop, newRight, newBottom) } private fun TaskInfo.hasPortraitTopActivity(): Boolean { val topActivityScreenOrientation = topActivityInfo?.screenOrientation ?: SCREEN_ORIENTATION_UNSPECIFIED private fun TaskInfo.hasPortraitTopActivity(screenOrientation: Int?): Boolean { val topActivityScreenOrientation = screenOrientation ?: SCREEN_ORIENTATION_UNSPECIFIED val appBounds = configuration.windowConfiguration.appBounds return when { Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt +18 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,8 @@ import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE import com.android.window.flags.Flags.FLAG_RESPECT_ORIENTATION_CHANGE_FOR_UNRESIZEABLE import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.TaskStackListenerImpl import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask Loading Loading @@ -96,12 +98,15 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer @Mock lateinit var userManager: UserManager @Mock lateinit var shellController: ShellController @Mock lateinit var displayController: DisplayController @Mock lateinit var displayLayout: DisplayLayout private lateinit var mockitoSession: StaticMockitoSession private lateinit var handler: DesktopActivityOrientationChangeHandler private lateinit var shellInit: ShellInit private lateinit var userRepositories: DesktopUserRepositories private lateinit var testScope: CoroutineScope // Mock running tasks are registered here so we can get the list from mock shell task organizer. private val runningTasks = mutableListOf<RunningTaskInfo>() Loading Loading @@ -131,6 +136,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() } whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }) .thenReturn(Desktop.getDefaultInstance()) whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout) handler = DesktopActivityOrientationChangeHandler( Loading @@ -140,6 +146,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { taskStackListener, resizeTransitionHandler, userRepositories, displayController, ) shellInit.init() Loading Loading @@ -171,6 +178,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { taskStackListener, resizeTransitionHandler, userRepositories, displayController, ) verify(shellInit, never()) Loading Loading @@ -251,6 +259,11 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { val oldBounds = task.configuration.windowConfiguration.bounds val newTask = setUpFreeformTask(isResizeable = false, orientation = SCREEN_ORIENTATION_LANDSCAPE) whenever(displayLayout.height()).thenReturn(800) whenever(displayLayout.width()).thenReturn(2000) whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> (i.arguments.first() as Rect).set(Rect(0, 0, 2000, 800)) } handler.handleActivityOrientationChange(task, newTask) Loading Loading @@ -279,6 +292,11 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { bounds = oldBounds, ) val newTask = setUpFreeformTask(isResizeable = false, bounds = oldBounds) whenever(displayLayout.height()).thenReturn(2000) whenever(displayLayout.width()).thenReturn(800) whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> (i.arguments.first() as Rect).set(Rect(0, 0, 800, 2000)) } handler.handleActivityOrientationChange(task, newTask) Loading