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

Commit ec7b916a authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Do not trigger IME task move on caption hold." into main

parents f5ecee2e c4bff889
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -1811,6 +1811,7 @@ public abstract class WMShellModule {
            Optional<DesktopUserRepositories> desktopUserRepositories,
            FocusTransitionObserver focusTransitionObserver,
            DisplayImeController displayImeController,
            Optional<DesktopModeWindowDecorViewModel> desktopModeWindowDecorViewModel,
            DisplayController displayController,
            ShellTaskOrganizer shellTaskOrganizer,
            Transitions transitions,
@@ -1825,7 +1826,8 @@ public abstract class WMShellModule {
        return Optional.of(
                new DesktopImeHandler(desktopTasksController.get(), desktopUserRepositories.get(),
                        focusTransitionObserver, shellTaskOrganizer,
                        displayImeController, displayController, transitions, mainExecutor,
                        displayImeController, desktopModeWindowDecorViewModel, displayController,
                        transitions, mainExecutor,
                        animExecutor, context, shellInit));
    }

+28 −3
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ import com.android.wm.shell.shared.animation.WindowAnimator
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.FocusTransitionObserver
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel
import java.util.Optional

/** Handles the interactions between IME and desktop tasks */
class DesktopImeHandler(
@@ -48,13 +50,17 @@ class DesktopImeHandler(
    private val focusTransitionObserver: FocusTransitionObserver,
    private val shellTaskOrganizer: ShellTaskOrganizer,
    private val displayImeController: DisplayImeController,
    private val desktopModeWindowDecorViewModel: Optional<DesktopModeWindowDecorViewModel>,
    private val displayController: DisplayController,
    private val transitions: Transitions,
    private val mainExecutor: ShellExecutor,
    private val animExecutor: ShellExecutor,
    private val context: Context,
    shellInit: ShellInit,
) : DisplayImeController.ImePositionProcessor, Transitions.TransitionHandler {
) :
    DisplayImeController.ImePositionProcessor,
    Transitions.TransitionHandler,
    DesktopModeWindowDecorViewModel.CaptionTouchStatusListener {

    init {
        shellInit.addInitCallback(::onInit, this)
@@ -63,11 +69,16 @@ class DesktopImeHandler(
    private fun onInit() {
        if (DesktopExperienceFlags.ENABLE_DESKTOP_IME_BUGFIX.isTrue()) {
            displayImeController.addPositionProcessor(this)
            desktopModeWindowDecorViewModel.ifPresent { it ->
                it.registerCaptionTouchStatusListener(this)
            }
        }
    }

    private val taskToImeTarget = mutableMapOf<Int, ImeTarget>()
    private var imeTriggeredTransition: IBinder? = null
    /** Responsible for tracking whether app header (not app handle) is pressed. */
    private var isCaptionPressed: Boolean = false

    data class ImeTarget(
        var topTask: ActivityManager.RunningTaskInfo,
@@ -87,9 +98,15 @@ class DesktopImeHandler(
            return IME_ANIMATION_DEFAULT
        }

        if (showing) {
        // Only get the top task when the IME will be showing. Otherwise just restore
        // previously manipulated task.
        if (showing) {
            // If user is still pressing the caption, we shouldn't move the task.
            if (isCaptionPressed) {
                logD("Caption is pressed, do not move task with IME")
                return IME_ANIMATION_DEFAULT
            }

            val currentTopTask = getFocusedTask(displayId) ?: return IME_ANIMATION_DEFAULT
            if (!userRepositories.current.isActiveTask(currentTopTask.taskId))
                return IME_ANIMATION_DEFAULT
@@ -265,6 +282,14 @@ class DesktopImeHandler(
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
    }

    override fun onCaptionPressed() {
        isCaptionPressed = true
    }

    override fun onCaptionReleased() {
        isCaptionPressed = false
    }

    private companion object {
        private const val TAG = "DesktopImeHandler"
        // NOTE: All these constants came from InsetsController.
+30 −0
Original line number Diff line number Diff line
@@ -267,6 +267,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
    private final LatencyTracker mLatencyTracker;
    private final CompatUIHandler mCompatUI;
    private final UserProfileContexts mUserProfileContexts;
    private CaptionTouchStatusListener mCaptionTouchStatusListener;

    public DesktopModeWindowDecorViewModel(
            Context context,
@@ -1055,6 +1056,18 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
        mDesktopTilingDecorViewModel.onDeskRemoved(deskId);
    }

    /** Registers a {@link CaptionTouchStatusListener}. */
    public void registerCaptionTouchStatusListener(CaptionTouchStatusListener l) {
        mCaptionTouchStatusListener = l;
    }

    /** Listener for caption touch events. */
    public interface CaptionTouchStatusListener {
        /** Called when the caption is pressed. */
        void onCaptionPressed();
        /** Called when the caption is released. */
        void onCaptionReleased();
    }
    @VisibleForTesting
    public class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
            implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
@@ -1395,6 +1408,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,

        private boolean handleFreeformMotionEvent(WindowDecorationWrapper decoration,
                RunningTaskInfo taskInfo, View v, MotionEvent e) {
            updateTouchStatus(e);
            final int id = v.getId();
            if (mGestureDetector.onTouchEvent(e)) {
                return true;
@@ -1543,6 +1557,22 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
            }
        }

        private void updateTouchStatus(MotionEvent e) {
            if (mCaptionTouchStatusListener == null) {
                return;
            }
            switch (e.getActionMasked()) {
                case MotionEvent.ACTION_DOWN:
                    mCaptionTouchStatusListener.onCaptionPressed();
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL: {
                    mCaptionTouchStatusListener.onCaptionReleased();
                    break;
                }
            }
        }

        /**
         * Perform a task size toggle on release of the double-tap, assuming no drag event
         * was handled during the double-tap.
+67 −0
Original line number Diff line number Diff line
@@ -40,7 +40,9 @@ import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.FocusTransitionObserver
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel
import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlin.test.Test
import org.junit.Before
import org.mockito.ArgumentCaptor
@@ -69,6 +71,7 @@ class DesktopImeHandlerTest : ShellTestCase() {
    private val focusTransitionObserver = mock<FocusTransitionObserver>()
    private val desktopUserRepositories = mock<DesktopUserRepositories>()
    private val tasksRepository = mock<DesktopRepository>()
    private val desktopModeWindowDecorViewModel = mock<DesktopModeWindowDecorViewModel>()

    private lateinit var imeHandler: DesktopImeHandler
    private lateinit var shellInit: ShellInit
@@ -89,6 +92,7 @@ class DesktopImeHandlerTest : ShellTestCase() {
                focusTransitionObserver,
                shellTaskOrganizer,
                displayImeController,
                Optional.of(desktopModeWindowDecorViewModel),
                displayController,
                transitions,
                mainExecutor = mock(),
@@ -290,6 +294,69 @@ class DesktopImeHandlerTest : ShellTestCase() {
        verify(transitions, never()).startTransition(eq(TRANSIT_CHANGE), wct.capture(), anyOrNull())
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_IME_BUGFIX)
    @DisableFlags(Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS)
    fun onImeStartPositioning_captionPressed_noOp() {
        setUpLandscapeDisplay()
        val wct = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
        val taskBounds = Rect(0, 400, 500, 1600)
        var freeformTask = createFreeformTask(DEFAULT_DISPLAY, taskBounds)
        freeformTask.isFocused = true
        whenever(shellTaskOrganizer.getRunningTasks(any())).thenReturn(arrayListOf(freeformTask))
        whenever(shellTaskOrganizer.getRunningTaskInfo(freeformTask.taskId))
            .thenReturn(freeformTask)

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

        // No transition is started because the IME is floating
        verify(transitions, never()).startTransition(eq(TRANSIT_CHANGE), wct.capture(), anyOrNull())
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_IME_BUGFIX)
    @DisableFlags(Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS)
    fun onImeStartPositioning_captionPressedAndReleased_movesTask() {
        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(shellTaskOrganizer.getRunningTasks(any())).thenReturn(arrayListOf(freeformTask))
        whenever(shellTaskOrganizer.getRunningTaskInfo(freeformTask.taskId))
            .thenReturn(freeformTask)

        imeHandler.onCaptionPressed()
        imeHandler.onCaptionReleased()
        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)
    }

    @Test
    @EnableFlags(
        Flags.FLAG_ENABLE_DESKTOP_IME_BUGFIX,