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

Commit ebfc427c authored by Ben Lin's avatar Ben Lin
Browse files

Add a new Recents transition state to signal a stop request.

When a recents animation is on its way to finishing, we want to get a
slightly earlier signal to certain parts (e.g. windowdecor) that it is
going to stop running soon. Instead of only sending a signal when the
transition clean up is happening, we will send another state to notify
that the transition is on its way to be done (e.g. finishInner is
already starting).

Bug: 410838192
Test: atest
Flag: com.android.window.flags.enable_input_layer_transition_fix
Change-Id: Ie183f96cac245c4f859bb74ed51b5d159de51547
parent cec94f25
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_ANIMATING;
import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING;
import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_REQUESTED;
import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_STOP_REQUESTED;
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION;
import static com.android.wm.shell.shared.split.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_END_RECENTS_TRANSITION;
@@ -1556,6 +1557,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
                }
            }

            for (int i = 0; i < mStateListeners.size(); i++) {
                mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_STOP_REQUESTED);
            }

            // Notify the mixers of the pending finish
            for (int i = 0; i < mMixers.size(); ++i) {
                mMixers.get(i).handleFinishRecents(returningToApp, wct, t);
+8 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ public interface RecentsTransitionStateListener {
            TRANSITION_STATE_NOT_RUNNING,
            TRANSITION_STATE_REQUESTED,
            TRANSITION_STATE_ANIMATING,
            TRANSITION_STATE_STOP_REQUESTED,
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface RecentsTransitionState {}
@@ -35,6 +36,7 @@ public interface RecentsTransitionStateListener {
    int TRANSITION_STATE_NOT_RUNNING = 1;
    int TRANSITION_STATE_REQUESTED = 2;
    int TRANSITION_STATE_ANIMATING = 3;
    int TRANSITION_STATE_STOP_REQUESTED = 4;

    /** Notifies whether the recents transition state changes. */
    default void onTransitionStateChanged(@RecentsTransitionState int state) {
@@ -50,12 +52,18 @@ public interface RecentsTransitionStateListener {
        return state >= TRANSITION_STATE_ANIMATING;
    }

    /** Returns whether the recents transition has been requested to stop and is finishing up. */
    static boolean isFinishing(@RecentsTransitionState int state) {
        return state == TRANSITION_STATE_STOP_REQUESTED || state == TRANSITION_STATE_NOT_RUNNING;
    }

    /** Returns a string representation of the given state. */
    static String stateToString(@RecentsTransitionState int state) {
        return switch (state) {
            case TRANSITION_STATE_NOT_RUNNING -> "TRANSITION_STATE_NOT_RUNNING";
            case TRANSITION_STATE_REQUESTED -> "TRANSITION_STATE_REQUESTED";
            case TRANSITION_STATE_ANIMATING -> "TRANSITION_STATE_ANIMATING";
            case TRANSITION_STATE_STOP_REQUESTED -> "TRANSITION_STATE_STOP_REQUESTED";
            default -> "UNKNOWN";
        };
    }
+13 −3
Original line number Diff line number Diff line
@@ -1958,11 +1958,21 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
                        setIsRecentsTransitionRunningForTask(taskId, true);
                    }
                    return;
                case RecentsTransitionStateListener.TRANSITION_STATE_STOP_REQUESTED:
                    if (DesktopModeFlags.ENABLE_INPUT_LAYER_TRANSITION_FIX.isTrue()) {
                        // No Recents transition running - clean up window decorations
                        for (int taskId : mAnimatingTaskIds) {
                            setIsRecentsTransitionRunningForTask(taskId, false);
                        }
                    }
                    return;
                case RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING:
                    if (!DesktopModeFlags.ENABLE_INPUT_LAYER_TRANSITION_FIX.isTrue()) {
                        // No Recents transition running - clean up window decorations
                        for (int taskId : mAnimatingTaskIds) {
                            setIsRecentsTransitionRunningForTask(taskId, false);
                        }
                    }
                    mAnimatingTaskIds.clear();
                    return;
                default:
+21 −12
Original line number Diff line number Diff line
@@ -28,12 +28,14 @@ import static com.android.wm.shell.Flags.FLAG_ENABLE_RECENTS_BOOKEND_TRANSITION;
import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_ANIMATING;
import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING;
import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_REQUESTED;
import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_STOP_REQUESTED;
import static com.android.wm.shell.transition.Transitions.TRANSIT_END_RECENTS_TRANSITION;
import static com.android.wm.shell.transition.Transitions.TRANSIT_START_RECENTS_TRANSITION;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -90,6 +92,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
@@ -219,7 +223,7 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
        startRecentsTransition(/* synthetic= */ false);
        mMainExecutor.flushAll();

        assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_REQUESTED);
        assertThat(listener.getLastProcessedState()).isEqualTo(TRANSITION_STATE_REQUESTED);
    }

    @Test
@@ -233,7 +237,7 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
                mock(Transitions.TransitionFinishCallback.class));
        mMainExecutor.flushAll();

        assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_ANIMATING);
        assertThat(listener.getLastProcessedState()).isEqualTo(TRANSITION_STATE_ANIMATING);
    }

    @Test
@@ -249,7 +253,8 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
                false /* sendUserLeaveHint */, mock(IResultReceiver.class));
        mMainExecutor.flushAll();

        assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
        assertThat(listener.getLastProcessedState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
        assertTrue(listener.didStateGetProcessed(TRANSITION_STATE_STOP_REQUESTED));
    }

    @Test
@@ -261,7 +266,7 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
        mRecentsTransitionHandler.findController(transition).cancel("test");
        mMainExecutor.flushAll();

        assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
        assertThat(listener.getLastProcessedState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
    }

    @Test
@@ -272,7 +277,7 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
        startRecentsTransition(/* synthetic= */ true);
        mMainExecutor.flushAll();

        assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_ANIMATING);
        assertThat(listener.getLastProcessedState()).isEqualTo(TRANSITION_STATE_ANIMATING);
    }

    @Test
@@ -285,7 +290,7 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
                false /* sendUserLeaveHint */, mock(IResultReceiver.class));
        mMainExecutor.flushAll();

        assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
        assertThat(listener.getLastProcessedState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
    }

    @Test
@@ -297,7 +302,7 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
        mRecentsTransitionHandler.findController(transition).cancel("test");
        mMainExecutor.flushAll();

        assertThat(listener.getState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
        assertThat(listener.getLastProcessedState()).isEqualTo(TRANSITION_STATE_NOT_RUNNING);
    }

    @Test
@@ -478,17 +483,21 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
    }

    private static class TestTransitionStateListener implements RecentsTransitionStateListener {
        @RecentsTransitionState
        private int mState = TRANSITION_STATE_NOT_RUNNING;
        private final List<Integer> mProcessedStates =
                new ArrayList<>(TRANSITION_STATE_NOT_RUNNING);

        @Override
        public void onTransitionStateChanged(int state) {
            mState = state;
            mProcessedStates.add(state);
        }

        @RecentsTransitionState
        int getState() {
            return mState;
        int getLastProcessedState() {
            return mProcessedStates.getLast();
        }

        boolean didStateGetProcessed(int state) {
            return mProcessedStates.contains(state);
        }
    }
}
+16 −0
Original line number Diff line number Diff line
@@ -1186,6 +1186,7 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX)
    @DisableFlags(Flags.FLAG_ENABLE_INPUT_LAYER_TRANSITION_FIX)
    fun testRecentsTransitionStateListener_nonRunningState_setsTransitionNotRunning() {
        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
        val decoration = setUpMockDecorationForTask(task)
@@ -1199,6 +1200,21 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest
        verify(decoration).setIsRecentsTransitionRunning(false)
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX, Flags.FLAG_ENABLE_INPUT_LAYER_TRANSITION_FIX)
    fun testRecentsTransitionStateListener_nonRunningState_setsTransitionStopRequested() {
        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
        val decoration = setUpMockDecorationForTask(task)
        onTaskOpening(task, SurfaceControl())
        desktopModeRecentsTransitionStateListener.onTransitionStateChanged(
            RecentsTransitionStateListener.TRANSITION_STATE_REQUESTED)

        desktopModeRecentsTransitionStateListener.onTransitionStateChanged(
            RecentsTransitionStateListener.TRANSITION_STATE_STOP_REQUESTED)

        verify(decoration).setIsRecentsTransitionRunning(false)
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX)
    fun testRecentsTransitionStateListener_requestedAndAnimating_setsTransitionRunningOnce() {