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

Commit e9389790 authored by Kazuki Takise's avatar Kazuki Takise Committed by Android (Google) Code Review
Browse files

Merge "Add transition support to presentation" into main

parents 27045609 bfc2dd44
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -56,11 +56,6 @@ class PresentationController {
        ProtoLog.v(WmProtoLogGroups.WM_DEBUG_PRESENTATION, "Presentation added to display %d: %s",
                win.getDisplayId(), win);
        mPresentingDisplayIds.add(win.getDisplayId());
        if (enablePresentationForConnectedDisplays()) {
            // A presentation hides all activities behind on the same display.
            win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null,
                    /*notifyClients=*/ true);
        }
        win.mWmService.mDisplayManagerInternal.onPresentation(displayId, /*isShown=*/ true);
    }

@@ -76,11 +71,6 @@ class PresentationController {
        if (displayIdIndex != -1) {
            mPresentingDisplayIds.remove(displayIdIndex);
        }
        if (enablePresentationForConnectedDisplays()) {
            // A presentation hides all activities behind on the same display.
            win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null,
                    /*notifyClients=*/ true);
        }
        win.mWmService.mDisplayManagerInternal.onPresentation(displayId, /*isShown=*/ false);
    }
}
+23 −2
Original line number Diff line number Diff line
@@ -157,6 +157,7 @@ import static com.android.server.wm.WindowManagerServiceDumpProto.POLICY;
import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER;
import static com.android.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID;
import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions;
import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays;
import static com.android.window.flags.Flags.multiCrop;
import static com.android.window.flags.Flags.setScPropertiesInClient;

@@ -1820,9 +1821,29 @@ public class WindowManagerService extends IWindowManager.Stub
            final boolean hideSystemAlertWindows = shouldHideNonSystemOverlayWindow(win);
            win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);

            // Only a presentation window needs a transition because its visibility affets the
            // lifecycle of apps below (b/390481865).
            if (enablePresentationForConnectedDisplays() && win.isPresentation()) {
                Transition transition = null;
                if (!win.mTransitionController.isCollecting()) {
                    transition = win.mTransitionController.createAndStartCollecting(TRANSIT_OPEN);
                }
                win.mTransitionController.collect(win.mToken);
                res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState,
                        outAttachedFrame, outActiveControls, client, outSizeCompatScale, attrs);
                // A presentation hides all activities behind on the same display.
                win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null,
                        /*notifyClients=*/ true);
                win.mTransitionController.getCollectingTransition().setReady(win.mToken, true);
                if (transition != null) {
                    win.mTransitionController.requestStartTransition(transition, null,
                            null /* remoteTransition */, null /* displayChange */);
                }
            } else {
                res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState,
                        outAttachedFrame, outActiveControls, client, outSizeCompatScale, attrs);
            }
        }

        Binder.restoreCallingIdentity(origId);

+29 −10
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
@@ -182,6 +183,7 @@ import static com.android.server.wm.WindowStateProto.UNRESTRICTED_KEEP_CLEAR_ARE
import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES;
import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays;
import static com.android.window.flags.Flags.surfaceTrustedOverlay;

import android.annotation.CallSuper;
@@ -2297,11 +2299,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
            dc.updateImeInputAndControlTarget(null);
        }

        final int type = mAttrs.type;

        if (isPresentation()) {
            mWmService.mPresentationController.onPresentationRemoved(this);
        }
        // Check if window provides non decor insets before clearing its provided insets.
        final boolean windowProvidesDisplayDecorInsets = providesDisplayDecorInsets();

@@ -2442,11 +2439,33 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                }
            }

            // Only a presentation window needs a transition because its visibility affets the
            // lifecycle of apps below (b/390481865).
            if (enablePresentationForConnectedDisplays() && isPresentation()) {
                Transition transition = null;
                if (!mTransitionController.isCollecting()) {
                    transition = mTransitionController.createAndStartCollecting(TRANSIT_CLOSE);
                }
                mTransitionController.collect(mToken);
                mAnimatingExit = true;
                mRemoveOnExit = true;
                mToken.setVisibleRequested(false);
                mWmService.mPresentationController.onPresentationRemoved(this);
                // A presentation hides all activities behind on the same display.
                mDisplayContent.ensureActivitiesVisible(/*starting=*/ null,
                        /*notifyClients=*/ true);
                mTransitionController.getCollectingTransition().setReady(mToken, true);
                if (transition != null) {
                    mTransitionController.requestStartTransition(transition, null,
                            null /* remoteTransition */, null /* displayChange */);
                }
            } else {
                removeImmediately();
                mWmService.updateFocusedWindowLocked(isFocused()
                                ? UPDATE_FOCUS_REMOVING_FOCUS
                                : UPDATE_FOCUS_NORMAL,
                        true /*updateInputWindows*/);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
+48 −5
Original line number Diff line number Diff line
@@ -17,14 +17,18 @@
package com.android.server.wm;

import static android.view.Display.FLAG_PRESENTATION;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.window.flags.Flags.FLAG_ENABLE_PRESENTATION_FOR_CONNECTED_DISPLAYS;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;

import android.annotation.NonNull;
import android.graphics.Rect;
import android.os.UserHandle;
import android.os.UserManager;
@@ -41,6 +45,7 @@ import android.view.WindowManagerGlobal;

import androidx.test.filters.SmallTest;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -53,9 +58,16 @@ import org.junit.runner.RunWith;
@RunWith(WindowTestRunner.class)
public class PresentationControllerTests extends WindowTestsBase {

    TestTransitionPlayer mPlayer;

    @Before
    public void setUp() {
        mPlayer = registerTestTransitionPlayer();
    }

    @EnableFlags(FLAG_ENABLE_PRESENTATION_FOR_CONNECTED_DISPLAYS)
    @Test
    public void testPresentationHidesActivitiesBehind() {
    public void testPresentationShowAndHide() {
        final DisplayInfo displayInfo = new DisplayInfo();
        displayInfo.copyFrom(mDisplayInfo);
        displayInfo.flags = FLAG_PRESENTATION;
@@ -64,7 +76,6 @@ public class PresentationControllerTests extends WindowTestsBase {
        doReturn(dc).when(mWm.mRoot).getDisplayContentOrCreate(displayId);
        final ActivityRecord activity = createActivityRecord(createTask(dc));
        assertTrue(activity.isVisible());

        doReturn(true).when(() -> UserManager.isVisibleBackgroundUsersEnabled());
        final int uid = 100000; // uid for non-system user
        final Session session = createTestSession(mAtm, 1234 /* pid */, uid);
@@ -72,16 +83,48 @@ public class PresentationControllerTests extends WindowTestsBase {
        doReturn(false).when(mWm.mUmInternal).isUserVisible(eq(userId), eq(displayId));
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_PRESENTATION);

        final IWindow clientWindow = new TestIWindow();

        // Show a Presentation window, which requests the activity to be stopped.
        final int result = mWm.addWindow(session, clientWindow, params, View.VISIBLE, displayId,
                userId, WindowInsets.Type.defaultVisible(), null, new InsetsState(),
                new InsetsSourceControl.Array(), new Rect(), new float[1]);
        assertTrue(result >= WindowManagerGlobal.ADD_OKAY);
        assertFalse(activity.isVisibleRequested());
        assertTrue(activity.isVisible());
        final WindowState window = mWm.windowForClientLocked(session, clientWindow, false);
        window.mHasSurface = true;
        final Transition addTransition = window.mTransitionController.getCollectingTransition();
        assertEquals(TRANSIT_OPEN, addTransition.mType);
        assertTrue(addTransition.isInTransition(window));
        assertTrue(addTransition.isInTransition(activity));

        // Completing the transition makes the activity invisible.
        completeTransition(addTransition, /*abortSync=*/ true);
        assertFalse(activity.isVisible());

        final WindowState window = mWm.windowForClientLocked(session, clientWindow, false);
        window.removeImmediately();
        // Remove a Presentation window, which requests the activity to be resumed back.
        window.removeIfPossible();
        final Transition removeTransition = window.mTransitionController.getCollectingTransition();
        assertEquals(TRANSIT_CLOSE, removeTransition.mType);
        assertTrue(removeTransition.isInTransition(window));
        assertTrue(removeTransition.isInTransition(activity));
        assertTrue(activity.isVisibleRequested());
        assertFalse(activity.isVisible());

        // Completing the transition makes the activity visible.
        completeTransition(removeTransition, /*abortSync=*/ false);
        assertTrue(activity.isVisible());
    }

    private void completeTransition(@NonNull Transition transition, boolean abortSync) {
        final ActionChain chain = ActionChain.testFinish(transition);
        if (abortSync) {
            // Forcefully finishing the active sync for testing purpose.
            mWm.mSyncEngine.abort(transition.getSyncId());
        } else {
            transition.onTransactionReady(transition.getSyncId(), mTransaction);
        }
        transition.finishTransition(chain);
    }
}