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

Commit 9a742e4e authored by Orhan Uysal's avatar Orhan Uysal
Browse files

If a transition happens, discard IME tasks.

When a transtion happens that affects one of the IME target windows, do
not try to restore the bounds of the windows.

Test: atest DesktopImeHandler

Test: trigger IME in a window, then swipe up to home. See no white
surface of the window.

Bug: 388570293

Flag: com.android.window.flags.enable_desktop_ime_bugfix

Change-Id: Idf58d423cefe72593ad222d2a2884faa1f198960
parent 6227a2b8
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -490,7 +490,8 @@ public abstract class WMShellModule {
            Optional<TaskChangeListener> taskChangeListener,
            FocusTransitionObserver focusTransitionObserver,
            Optional<DesksTransitionObserver> desksTransitionObserver,
            DesktopState desktopState) {
            DesktopState desktopState,
            Optional<DesktopImeHandler> desktopImeHandler) {
        return new FreeformTaskTransitionObserver(
                shellInit,
                transitions,
@@ -499,7 +500,8 @@ public abstract class WMShellModule {
                taskChangeListener,
                focusTransitionObserver,
                desksTransitionObserver,
                desktopState);
                desktopState,
                desktopImeHandler);
    }

    @WMSingleton
+19 −1
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ class DesktopImeHandler(
    }

    private val taskToImeTarget = mutableMapOf<Int, ImeTarget>()
    private var imeTriggeredTransition: IBinder? = null

    data class ImeTarget(
        var topTask: ActivityManager.RunningTaskInfo,
@@ -133,7 +134,7 @@ class DesktopImeHandler(

            logD("Moving task %d due to IME", imeTarget.topTask.taskId)
            val wct = WindowContainerTransaction().setBounds(imeTarget.topTask.token, finalBounds)
            transitions.startTransition(TRANSIT_CHANGE, wct, this)
            imeTriggeredTransition = transitions.startTransition(TRANSIT_CHANGE, wct, this)
            taskToImeTarget[currentTopTask.taskId]?.newBounds = finalBounds
        } else {
            val wct = WindowContainerTransaction()
@@ -144,6 +145,7 @@ class DesktopImeHandler(
                if (task.configuration.windowConfiguration.bounds == imeTarget.newBounds) {
                    val finalBounds = imeTarget.previousBounds ?: return@forEach

                    logD("Restoring task %d due to IME", taskId)
                    // Restore the previous bounds if they exist
                    wct.setBounds(imeTarget.topTask.token, finalBounds)
                }
@@ -164,6 +166,22 @@ class DesktopImeHandler(
            shellTaskOrganizer.getRunningTasks(displayId).find { taskInfo -> taskInfo.isFocused }
        }

    /**
     * If a transition related to a target that we have previously moved up, remove it from the
     * target list so we do not restore its bounds.
     */
    fun onTransitionReady(transition: IBinder, info: TransitionInfo) {
        // Do nothing if we get the callback for IME triggered transition
        if (transition == imeTriggeredTransition || taskToImeTarget.isEmpty()) return

        // If there is a transition targeting the IME targets remove them from the list
        info.changes.forEach { change ->
            if (taskToImeTarget[change.taskInfo?.taskId] != null) {
                taskToImeTarget.remove(change.taskInfo?.taskId)
            }
        }
    }

    override fun startAnimation(
        transition: IBinder,
        info: TransitionInfo,
+8 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.window.WindowContainerToken;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;

import com.android.wm.shell.desktopmode.DesktopImeHandler;
import com.android.wm.shell.desktopmode.DesktopImmersiveController;
import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver;
import com.android.wm.shell.shared.desktopmode.DesktopState;
@@ -56,6 +57,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
    private final Optional<TaskChangeListener> mTaskChangeListener;
    private final FocusTransitionObserver mFocusTransitionObserver;
    private final Optional<DesksTransitionObserver> mDesksTransitionObserver;
    private final Optional<DesktopImeHandler> mDesktopImeHandler;

    private final Map<IBinder, List<ActivityManager.RunningTaskInfo>> mTransitionToTaskInfo =
            new HashMap<>();
@@ -71,13 +73,15 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
            Optional<TaskChangeListener> taskChangeListener,
            FocusTransitionObserver focusTransitionObserver,
            Optional<DesksTransitionObserver> desksTransitionObserver,
            DesktopState desktopState) {
            DesktopState desktopState,
            Optional<DesktopImeHandler> desktopImeHandler) {
        mTransitions = transitions;
        mDesktopImmersiveController = desktopImmersiveController;
        mWindowDecorViewModel = windowDecorViewModel;
        mTaskChangeListener = taskChangeListener;
        mFocusTransitionObserver = focusTransitionObserver;
        mDesksTransitionObserver = desksTransitionObserver;
        mDesktopImeHandler = desktopImeHandler;
        if (FreeformComponents.requiresFreeformComponents(desktopState)) {
            shellInit.addInitCallback(this::onInit, this);
        }
@@ -109,6 +113,9 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
        // TODO(371503964): Remove this once the unified task repository is ready.
        mFocusTransitionObserver.updateFocusState(info);

        // Call after the focus state update to have the correct focused window.
        mDesktopImeHandler.ifPresent(o -> o.onTransitionReady(transition, info));

        final ArrayList<ActivityManager.RunningTaskInfo> taskInfoList = new ArrayList<>();
        final ArrayList<WindowContainerToken> taskParents = new ArrayList<>();
        for (TransitionInfo.Change change : info.getChanges()) {
+73 −0
Original line number Diff line number Diff line
@@ -20,10 +20,14 @@ import android.app.ActivityManager.RunningTaskInfo
import android.app.WindowConfiguration
import android.content.Context
import android.graphics.Rect
import android.os.IBinder
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.Display.DEFAULT_DISPLAY
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_TO_BACK
import android.window.TransitionInfo
import android.window.TransitionInfo.Change
import android.window.WindowContainerTransaction
import com.android.window.flags.Flags
import com.android.wm.shell.ShellTaskOrganizer
@@ -40,6 +44,7 @@ import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import org.junit.Before
import org.mockito.ArgumentCaptor
import org.mockito.Mockito
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.eq
@@ -339,6 +344,62 @@ class DesktopImeHandlerTest : ShellTestCase() {
            .startTransition(eq(TRANSIT_CHANGE), wct.capture(), anyOrNull())
    }

    @Test
    @EnableFlags(
        Flags.FLAG_ENABLE_DESKTOP_IME_BUGFIX,
        Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS,
    )
    fun onImeStartPositioning_newTransitionOnTask_doesNotRestorePreImeBounds() {
        setUpLandscapeDisplay()
        val wct = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
        val taskBounds = Rect(0, 400, 500, 1600)
        val expectedBounds =
            Rect(
                taskBounds.left,
                STATUS_BAR_HEIGHT,
                taskBounds.right,
                STATUS_BAR_HEIGHT + taskBounds.height(),
            )
        var freeformTask = createFreeformTask(DEFAULT_DISPLAY, taskBounds)
        freeformTask.isFocused = true
        whenever(focusTransitionObserver.globallyFocusedTaskId).thenReturn(freeformTask.taskId)
        whenever(shellTaskOrganizer.getRunningTaskInfo(freeformTask.taskId))
            .thenReturn(freeformTask)

        imeHandler.onImeStartPositioning(
            DEFAULT_DISPLAY,
            hiddenTop = DISPLAY_DIMENSION_SHORT,
            shownTop = IME_HEIGHT,
            showing = true,
            isFloating = false,
            t = mock(),
        )

        // Moves the task up to the top of stable bounds
        verify(transitions).startTransition(eq(TRANSIT_CHANGE), wct.capture(), anyOrNull())
        assertThat(findBoundsChange(wct.value, freeformTask)).isEqualTo(expectedBounds)

        // Create a transition that affects the freeform task we modified previously
        imeHandler.onTransitionReady(
            transition = Mockito.mock(IBinder::class.java),
            info = createToBackTransition(freeformTask),
        )

        // This should be no op.
        imeHandler.onImeStartPositioning(
            DEFAULT_DISPLAY,
            hiddenTop = DISPLAY_DIMENSION_SHORT,
            shownTop = IME_HEIGHT,
            showing = false,
            isFloating = false,
            t = mock(),
        )

        // Task is not moved back to original position with a new transition.
        verify(transitions, times(1))
            .startTransition(eq(TRANSIT_CHANGE), wct.capture(), anyOrNull())
    }

    @Test
    @EnableFlags(
        Flags.FLAG_ENABLE_DESKTOP_IME_BUGFIX,
@@ -393,6 +454,18 @@ class DesktopImeHandlerTest : ShellTestCase() {
        }
    }

    private fun createToBackTransition(task: RunningTaskInfo?) =
        TransitionInfo(TRANSIT_TO_BACK, /* flags= */ 0).apply {
            addChange(
                Change(mock(), mock()).apply {
                    mode = TRANSIT_TO_BACK
                    parent = null
                    taskInfo = task
                    flags = flags
                }
            )
        }

    private companion object {
        private const val DISPLAY_DIMENSION_SHORT = 1600
        private const val DISPLAY_DIMENSION_LONG = 2560
+4 −2
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import androidx.test.filters.SmallTest;

import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.desktopmode.DesktopImeHandler;
import com.android.wm.shell.desktopmode.DesktopImmersiveController;
import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver;
import com.android.wm.shell.shared.desktopmode.FakeDesktopState;
@@ -76,8 +77,8 @@ public class FreeformTaskTransitionObserverTest extends ShellTestCase {
    @Mock private TaskChangeListener mTaskChangeListener;
    @Mock private FocusTransitionObserver mFocusTransitionObserver;
    @Mock private DesksTransitionObserver mDesksTransitionObserver;
    @Mock private DesktopImeHandler mDesktopImeHandler;
    private FakeDesktopState mDesktopState;

    private FreeformTaskTransitionObserver mTransitionObserver;
    private AutoCloseable mMocksInits = null;

@@ -102,7 +103,8 @@ public class FreeformTaskTransitionObserverTest extends ShellTestCase {
                        Optional.of(mTaskChangeListener),
                        mFocusTransitionObserver,
                        Optional.of(mDesksTransitionObserver),
                        mDesktopState);
                        mDesktopState,
                        Optional.of(mDesktopImeHandler));

        final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
        verify(mShellInit).addInitCallback(initRunnableCaptor.capture(), same(mTransitionObserver));