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

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

Modify Desktop Windowing incompatible task heuristic

Update heuristic to exclude activities which are not displayed so we
remain in the freeform state.

Flag: com.android.window.flags.enable_desktop_windowing_modals_policy
Test: atest WMShellUnitTests:AppCompatUtilsTest
Test: atest WMShellUnitTests:DesktopTasksControllerTest
Test: atest WMShellUnitTests:DesktopModeWindowDecorViewModelTests
Bug: 364012155
Change-Id: I414fc9977adf0a20f645d39f540299fdcc214588
parent 2ed42dc6
Loading
Loading
Loading
Loading
+10 −10
Original line number Diff line number Diff line
@@ -296,22 +296,22 @@ public class TaskInfo {
    public boolean isVisibleRequested;

    /**
     * Whether this task is sleeping due to sleeping display.
     * Whether the top activity is to be displayed. See {@link android.R.attr#windowNoDisplay}.
     * @hide
     */
    public boolean isSleeping;
    public boolean isTopActivityNoDisplay;

    /**
     * Whether the top activity fillsParent() is false
     * Whether this task is sleeping due to sleeping display.
     * @hide
     */
    public boolean isTopActivityTransparent;
    public boolean isSleeping;

    /**
     * Whether the top activity has specified style floating.
     * Whether the top activity fillsParent() is false
     * @hide
     */
    public boolean isTopActivityStyleFloating;
    public boolean isTopActivityTransparent;

    /**
     * The last non-fullscreen bounds the task was launched in or resized to.
@@ -482,12 +482,12 @@ public class TaskInfo {
                && isFocused == that.isFocused
                && isVisible == that.isVisible
                && isVisibleRequested == that.isVisibleRequested
                && isTopActivityNoDisplay == that.isTopActivityNoDisplay
                && isSleeping == that.isSleeping
                && Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId)
                && parentTaskId == that.parentTaskId
                && Objects.equals(topActivity, that.topActivity)
                && isTopActivityTransparent == that.isTopActivityTransparent
                && isTopActivityStyleFloating == that.isTopActivityStyleFloating
                && Objects.equals(lastNonFullscreenBounds, that.lastNonFullscreenBounds)
                && Objects.equals(capturedLink, that.capturedLink)
                && capturedLinkTimestamp == that.capturedLinkTimestamp
@@ -561,11 +561,11 @@ public class TaskInfo {
        isFocused = source.readBoolean();
        isVisible = source.readBoolean();
        isVisibleRequested = source.readBoolean();
        isTopActivityNoDisplay = source.readBoolean();
        isSleeping = source.readBoolean();
        mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR);
        displayAreaFeatureId = source.readInt();
        isTopActivityTransparent = source.readBoolean();
        isTopActivityStyleFloating = source.readBoolean();
        lastNonFullscreenBounds = source.readTypedObject(Rect.CREATOR);
        capturedLink = source.readTypedObject(Uri.CREATOR);
        capturedLinkTimestamp = source.readLong();
@@ -616,11 +616,11 @@ public class TaskInfo {
        dest.writeBoolean(isFocused);
        dest.writeBoolean(isVisible);
        dest.writeBoolean(isVisibleRequested);
        dest.writeBoolean(isTopActivityNoDisplay);
        dest.writeBoolean(isSleeping);
        dest.writeTypedObject(mTopActivityLocusId, flags);
        dest.writeInt(displayAreaFeatureId);
        dest.writeBoolean(isTopActivityTransparent);
        dest.writeBoolean(isTopActivityStyleFloating);
        dest.writeTypedObject(lastNonFullscreenBounds, flags);
        dest.writeTypedObject(capturedLink, flags);
        dest.writeLong(capturedLinkTimestamp);
@@ -661,11 +661,11 @@ public class TaskInfo {
                + " isFocused=" + isFocused
                + " isVisible=" + isVisible
                + " isVisibleRequested=" + isVisibleRequested
                + " isTopActivityNoDisplay=" + isTopActivityNoDisplay
                + " isSleeping=" + isSleeping
                + " locusId=" + mTopActivityLocusId
                + " displayAreaFeatureId=" + displayAreaFeatureId
                + " isTopActivityTransparent=" + isTopActivityTransparent
                + " isTopActivityStyleFloating=" + isTopActivityStyleFloating
                + " lastNonFullscreenBounds=" + lastNonFullscreenBounds
                + " capturedLink=" + capturedLink
                + " capturedLinkTimestamp=" + capturedLinkTimestamp
+8 −2
Original line number Diff line number Diff line
@@ -23,9 +23,15 @@ import android.content.Context
import com.android.internal.R

// TODO(b/347289970): Consider replacing with API
/**
 * If the top activity should be exempt from desktop windowing and forced back to fullscreen.
 * Currently includes all system ui activities and modal dialogs. However is the top activity is not
 * being displayed, regardless of its configuration, we will not exempt it as to remain in the
 * desktop windowing environment.
 */
fun isTopActivityExemptFromDesktopWindowing(context: Context, task: TaskInfo) =
    isSystemUiTask(context, task) || (task.isTopActivityTransparent && task.numActivities == 1
            && !task.isTopActivityStyleFloating)
    (isSystemUiTask(context, task) || (task.isTopActivityTransparent && task.numActivities == 1))
            && !task.isTopActivityNoDisplay

private fun isSystemUiTask(context: Context, task: TaskInfo): Boolean {
    val sysUiPackageName: String =
+26 −21
Original line number Diff line number Diff line
@@ -43,48 +43,53 @@ class AppCompatUtilsTest : ShellTestCase() {
                    .apply {
                        isTopActivityTransparent = true
                        numActivities = 1
                        isTopActivityNoDisplay = false
                    }))
    }

    @Test
    fun testIsTopActivityExemptFromDesktopWindowing_topActivityTransparent_multipleActivities() {
        assertFalse(isTopActivityExemptFromDesktopWindowing(mContext,
            createFreeformTask(/* displayId */ 0)
                .apply {
                    isTopActivityTransparent = true
                        numActivities = 0
                    numActivities = 2
                    isTopActivityNoDisplay = false
                }))
    }

    @Test
    fun testIsTopActivityExemptFromDesktopWindowing_singleTopActivity() {
        assertTrue(isTopActivityExemptFromDesktopWindowing(mContext,
            createFreeformTask(/* displayId */ 0)
                    .apply {
                        isTopActivityTransparent = true
                        numActivities = 1
                    }))
    fun testIsTopActivityExemptFromDesktopWindowing_topActivityTransparent_notDisplayed() {
        assertFalse(isTopActivityExemptFromDesktopWindowing(mContext,
            createFreeformTask(/* displayId */ 0)
                .apply {
                        isTopActivityTransparent = false
                    isTopActivityTransparent = true
                    numActivities = 1
                    isTopActivityNoDisplay = true
                }))
    }

    @Test
    fun testIsTopActivityExemptFromDesktopWindowing__topActivityStyleFloating() {
        assertFalse(isTopActivityExemptFromDesktopWindowing(mContext,
    fun testIsTopActivityExemptFromDesktopWindowing_systemUiTask() {
        val systemUIPackageName = context.resources.getString(R.string.config_systemUi)
        val baseComponent = ComponentName(systemUIPackageName, /* class */ "")
        assertTrue(isTopActivityExemptFromDesktopWindowing(mContext,
            createFreeformTask(/* displayId */ 0)
                    .apply {
                        isTopActivityStyleFloating = true
                        baseActivity = baseComponent
                        isTopActivityNoDisplay = false
                    }))
    }

    @Test
    fun testIsTopActivityExemptFromDesktopWindowing_systemUiTask() {
    fun testIsTopActivityExemptFromDesktopWindowing_systemUiTask_notDisplayed() {
        val systemUIPackageName = context.resources.getString(R.string.config_systemUi)
        val baseComponent = ComponentName(systemUIPackageName, /* class */ "")
        assertTrue(isTopActivityExemptFromDesktopWindowing(mContext,
        assertFalse(isTopActivityExemptFromDesktopWindowing(mContext,
            createFreeformTask(/* displayId */ 0)
                .apply {
                    baseActivity = baseComponent
                    isTopActivityNoDisplay = true
                }))
    }
}
+65 −15
Original line number Diff line number Diff line
@@ -1123,11 +1123,11 @@ class DesktopTasksControllerTest : ShellTestCase() {

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
  fun moveRunningTaskToDesktop_topActivityTranslucentWithStyleFloating_taskIsMovedToDesktop() {
  fun moveRunningTaskToDesktop_topActivityTranslucentWithoutDisplay_taskIsMovedToDesktop() {
    val task =
      setUpFullscreenTask().apply {
        isTopActivityTransparent = true
        isTopActivityStyleFloating = true
        isTopActivityNoDisplay = true
        numActivities = 1
      }

@@ -1139,11 +1139,11 @@ class DesktopTasksControllerTest : ShellTestCase() {

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
  fun moveRunningTaskToDesktop_topActivityTranslucentWithoutStyleFloating_doesNothing() {
  fun moveRunningTaskToDesktop_topActivityTranslucentWithDisplay_doesNothing() {
    val task =
      setUpFullscreenTask().apply {
        isTopActivityTransparent = true
        isTopActivityStyleFloating = false
        isTopActivityNoDisplay = false
        numActivities = 1
      }

@@ -1153,19 +1153,40 @@ class DesktopTasksControllerTest : ShellTestCase() {

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
  fun moveRunningTaskToDesktop_systemUIActivity_doesNothing() {
    val task = setUpFullscreenTask()

  fun moveRunningTaskToDesktop_systemUIActivityWithDisplay_doesNothing() {
    // 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 task =
      setUpFullscreenTask().apply {
        baseActivity = baseComponent
        isTopActivityNoDisplay = false
      }

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

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
  fun moveRunningTaskToDesktop_systemUIActivityWithoutDisplay_doesNothing() {
    // Set task as systemUI package
    val systemUIPackageName = context.resources.getString(
      com.android.internal.R.string.config_systemUi)
    val baseComponent = ComponentName(systemUIPackageName, /* class */ "")
    val task =
      setUpFullscreenTask().apply {
        baseActivity = baseComponent
        isTopActivityNoDisplay = true
      }

    controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)

    val wct = getLatestEnterDesktopWct()
    assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
  }

  @Test
  fun moveRunningTaskToDesktop_deviceSupported_taskIsMovedToDesktop() {
    val task = setUpFullscreenTask()
@@ -2223,14 +2244,14 @@ class DesktopTasksControllerTest : ShellTestCase() {

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
  fun handleRequest_topActivityTransparentWithStyleFloating_returnSwitchToFreeformWCT() {
  fun handleRequest_topActivityTransparentWithoutDisplay_returnSwitchToFreeformWCT() {
    val freeformTask = setUpFreeformTask()
    markTaskVisible(freeformTask)

    val task =
      setUpFullscreenTask().apply {
        isTopActivityTransparent = true
        isTopActivityStyleFloating = true
        isTopActivityNoDisplay = true
        numActivities = 1
      }

@@ -2241,11 +2262,14 @@ class DesktopTasksControllerTest : ShellTestCase() {

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
  fun handleRequest_topActivityTransparentWithoutStyleFloating_returnSwitchToFullscreenWCT() {
  fun handleRequest_topActivityTransparentWithDisplay_returnSwitchToFullscreenWCT() {
    val freeformTask = setUpFreeformTask()
    markTaskVisible(freeformTask)

    val task =
      setUpFreeformTask().apply {
        isTopActivityTransparent = true
        isTopActivityStyleFloating = false
        isTopActivityNoDisplay = false
        numActivities = 1
      }

@@ -2256,20 +2280,46 @@ class DesktopTasksControllerTest : ShellTestCase() {

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
  fun handleRequest_systemUIActivity_returnSwitchToFullscreenWCT() {
    val task = setUpFreeformTask()
  fun handleRequest_systemUIActivityWithDisplay_returnSwitchToFullscreenWCT() {
    val freeformTask = setUpFreeformTask()
    markTaskVisible(freeformTask)

    // 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 task =
      setUpFreeformTask().apply {
        baseActivity = baseComponent
        isTopActivityNoDisplay = false
      }

    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_systemUIActivityWithoutDisplay_returnSwitchToFreeformWCT() {
    val freeformTask = setUpFreeformTask()
    markTaskVisible(freeformTask)

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

    val result = controller.handleRequest(Binder(), createTransition(task))
    assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode)
      .isEqualTo(WINDOWING_MODE_FREEFORM)
  }

  @Test
  @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,)
  fun handleRequest_backTransition_singleTaskNoToken_noWallpaper_doesNotHandle() {
+6 −20
Original line number Diff line number Diff line
@@ -478,25 +478,10 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
    fun testDecorationIsCreatedForTopTranslucentActivitiesWithStyleFloating() {
    fun testDecorationIsNotCreatedForTopTranslucentActivities() {
        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN).apply {
            isTopActivityTransparent = true
            isTopActivityStyleFloating = true
            numActivities = 1
        }
        doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(any()) }
        setUpMockDecorationsForTasks(task)

        onTaskOpening(task)
        assertTrue(windowDecorByTaskIdSpy.contains(task.taskId))
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
    fun testDecorationIsNotCreatedForTopTranslucentActivitiesWithoutStyleFloating() {
        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN).apply {
            isTopActivityTransparent = true
            isTopActivityStyleFloating = false
            isTopActivityNoDisplay = false
            numActivities = 1
        }
        onTaskOpening(task)
@@ -507,13 +492,14 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
    fun testDecorationIsNotCreatedForSystemUIActivities() {
        val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN)

        // 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 task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN).apply {
            baseActivity = baseComponent
            isTopActivityNoDisplay = false
        }

        onTaskOpening(task)

Loading