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

Commit 75e8c4d0 authored by Nick Chameyev's avatar Nick Chameyev
Browse files

Do not no-op fold/unfold Shell transitions

Adds TRANSIT_FLAG_DISPLAY_LEVEL_TRANSITION flag to
display update transitions to ensure that we don't
miss DisplayInfo updates if there is already a
collecting (but not started) display transition.

Fixes: 416768740
Flag: EXEMPT bugfix
Test: atest TransitionTests
Test: atest DisplayContentDeferredUpdateTests
Change-Id: Idcd853f1f73527626869984e0647e4513da6c55d
parent dbdd0c46
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.wm;

import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_FLAG_DISPLAY_LEVEL_TRANSITION;

import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN;
import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
@@ -192,7 +193,8 @@ class DeferredDisplayUpdater {
    private void requestDisplayChangeTransition(boolean physicalDisplayUpdated,
            @NonNull Runnable onStartCollect) {

        final Transition transition = new Transition(TRANSIT_CHANGE, /* flags= */ 0,
        final Transition transition = new Transition(TRANSIT_CHANGE,
                /* flags= */ TRANSIT_FLAG_DISPLAY_LEVEL_TRANSITION,
                mDisplayContent.mTransitionController,
                mDisplayContent.mTransitionController.mSyncEngine);

+14 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.wm;

import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_FLAG_DISPLAY_LEVEL_TRANSITION;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -237,6 +238,19 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase {
        verify(mScreenUnblocker).sendToTarget();
    }

    @Test
    public void testDisplaySwitching_requestsTransitionWithDisplayLevelFlag() {
        mDisplayContent.mDisplayUpdater.onDisplaySwitching(/* switching= */ true);
        mUniqueId = "new";

        mDisplayContent.requestDisplayUpdate(mock(Runnable.class));

        captureStartTransitionCollection().getValue().onCollectStarted(/* deferred= */ true);
        final Transition transition = captureRequestedTransition().getValue();
        assertThat(transition.getFlags() & TRANSIT_FLAG_DISPLAY_LEVEL_TRANSITION)
                .isNotEqualTo(0);
    }

    @Test
    public void testWaitForTransition_displayNotSwitching_doesNotWait() {
        mDisplayContent.mDisplayUpdater.onDisplaySwitching(/* switching= */ false);
+139 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_DISPLAY_LEVEL_TRANSITION;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
@@ -52,6 +53,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;

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

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -72,6 +75,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import static java.lang.Integer.MAX_VALUE;

@@ -99,12 +103,15 @@ import android.window.SystemPerformanceHinter;
import android.window.TaskFragmentAnimationParams;
import android.window.TaskFragmentOrganizer;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo.DisplayChange;

import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;

import com.android.internal.graphics.ColorUtils;
import com.android.server.wm.TransitionController.OnStartCollect;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -2984,6 +2991,138 @@ public class TransitionTests extends WindowTestsBase {
        verify(session[0]).close();
    }

    @Test
    public void testDisplayTransitionCollectingNotStarted_queuedNonDisplayTransitionWillBeNoOp() {
        final TransitionController controller = mDisplayContent.mTransitionController;
        final TestTransitionPlayer player = registerTestTransitionPlayer();

        final Transition displayTransition = createTestTransition(TRANSIT_CHANGE, controller);
        controller.moveToCollecting(displayTransition);
        displayTransition.collect(mDefaultDisplay);

        final OnStartCollect openAppCollectStartedCallback = mock(OnStartCollect.class);
        final Transition queuedTransition = createTestTransition(TRANSIT_OPEN, controller);
        controller.startCollectOrQueue(queuedTransition, openAppCollectStartedCallback);

        // Finish display transition
        controller.requestStartTransition(displayTransition, /* startTask= */ null,
                /* remoteTransition= */ null,
                /* displayChange= */ new DisplayChange(mDefaultDisplay.mDisplayId));
        player.start();
        player.finish();
        waitHandlerIdle(mWm.mAtmService.mH);

        // Verify that the queued transition is not collected and force played
        verify(openAppCollectStartedCallback, never()).onCollectStarted(anyBoolean());
        assertThat(queuedTransition.isForcePlaying()).isTrue();
    }

    @Test
    public void testDisplayTransitionCollectingStarted_queuedNonDisplayTransitionWillNotBeNoOp() {
        final TransitionController controller = mDisplayContent.mTransitionController;
        final TestTransitionPlayer player = registerTestTransitionPlayer();

        final Transition displayTransition = createTestTransition(TRANSIT_CHANGE, controller);
        controller.moveToCollecting(displayTransition);
        displayTransition.collect(mDefaultDisplay);

        // Start the display transition
        controller.requestStartTransition(displayTransition, /* startTask= */ null,
                /* remoteTransition= */ null,
                /* displayChange= */ new DisplayChange(mDefaultDisplay.mDisplayId));
        player.start();

        final OnStartCollect openAppCollectStartedCallback = mock(OnStartCollect.class);
        final Transition queuedTransition = createTestTransition(TRANSIT_OPEN, controller);
        controller.startCollectOrQueue(queuedTransition, openAppCollectStartedCallback);

        // Finish the display transition
        player.finish();
        waitHandlerIdle(mWm.mAtmService.mH);

        // Verify that the queued transition is collected and not force played
        verify(openAppCollectStartedCallback).onCollectStarted(anyBoolean());
        assertThat(queuedTransition.isForcePlaying()).isFalse();
    }

    @Test
    public void testDisplayTransitionCollectingNotStarted_queuedDisplayTransitionWillNotBeNoOp() {
        final TransitionController controller = mDisplayContent.mTransitionController;
        final TestTransitionPlayer player = registerTestTransitionPlayer();

        final Transition displayTransition = createTestTransition(TRANSIT_CHANGE, controller);
        controller.moveToCollecting(displayTransition);
        displayTransition.collect(mDefaultDisplay);

        final OnStartCollect queuedTransitionStartedCallback = mock(OnStartCollect.class);
        final Transition queuedTransition = createTestTransition(TRANSIT_CHANGE, controller);
        queuedTransition.addFlag(TRANSIT_FLAG_DISPLAY_LEVEL_TRANSITION);
        controller.startCollectOrQueue(queuedTransition, queuedTransitionStartedCallback);

        // Finish display transition
        controller.requestStartTransition(displayTransition, /* startTask= */ null,
                /* remoteTransition= */ null,
                /* displayChange= */ new DisplayChange(mDefaultDisplay.mDisplayId));
        player.start();
        player.finish();
        waitHandlerIdle(mWm.mAtmService.mH);

        // Verify that the queued transition is collected and not force played
        verify(queuedTransitionStartedCallback).onCollectStarted(anyBoolean());
        assertThat(queuedTransition.isForcePlaying()).isFalse();
    }

    @Test
    public void testNonDisplayTransitionCollectingNotStarted_queuedDisplayTransitionWillNotBeNoOp() {
        final TransitionController controller = mDisplayContent.mTransitionController;
        final TestTransitionPlayer player = registerTestTransitionPlayer();

        final Transition nonDisplayTransition = createTestTransition(TRANSIT_OPEN, controller);
        controller.moveToCollecting(nonDisplayTransition);

        final OnStartCollect queuedTransitionStartedCallback = mock(OnStartCollect.class);
        final Transition queuedTransition = createTestTransition(TRANSIT_CHANGE, controller);
        queuedTransition.addFlag(TRANSIT_FLAG_DISPLAY_LEVEL_TRANSITION);
        controller.startCollectOrQueue(queuedTransition, queuedTransitionStartedCallback);

        // Finish non-display transition
        controller.requestStartTransition(nonDisplayTransition, /* startTask= */ null,
                /* remoteTransition= */ null, /* displayChange= */ null);
        player.start();
        player.finish();
        waitHandlerIdle(mWm.mAtmService.mH);

        // Verify that the queued transition is collected and not force played
        verify(queuedTransitionStartedCallback).onCollectStarted(anyBoolean());
        assertThat(queuedTransition.isCollecting()).isTrue();
        assertThat(queuedTransition.isForcePlaying()).isFalse();
    }

    @Test
    public void testNonDisplayTransitionCollectingNotStarted_queuedNonDisplayTransitionWillNotBeNoOp() {
        final TransitionController controller = mDisplayContent.mTransitionController;
        final TestTransitionPlayer player = registerTestTransitionPlayer();

        final Transition nonDisplayTransition = createTestTransition(TRANSIT_OPEN, controller);
        controller.moveToCollecting(nonDisplayTransition);

        final OnStartCollect queuedTransitionStartedCallback = mock(OnStartCollect.class);
        final Transition queuedTransition = createTestTransition(TRANSIT_OPEN, controller);
        controller.startCollectOrQueue(queuedTransition, queuedTransitionStartedCallback);

        // Finish the first transition
        controller.requestStartTransition(nonDisplayTransition, /* startTask= */ null,
                /* remoteTransition= */ null, /* displayChange= */ null);
        player.start();
        player.finish();
        waitHandlerIdle(mWm.mAtmService.mH);

        // Verify that the queued transition is collected and not force played
        verify(queuedTransitionStartedCallback).onCollectStarted(anyBoolean());
        assertThat(queuedTransition.isCollecting()).isTrue();
        assertThat(queuedTransition.isForcePlaying()).isFalse();
    }

    @Test
    public void testConfigAtEnd() {
        final TransitionController controller = mDisplayContent.mTransitionController;