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

Commit 96078978 authored by Jorge Gil's avatar Jorge Gil Committed by Android (Google) Code Review
Browse files

Merge "Block relayout during Recents transition" into main

parents 380befbb c1a30723
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -205,6 +205,7 @@ public abstract class WMShellModule {
            SyncTransactionQueue syncQueue,
            Transitions transitions,
            Optional<DesktopTasksController> desktopTasksController,
            RecentsTransitionHandler recentsTransitionHandler,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
        if (DesktopModeStatus.isEnabled()) {
            return new DesktopModeWindowDecorViewModel(
@@ -218,6 +219,7 @@ public abstract class WMShellModule {
                    syncQueue,
                    transitions,
                    desktopTasksController,
                    recentsTransitionHandler,
                    rootTaskDisplayAreaOrganizer);
        }
        return new CaptionWindowDecorViewModel(
+3 −0
Original line number Diff line number Diff line
@@ -134,6 +134,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
        }
        final IBinder transition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct,
                mixedHandler == null ? this : mixedHandler);
        for (int i = 0; i < mStateListeners.size(); i++) {
            mStateListeners.get(i).onTransitionStarted(transition);
        }
        if (mixer != null) {
            mixer.setRecentsTransition(transition);
        }
+5 −0
Original line number Diff line number Diff line
@@ -16,10 +16,15 @@

package com.android.wm.shell.recents;

import android.os.IBinder;

/** The listener for the events from {@link RecentsTransitionHandler}. */
public interface RecentsTransitionStateListener {

    /** Notifies whether the recents animation is running. */
    default void onAnimationStateChanged(boolean running) {
    }

    /** Notifies that a recents shell transition has started. */
    default void onTransitionStarted(IBinder transition) {}
}
+24 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;

import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
@@ -73,6 +74,8 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.recents.RecentsTransitionHandler;
import com.android.wm.shell.recents.RecentsTransitionStateListener;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.KeyguardChangeListener;
@@ -102,6 +105,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
    private final DisplayController mDisplayController;
    private final SyncTransactionQueue mSyncQueue;
    private final Optional<DesktopTasksController> mDesktopTasksController;
    private final RecentsTransitionHandler mRecentsTransitionHandler;
    private boolean mTransitionDragActive;

    private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>();
@@ -135,6 +139,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
            SyncTransactionQueue syncQueue,
            Transitions transitions,
            Optional<DesktopTasksController> desktopTasksController,
            RecentsTransitionHandler recentsTransitionHandler,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer
    ) {
        this(
@@ -148,6 +153,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                syncQueue,
                transitions,
                desktopTasksController,
                recentsTransitionHandler,
                new DesktopModeWindowDecoration.Factory(),
                new InputMonitorFactory(),
                SurfaceControl.Transaction::new,
@@ -167,6 +173,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
            SyncTransactionQueue syncQueue,
            Transitions transitions,
            Optional<DesktopTasksController> desktopTasksController,
            RecentsTransitionHandler recentsTransitionHandler,
            DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
            InputMonitorFactory inputMonitorFactory,
            Supplier<SurfaceControl.Transaction> transactionFactory,
@@ -182,6 +189,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        mSyncQueue = syncQueue;
        mTransitions = transitions;
        mDesktopTasksController = desktopTasksController;
        mRecentsTransitionHandler = recentsTransitionHandler;

        mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory;
        mInputMonitorFactory = inputMonitorFactory;
@@ -194,6 +202,12 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {

    private void onInit() {
        mShellController.addKeyguardChangeListener(mDesktopModeKeyguardChangeListener);
        mRecentsTransitionHandler.addTransitionStateListener(new RecentsTransitionStateListener() {
            @Override
            public void onTransitionStarted(IBinder transition) {
                onRecentsTransitionStarted(transition);
            }
        });
    }

    @Override
@@ -319,6 +333,16 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        }
    }

    private void onRecentsTransitionStarted(IBinder transition) {
        // Block relayout on window decorations originating from #onTaskInfoChanges until the
        // animation completes to avoid interfering with the transition animation.
        for (int i = 0; i < mWindowDecorByTaskId.size(); i++) {
            final DesktopModeWindowDecoration decor = mWindowDecorByTaskId.valueAt(i);
            decor.incrementRelayoutBlock();
            decor.addTransitionPausingRelayout(transition);
        }
    }

    private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
            implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
            DragDetector.MotionEventHandler{
+44 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;

import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -38,6 +39,7 @@ import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.view.Choreographer;
import android.view.Display;
@@ -54,14 +56,18 @@ import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.recents.RecentsTransitionHandler;
import com.android.wm.shell.recents.RecentsTransitionStateListener;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;

import java.util.ArrayList;
@@ -96,18 +102,21 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
    @Mock private SurfaceControl.Transaction mTransaction;
    @Mock private Display mDisplay;
    @Mock private ShellController mShellController;
    @Mock private ShellInit mShellInit;
    @Mock private ShellExecutor mShellExecutor;
    @Mock private DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
            mDesktopModeKeyguardChangeListener;
    @Mock private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
    @Mock private RecentsTransitionHandler mRecentsTransitionHandler;

    private final List<InputManager> mMockInputManagers = new ArrayList<>();

    private ShellInit mShellInit;
    private DesktopModeWindowDecorViewModel mDesktopModeWindowDecorViewModel;

    @Before
    public void setUp() {
        mMockInputManagers.add(mInputManager);

        mShellInit = new ShellInit(mShellExecutor);
        mDesktopModeWindowDecorViewModel =
                new DesktopModeWindowDecorViewModel(
                        mContext,
@@ -120,6 +129,7 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
                        mSyncQueue,
                        mTransitions,
                        Optional.of(mDesktopTasksController),
                        mRecentsTransitionHandler,
                        mDesktopModeWindowDecorFactory,
                        mMockInputMonitorFactory,
                        mTransactionFactory,
@@ -143,6 +153,8 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {

        mDesktopModeWindowDecoration.mDisplay = mDisplay;
        doReturn(Display.DEFAULT_DISPLAY).when(mDisplay).getDisplayId();

        mShellInit.init();
    }

    @Test
@@ -296,6 +308,36 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
                .create(any(), any(), any(), any(), any(), any(), any(), any(), any());
    }

    @Test
    public void testRelayoutBlockedDuringRecentsTransition() throws Exception {
        final ArgumentCaptor<RecentsTransitionStateListener> recentsCaptor =
                ArgumentCaptor.forClass(RecentsTransitionStateListener.class);
        verify(mRecentsTransitionHandler).addTransitionStateListener(recentsCaptor.capture());

        final IBinder transition = mock(IBinder.class);
        final DesktopModeWindowDecoration decoration = mock(DesktopModeWindowDecoration.class);
        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
        final int taskId = 1;
        final SurfaceControl taskSurface = new SurfaceControl();
        final ActivityManager.RunningTaskInfo taskInfo =
                createTaskInfo(taskId, Display.DEFAULT_DISPLAY, WINDOWING_MODE_FREEFORM);
        doReturn(decoration).when(mDesktopModeWindowDecorFactory)
                .create(any(), any(), any(), eq(taskInfo), eq(taskSurface), any(), any(), any(),
                        any());

        runOnMainThread(() -> {
            // Make sure a window decorations exists first by launching a freeform task.
            mDesktopModeWindowDecorViewModel.onTaskOpening(
                    taskInfo, taskSurface, startT, finishT);
            // Now call back when as a Recents transition starts.
            recentsCaptor.getValue().onTransitionStarted(transition);
        });

        verify(decoration).incrementRelayoutBlock();
        verify(decoration).addTransitionPausingRelayout(transition);
    }

    private void runOnMainThread(Runnable r) throws Exception {
        final Handler mainHandler = new Handler(Looper.getMainLooper());
        final CountDownLatch latch = new CountDownLatch(1);