diff options
9 files changed, 163 insertions, 64 deletions
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index ef8501f563dc..aca9bb4d07c1 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -297,6 +297,12 @@ public class TaskInfo { public boolean isTopActivityTransparent; /** + * Whether the top activity has specified style floating. + * @hide + */ + public boolean isTopActivityStyleFloating; + + /** * Encapsulate specific App Compat information. * @hide */ @@ -429,6 +435,7 @@ public class TaskInfo { && parentTaskId == that.parentTaskId && Objects.equals(topActivity, that.topActivity) && isTopActivityTransparent == that.isTopActivityTransparent + && isTopActivityStyleFloating == that.isTopActivityStyleFloating && appCompatTaskInfo.equalsForTaskOrganizer(that.appCompatTaskInfo); } @@ -498,6 +505,7 @@ public class TaskInfo { mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR); displayAreaFeatureId = source.readInt(); isTopActivityTransparent = source.readBoolean(); + isTopActivityStyleFloating = source.readBoolean(); appCompatTaskInfo = source.readTypedObject(AppCompatTaskInfo.CREATOR); } @@ -545,6 +553,7 @@ public class TaskInfo { dest.writeTypedObject(mTopActivityLocusId, flags); dest.writeInt(displayAreaFeatureId); dest.writeBoolean(isTopActivityTransparent); + dest.writeBoolean(isTopActivityStyleFloating); dest.writeTypedObject(appCompatTaskInfo, flags); } @@ -582,6 +591,7 @@ public class TaskInfo { + " locusId=" + mTopActivityLocusId + " displayAreaFeatureId=" + displayAreaFeatureId + " isTopActivityTransparent=" + isTopActivityTransparent + + " isTopActivityStyleFloating=" + isTopActivityStyleFloating + " appCompatTaskInfo=" + appCompatTaskInfo + "}"; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt index 6781d08c9904..d1b2347a4411 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt @@ -19,6 +19,16 @@ package com.android.wm.shell.compatui import android.app.TaskInfo -fun isSingleTopActivityTranslucent(task: TaskInfo) = - task.isTopActivityTransparent && task.numActivities == 1 +import android.content.Context +import com.android.internal.R +// TODO(b/347289970): Consider replacing with API +fun isTopActivityExemptFromDesktopWindowing(context: Context, task: TaskInfo) = + isSystemUiTask(context, task) || (task.isTopActivityTransparent && task.numActivities == 1 + && !task.isTopActivityStyleFloating) + +private fun isSystemUiTask(context: Context, task: TaskInfo): Boolean { + val sysUiPackageName: String = + context.resources.getString(R.string.config_systemUi) + return task.baseActivity?.packageName == sysUiPackageName +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index d8e8c57148ab..ef9ef645430e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -66,7 +66,7 @@ import com.android.wm.shell.common.SyncTransactionQueue import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource 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.compatui.isSingleTopActivityTranslucent +import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener import com.android.wm.shell.draganddrop.DragAndDropController @@ -158,8 +158,6 @@ class DesktopTasksController( visualIndicator = null } } - private val sysUIPackageName = context.resources.getString( - com.android.internal.R.string.config_systemUi) private val transitionAreaHeight get() = @@ -219,11 +217,6 @@ class DesktopTasksController( return visualIndicator } - // TODO(b/347289970): Consider replacing with API - private fun isSystemUIApplication(taskInfo: RunningTaskInfo): Boolean { - return taskInfo.baseActivity?.packageName == sysUIPackageName - } - fun setOnTaskResizeAnimationListener(listener: OnTaskResizeAnimationListener) { toggleResizeDesktopTaskTransitionHandler.setOnTaskResizeAnimationListener(listener) enterDesktopTaskTransitionHandler.setOnTaskResizeAnimationListener(listener) @@ -351,19 +344,12 @@ class DesktopTasksController( wct: WindowContainerTransaction = WindowContainerTransaction(), transitionSource: DesktopModeTransitionSource, ) { - if (Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)) { - KtProtoLog.w( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: Cannot enter desktop, " + - "translucent top activity found. This is likely a modal dialog." - ) - return - } - if (isSystemUIApplication(task)) { + if (Flags.enableDesktopWindowingModalsPolicy() + && isTopActivityExemptFromDesktopWindowing(context, task)) { KtProtoLog.w( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: Cannot enter desktop, " + - "systemUI top activity found." + "ineligible top activity found." ) return } @@ -942,10 +928,8 @@ class DesktopTasksController( when { // Check if the closing task needs to be handled TransitionUtil.isClosingType(request.type) -> handleTaskClosing(task) - // Check if the task has a top transparent activity - shouldLaunchAsModal(task) -> handleIncompatibleTaskLaunch(task) - // Check if the task has a top systemUI activity - isSystemUIApplication(task) -> handleIncompatibleTaskLaunch(task) + // Check if the top task shouldn't be allowed to enter desktop mode + isIncompatibleTask(task) -> handleIncompatibleTaskLaunch(task) // Check if fullscreen task should be updated task.isFullscreen -> handleFullscreenTaskLaunch(task, transition) // Check if freeform task should be updated @@ -979,9 +963,9 @@ class DesktopTasksController( .forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) } } - // TODO(b/347289970): Consider replacing with API - private fun shouldLaunchAsModal(task: TaskInfo) = - Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task) + private fun isIncompatibleTask(task: TaskInfo) = + Flags.enableDesktopWindowingModalsPolicy() + && isTopActivityExemptFromDesktopWindowing(context, task) private fun shouldHandleTaskClosing(request: TransitionRequestInfo): Boolean { return Flags.enableDesktopWindowingWallpaperActivity() && diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index a05dbf844db0..5bf3c253471e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -32,7 +32,7 @@ import static android.view.WindowInsets.Type.statusBars; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; 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.compatui.AppCompatUtils.isTopActivityExemptFromDesktopWindowing; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; @@ -105,7 +105,6 @@ import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; import java.io.PrintWriter; -import java.util.Objects; import java.util.Optional; import java.util.function.Supplier; @@ -1029,12 +1028,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && taskInfo.isFocused) { return false; } - // TODO(b/347289970): Consider replacing with API if (Flags.enableDesktopWindowingModalsPolicy() - && isSingleTopActivityTranslucent(taskInfo)) { - return false; - } - if (isSystemUIApplication(taskInfo)) { + && isTopActivityExemptFromDesktopWindowing(mContext, taskInfo)) { return false; } return DesktopModeStatus.canEnterDesktopMode(mContext) @@ -1113,14 +1108,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && mSplitScreenController.isTaskInSplitScreen(taskId); } - // TODO(b/347289970): Consider replacing with API - private boolean isSystemUIApplication(RunningTaskInfo taskInfo) { - if (taskInfo.baseActivity != null) { - return (Objects.equals(taskInfo.baseActivity.getPackageName(), mSysUIPackageName)); - } - return false; - } - private void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + "DesktopModeWindowDecorViewModel"); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt index 4cd2a366f5eb..ecaf970ae389 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt @@ -16,8 +16,10 @@ package com.android.wm.shell.compatui +import android.content.ComponentName import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest +import com.android.internal.R import com.android.wm.shell.ShellTestCase import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask import org.junit.Assert.assertFalse @@ -34,26 +36,55 @@ import org.junit.runner.RunWith @RunWith(AndroidTestingRunner::class) @SmallTest class AppCompatUtilsTest : ShellTestCase() { - @Test - fun testIsSingleTopActivityTranslucent() { - assertTrue(isSingleTopActivityTranslucent( + fun testIsTopActivityExemptFromDesktopWindowing_topActivityTransparent() { + assertTrue(isTopActivityExemptFromDesktopWindowing(mContext, createFreeformTask(/* displayId */ 0) .apply { isTopActivityTransparent = true numActivities = 1 })) - assertFalse(isSingleTopActivityTranslucent( + assertFalse(isTopActivityExemptFromDesktopWindowing(mContext, createFreeformTask(/* displayId */ 0) .apply { isTopActivityTransparent = true numActivities = 0 })) - assertFalse(isSingleTopActivityTranslucent( + } + + @Test + fun testIsTopActivityExemptFromDesktopWindowing_singleTopActivity() { + assertTrue(isTopActivityExemptFromDesktopWindowing(mContext, + createFreeformTask(/* displayId */ 0) + .apply { + isTopActivityTransparent = true + numActivities = 1 + })) + assertFalse(isTopActivityExemptFromDesktopWindowing(mContext, createFreeformTask(/* displayId */ 0) .apply { isTopActivityTransparent = false numActivities = 1 })) } -}
\ No newline at end of file + + @Test + fun testIsTopActivityExemptFromDesktopWindowing__topActivityStyleFloating() { + assertFalse(isTopActivityExemptFromDesktopWindowing(mContext, + createFreeformTask(/* displayId */ 0) + .apply { + isTopActivityStyleFloating = true + })) + } + + @Test + fun testIsTopActivityExemptFromDesktopWindowing_systemUiTask() { + val systemUIPackageName = context.resources.getString(R.string.config_systemUi) + val baseComponent = ComponentName(systemUIPackageName, /* class */ "") + assertTrue(isTopActivityExemptFromDesktopWindowing(mContext, + createFreeformTask(/* displayId */ 0) + .apply { + baseActivity = baseComponent + })) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 0bcbe139e31f..590598203f6b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -700,19 +700,37 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - fun moveToDesktop_topActivityTranslucent_doesNothing() { - setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + fun moveToDesktop_topActivityTranslucentWithStyleFloating_taskIsMovedToDesktop() { val task = - setUpFullscreenTask().apply { - isTopActivityTransparent = true - numActivities = 1 - } + setUpFullscreenTask().apply { + isTopActivityTransparent = true + isTopActivityStyleFloating = true + numActivities = 1 + } + + controller.moveToDesktop(task, transitionSource = UNKNOWN) + + val wct = getLatestEnterDesktopWct() + assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + fun moveToDesktop_topActivityTranslucentWithoutStyleFloating_doesNothing() { + val task = + setUpFullscreenTask().apply { + isTopActivityTransparent = true + isTopActivityStyleFloating = false + numActivities = 1 + } controller.moveToDesktop(task, transitionSource = UNKNOWN) verifyEnterDesktopWCTNotExecuted() } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) fun moveToDesktop_systemUIActivity_doesNothing() { val task = setUpFullscreenTask() @@ -1368,20 +1386,40 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - fun handleRequest_shouldLaunchAsModal_returnSwitchToFullscreenWCT() { - setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + fun handleRequest_topActivityTransparentWithStyleFloating_returnSwitchToFreeformWCT() { + val freeformTask = setUpFreeformTask() + markTaskVisible(freeformTask) + val task = - setUpFreeformTask().apply { - isTopActivityTransparent = true - numActivities = 1 - } + setUpFullscreenTask().apply { + isTopActivityTransparent = true + isTopActivityStyleFloating = true + numActivities = 1 + } val result = controller.handleRequest(Binder(), createTransition(task)) assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode) - .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN + .isEqualTo(WINDOWING_MODE_FREEFORM) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + fun handleRequest_topActivityTransparentWithoutStyleFloating_returnSwitchToFullscreenWCT() { + val task = + setUpFreeformTask().apply { + isTopActivityTransparent = true + isTopActivityStyleFloating = false + numActivities = 1 + } + + val result = controller.handleRequest(Binder(), createTransition(task)) + assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode) + .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) fun handleRequest_systemUIActivity_returnSwitchToFullscreenWCT() { val task = setUpFreeformTask() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index 4c94c2933383..d85e25c82393 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -346,10 +346,35 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { } @Test - fun testDecorationIsNotCreatedForTopTranslucentActivities() { - setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + fun testDecorationIsCreatedForTopTranslucentActivitiesWithStyleFloating() { + val mockitoSession: StaticMockitoSession = mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(DesktopModeStatus::class.java) + .startMocking() + try { + val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply { + isTopActivityTransparent = true + isTopActivityStyleFloating = true + numActivities = 1 + } + doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + setUpMockDecorationsForTasks(task) + + onTaskOpening(task) + verify(mockDesktopModeWindowDecorFactory) + .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) + } finally { + mockitoSession.finishMocking() + } + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + fun testDecorationIsNotCreatedForTopTranslucentActivitiesWithoutStyleFloating() { val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply { isTopActivityTransparent = true + isTopActivityStyleFloating = false numActivities = 1 } onTaskOpening(task) @@ -359,6 +384,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) fun testDecorationIsNotCreatedForSystemUIActivities() { val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5f19924fc538..2d1ac1b59fba 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -734,6 +734,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ private boolean mOccludesParent; + /** Whether the activity have style floating */ + private boolean mStyleFloating; + /** * Unlike {@link #mOccludesParent} which can be changed at runtime. This is a static attribute * from the style of activity. Because we don't want {@link WindowContainer#getOrientation()} @@ -2188,7 +2191,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A realTheme, com.android.internal.R.styleable.Window, mUserId); if (ent != null) { - mOccludesParent = !ActivityInfo.isTranslucentOrFloating(ent.array) + final boolean styleTranslucent = ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowIsTranslucent, false); + mStyleFloating = ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowIsFloating, false); + mOccludesParent = !(styleTranslucent || mStyleFloating) // This style is propagated to the main window attributes with // FLAG_SHOW_WALLPAPER from PhoneWindow#generateLayout. || ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false); @@ -2197,6 +2204,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mOptOutEdgeToEdge = ent.array.getBoolean( R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false); } else { + mStyleFloating = false; mStyleFillsParent = mOccludesParent = true; noDisplay = false; mOptOutEdgeToEdge = false; @@ -3237,6 +3245,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return occludesParent(true /* includingFinishing */); } + boolean isStyleFloating() { + return mStyleFloating; + } + /** Returns true if this activity is not finishing, is opaque and fills the entire space of * this task. */ boolean occludesParent() { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index f0b0e915da29..b16b0e517b15 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3476,6 +3476,7 @@ class Task extends TaskFragment { info.isVisibleRequested = isVisibleRequested(); info.isSleeping = shouldSleepActivities(); info.isTopActivityTransparent = top != null && !top.fillsParent(); + info.isTopActivityStyleFloating = top != null && top.isStyleFloating(); appCompatTaskInfo.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET; appCompatTaskInfo.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET; appCompatTaskInfo.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET; |