Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98741941 authored by Eghosa Ewansiha-Vlachavas's avatar Eghosa Ewansiha-Vlachavas
Browse files

Prevent system ui applications from entering dw

Don't show app handle and make `moveToDesktop` no-op to prevent entry
with keyboard shortcut. If request comes directly from activity via a
launch straight into freeform, force activity to be fullscreen.

Fixes: 340189815
Test: atest WMShellUnitTests:DesktopModeWindowDecorViewModelTests
Test: atest WMShellUnitTests:DesktopTasksControllerTest
Change-Id: Ieade491fac2019b8dbbd29ecc89bdb62aab94bbf
parent 34e7507d
Loading
Loading
Loading
Loading
+24 −3
Original line number Diff line number Diff line
@@ -155,6 +155,8 @@ class DesktopTasksController(
                visualIndicator = null
            }
        }
    private val sysUIPackageName = context.resources.getString(
        com.android.internal.R.string.config_systemUi)

    private val transitionAreaHeight
        get() =
@@ -214,6 +216,11 @@ 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)
@@ -349,6 +356,14 @@ class DesktopTasksController(
            )
            return
        }
        if (isSystemUIApplication(task)) {
            KtProtoLog.w(
                WM_SHELL_DESKTOP_MODE,
                "DesktopTasksController: Cannot enter desktop, " +
                        "systemUI top activity found."
            )
            return
        }
        KtProtoLog.v(
            WM_SHELL_DESKTOP_MODE,
            "DesktopTasksController: moveToDesktop taskId=%d",
@@ -896,7 +911,9 @@ class DesktopTasksController(
                when {
                    request.type == TRANSIT_TO_BACK -> handleBackNavigation(task)
                    // Check if the task has a top transparent activity
                    shouldLaunchAsModal(task) -> handleTransparentTaskLaunch(task)
                    shouldLaunchAsModal(task) -> handleIncompatibleTaskLaunch(task)
                    // Check if the task has a top systemUI activity
                    isSystemUIApplication(task) -> handleIncompatibleTaskLaunch(task)
                    // Check if fullscreen task should be updated
                    task.isFullscreen -> handleFullscreenTaskLaunch(task, transition)
                    // Check if freeform task should be updated
@@ -930,6 +947,7 @@ class DesktopTasksController(
            .forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) }
    }

    // TODO(b/347289970): Consider replacing with API
    private fun shouldLaunchAsModal(task: TaskInfo) =
        Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)

@@ -996,8 +1014,11 @@ class DesktopTasksController(
        return null
    }

    // Always launch transparent tasks in fullscreen.
    private fun handleTransparentTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? {
    /**
     * If a task is not compatible with desktop mode freeform, it should always be launched in
     * fullscreen.
     */
    private fun handleIncompatibleTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? {
        // Already fullscreen, no-op.
        if (task.isFullscreen) return null
        return WindowContainerTransaction().also { wct -> addMoveToFullscreenChanges(wct, task) }
+16 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionReg
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;

import java.io.PrintWriter;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;

@@ -152,6 +153,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
    private final DisplayInsetsController mDisplayInsetsController;
    private final Region mExclusionRegion = Region.obtain();
    private boolean mInImmersiveMode;
    private final String mSysUIPackageName;

    private final ISystemGestureExclusionListener mGestureExclusionListener =
            new ISystemGestureExclusionListener.Stub() {
@@ -247,6 +249,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
        mInputManager = mContext.getSystemService(InputManager.class);
        mWindowDecorByTaskId = windowDecorByTaskId;
        mSysUIPackageName = mContext.getResources().getString(
                com.android.internal.R.string.config_systemUi);

        shellInit.addInitCallback(this::onInit, this);
    }
@@ -1035,10 +1039,14 @@ 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)) {
            return false;
        }
        return DesktopModeStatus.canEnterDesktopMode(mContext)
                && !DesktopWallpaperActivity.isWallpaperTask(taskInfo)
                && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
@@ -1109,6 +1117,14 @@ 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");
+32 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.content.ComponentName
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.ActivityInfo.CONFIG_DENSITY
@@ -667,6 +668,20 @@ class DesktopTasksControllerTest : ShellTestCase() {
    verifyEnterDesktopWCTNotExecuted()
  }

  @Test
  fun moveToDesktop_systemUIActivity_doesNothing() {
    val task = setUpFullscreenTask()

    // Set task as systemUI package
    val systemUIPackageName = context.resources.getString(
      com.android.internal.R.string.config_systemUi)
    val baseComponent = ComponentName(systemUIPackageName, /* class */ "")
    task.baseActivity = baseComponent

    controller.moveToDesktop(task, transitionSource = UNKNOWN)
    verifyEnterDesktopWCTNotExecuted()
  }

  @Test
  fun moveToDesktop_deviceSupported_taskIsMovedToDesktop() {
    val task = setUpFullscreenTask()
@@ -1169,6 +1184,21 @@ class DesktopTasksControllerTest : ShellTestCase() {
        .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
  }

  @Test
  fun handleRequest_systemUIActivity_returnSwitchToFullscreenWCT() {
    val task = setUpFreeformTask()

    // Set task as systemUI package
    val systemUIPackageName = context.resources.getString(
      com.android.internal.R.string.config_systemUi)
    val baseComponent = ComponentName(systemUIPackageName, /* class */ "")
    task.baseActivity = baseComponent

    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_WALLPAPER_ACTIVITY)
  fun handleRequest_backTransition_singleActiveTask_noToken() {
@@ -1581,6 +1611,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
      bounds: Rect? = null
  ): RunningTaskInfo {
    val task = createFreeformTask(displayId, bounds)
    val activityInfo = ActivityInfo()
    task.topActivityInfo = activityInfo
    whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
    desktopModeTaskRepository.addActiveTask(displayId, task.taskId)
    desktopModeTaskRepository.addOrMoveFreeformTaskToTop(displayId, task.taskId)
+22 −2
Original line number Diff line number Diff line
@@ -22,7 +22,9 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.content.ComponentName
import android.content.Context
import android.content.pm.ActivityInfo
import android.graphics.Rect
import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
@@ -341,7 +343,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
    }

    @Test
    fun testDescorationIsNotCreatedForTopTranslucentActivities() {
    fun testDecorationIsNotCreatedForTopTranslucentActivities() {
        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply {
            isTopActivityTransparent = true
@@ -353,6 +355,22 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
    }

    @Test
    fun testDecorationIsNotCreatedForSystemUIActivities() {
        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true)

        // Set task as systemUI package
        val systemUIPackageName = context.resources.getString(
            com.android.internal.R.string.config_systemUi)
        val baseComponent = ComponentName(systemUIPackageName, /* class */ "")
        task.baseActivity = baseComponent

        onTaskOpening(task)

        verify(mockDesktopModeWindowDecorFactory, never())
                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_IMMERSIVE_HANDLE_HIDING)
    fun testRelayoutRunsWhenStatusBarsInsetsSourceVisibilityChanges() {
@@ -522,7 +540,8 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
            displayId: Int = DEFAULT_DISPLAY,
            @WindowConfiguration.WindowingMode windowingMode: Int,
            activityType: Int = ACTIVITY_TYPE_STANDARD,
            focused: Boolean = true
            focused: Boolean = true,
            activityInfo: ActivityInfo = ActivityInfo()
    ): RunningTaskInfo {
        return TestRunningTaskInfoBuilder()
                .setDisplayId(displayId)
@@ -530,6 +549,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
                .setVisible(true)
                .setActivityType(activityType)
                .build().apply {
                    topActivityInfo = activityInfo
                    isFocused = focused
                }
    }