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

Commit d1eecd56 authored by Eric Lin's avatar Eric Lin
Browse files

Support bubble to fullscreen in onTaskMovedToFront.

This change modifies BubbleTaskStackListener to correctly handle
scenarios where a bubbled application, currently in a collapsed state,
is moved to the front and its windowing mode becomes fullscreen.

Previously, when a bubbled app's task moved to the front and entered
fullscreen (e.g., via a launcher shortcut), the bubble would not
properly transition to a fullscreen state. This fix addresses that by
invoking moveCollapsedInStackBubbleToFullscreen within the
onTaskMovedToFront callback. This ensures that the bubble is correctly
dissolved and the app is displayed in fullscreen, providing a seamless
user experience.

Bug: 389810202
Flag: EXEMPT bug fix
Test: atest WMShellRobolectricTests:BubbleTaskStackListenerTest
Test: atest WMShellMultivalentTestsOnDevice:BubbleTaskStackListenerTest
Change-Id: I62e03136f32ba7d29f363ddd4ae895091c4753e3
parent c5c576fb
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -195,4 +195,29 @@ class BubbleTaskStackListenerTest {
        verifyNoInteractions(taskOrganizer)
        verifyNoInteractions(taskViewTaskController)
    }

    @Test
    @EnableFlags(
        FLAG_ENABLE_CREATE_ANY_BUBBLE,
        FLAG_ENABLE_BUBBLE_ANYTHING,
        FLAG_EXCLUDE_TASK_FROM_RECENTS,
        FLAG_ENABLE_BUBBLE_APP_COMPAT_FIXES,
    )
    fun onTaskMovedToFront_inStackAppBubbleToFullscreen_notifiesTaskRemoval() {
        task.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
        bubbleData.stub {
            on { getBubbleInStackWithTaskId(bubbleTaskId) } doReturn bubble
        }

        bubbleTaskStackListener.onTaskMovedToFront(task)

        val taskViewTaskController = bubble.taskView.controller
        val taskOrganizer = taskViewTaskController.taskOrganizer
        val wct = argumentCaptor<WindowContainerTransaction>().let { wctCaptor ->
            verify(taskOrganizer).applyTransaction(wctCaptor.capture())
            wctCaptor.lastValue
        }
        verifyExitBubbleTransaction(wct, bubbleTaskToken.asBinder())
        verify(taskViewTaskController).notifyTaskRemovalStarted(task)
    }
}
+20 −18
Original line number Diff line number Diff line
@@ -34,11 +34,12 @@ import dagger.Lazy
import java.util.Optional

/**
 * Listens for task stack changes and handles bubble interactions when activities are restarted.
 * Listens for task stack changes to manage associated bubble interactions.
 *
 * This class monitors task stack events to determine how bubbles should behave when their
 * associated activities are restarted. It handles scenarios where bubbles should be expanded
 * or moved to fullscreen based on the task's windowing mode.
 * This class monitors task stack events, including task restarts and movements to the front,
 * to determine how bubbles should behave. It handles scenarios where bubbles should be expanded
 * or moved to fullscreen based on the task's windowing mode. This includes skipping split
 * task restarts, as they are handled by the split screen controller.
 *
 * @property bubbleController The [BubbleController] to manage bubble promotions and expansions.
 * @property bubbleData The [BubbleData] to access and update bubble information.
@@ -55,11 +56,11 @@ class BubbleTaskStackListener(
        clearedTask: Boolean,
        wasVisible: Boolean,
    ) {
        val taskId = task.taskId
        ProtoLog.d(
            WM_SHELL_BUBBLES_NOISY,
            "BubbleTaskStackListener.onActivityRestartAttempt(): taskId=%d",
            task.taskId)
        val taskId = task.taskId
            taskId)
        bubbleData.getBubbleInStackWithTaskId(taskId)?.let { bubble ->
            when {
                isBubbleToFullscreen(task) -> moveCollapsedInStackBubbleToFullscreen(bubble, task)
@@ -69,6 +70,19 @@ class BubbleTaskStackListener(
        }
    }

    override fun onTaskMovedToFront(task: ActivityManager.RunningTaskInfo) {
        val taskId = task.taskId
        ProtoLog.d(
            WM_SHELL_BUBBLES_NOISY,
            "BubbleTaskStackListener.onTaskMovedToFront(): taskId=%d",
            taskId)
        bubbleData.getBubbleInStackWithTaskId(taskId)?.let { bubble ->
            when {
                isBubbleToFullscreen(task) -> moveCollapsedInStackBubbleToFullscreen(bubble, task)
            }
        }
    }

    private fun isBubbleToSplit(task: ActivityManager.RunningTaskInfo): Boolean {
        return task.hasParentTask() && splitScreenController.get()
            .map { it.isTaskRootOrStageRoot(task.parentTaskId) }
@@ -112,18 +126,6 @@ class BubbleTaskStackListener(
            task.taskId,
            bubble.key
        )
        collapsedBubbleToFullscreenInternal(bubble, task)
    }

    /** Internal function to move a collapsed bubble to fullscreen task. */
    private fun collapsedBubbleToFullscreenInternal(
        bubble: Bubble,
        task: ActivityManager.RunningTaskInfo,
    ) {
        ProtoLog.d(
            WM_SHELL_BUBBLES_NOISY,
            "BubbleTaskStackListener.collapsedBubbleToFullscreenInternal(): taskId=%d",
            task.taskId)
        val taskViewTaskController: TaskViewTaskController = bubble.taskView.controller
        val taskOrganizer: ShellTaskOrganizer = taskViewTaskController.taskOrganizer

+3 −1
Original line number Diff line number Diff line
@@ -75,7 +75,9 @@ object BubbleTestUtils {
    /** Verifies the [WindowContainerTransaction] to exit Bubble. */
    @JvmStatic
    fun verifyExitBubbleTransaction(
        wct: WindowContainerTransaction, taskToken: IBinder, captionInsetsOwner: IBinder?
        wct: WindowContainerTransaction,
        taskToken: IBinder,
        captionInsetsOwner: IBinder? = null,
    ) {
        // Verify hierarchy ops