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

Commit b327458f authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Do not use virtual display from real system in mocked test

If the test inherit WindowTestsBase, the window manager is like in a
sandbox environment. It should not have interaction with real
system as possible. Otherwise it may leave some permanent side effects
and affect other tests because the mocked environment cannot guarantee
to manage the real resources well.

Also moved content recording related tests to ContentRecorderTests.

Bug: 254268165
Test: atest ContentRecorderTests WindowManagerServiceTests
Change-Id: I33ca2cfc51943f4a19abc4fc226309cb68eb32bf
parent 89563b52
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
@@ -453,6 +453,78 @@ public class ContentRecorderTests extends WindowTestsBase {
                displayAreaBounds.width(), displayAreaBounds.height());
    }

    @Test
    public void testDisplayContentUpdatesRecording_withoutSurface() {
        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
        // mirror.
        setUpDefaultTaskDisplayAreaWindowToken();

        // WHEN getting the DisplayContent for the new virtual display without providing a valid
        // size from getDisplaySurfaceDefaultSize, i.e. the case of null surface.
        final DisplayContent virtualDisplay =
                mRootWindowContainer.getDisplayContent(mDisplaySession.getVirtualDisplayId());
        doReturn(null).when(mWm.mDisplayManagerInternal).getDisplaySurfaceDefaultSize(anyInt());
        mWm.mContentRecordingController.setContentRecordingSessionLocked(mDisplaySession, mWm);
        virtualDisplay.updateRecording();

        // THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off.
        assertThat(virtualDisplay.isCurrentlyRecording()).isFalse();
    }

    @Test
    public void testDisplayContentUpdatesRecording_withSurface() {
        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
        // mirror.
        setUpDefaultTaskDisplayAreaWindowToken();

        // WHEN getting the DisplayContent for the virtual display with a valid size from
        // getDisplaySurfaceDefaultSize (done by surfaceControlMirrors in setUp).
        final DisplayContent virtualDisplay =
                mRootWindowContainer.getDisplayContent(mDisplaySession.getVirtualDisplayId());
        mWm.mContentRecordingController.setContentRecordingSessionLocked(mDisplaySession, mWm);
        virtualDisplay.updateRecording();

        // THEN mirroring is initiated for the default display's DisplayArea.
        assertThat(virtualDisplay.isCurrentlyRecording()).isTrue();
    }

    @Test
    public void testDisplayContentUpdatesRecording_displayMirroring() {
        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
        // mirror.
        setUpDefaultTaskDisplayAreaWindowToken();

        // GIVEN SurfaceControl can successfully mirror the provided surface.
        surfaceControlMirrors(sSurfaceSize);
        // Initially disable getDisplayIdToMirror since the DMS may create the DC outside the direct
        // call in the test. We need to spy on the DC before updateRecording is called or we can't
        // verify setDisplayMirroring is called
        doReturn(INVALID_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());

        // WHEN getting the DisplayContent for the new virtual display.
        final DisplayContent virtualDisplay =
                mRootWindowContainer.getDisplayContent(mDisplaySession.getVirtualDisplayId());
        // Return the default display as the value to mirror to ensure the VD with flag mirroring
        // creates a ContentRecordingSession automatically.
        doReturn(DEFAULT_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());
        virtualDisplay.updateRecording();

        // THEN mirroring is initiated for the default display's DisplayArea.
        verify(virtualDisplay).setDisplayMirroring();
        assertThat(virtualDisplay.isCurrentlyRecording()).isTrue();
    }

    /**
     * Creates a WindowToken associated with the default task DisplayArea, in order for that
     * DisplayArea to be mirrored.
     */
    private void setUpDefaultTaskDisplayAreaWindowToken() {
        // GIVEN the default task display area is represented by the WindowToken.
        spyOn(mWm.mWindowContextListenerController);
        doReturn(mDefaultDisplay.getDefaultTaskDisplayArea()).when(
                mWm.mWindowContextListenerController).getContainer(any());
    }

    /**
     * Creates a {@link android.window.WindowContainerToken} associated with a task, in order for
     * that task to be recorded.
+0 −137
Original line number Diff line number Diff line
@@ -27,12 +27,10 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.Q;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
import static android.view.Surface.ROTATION_0;
@@ -112,11 +110,9 @@ import android.app.ActivityTaskManager;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.HardwareBuffer;
import android.hardware.display.VirtualDisplay;
import android.metrics.LogMaker;
import android.os.Binder;
import android.os.RemoteException;
@@ -124,7 +120,6 @@ import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.view.ContentRecordingSession;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
@@ -2654,138 +2649,6 @@ public class DisplayContentTests extends WindowTestsBase {
        assertNotEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
    }

    @Test
    public void testVirtualDisplayContent_withoutSurface() {
        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
        // mirror.
        setUpDefaultTaskDisplayAreaWindowToken();

        // GIVEN SurfaceControl does not mirror a null surface.
        Point surfaceSize = new Point(
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());

        // GIVEN a new VirtualDisplay with an associated surface.
        final VirtualDisplay display = createVirtualDisplay(surfaceSize, null /* surface */);
        final int displayId = display.getDisplay().getDisplayId();
        mWm.mRoot.onDisplayAdded(displayId);

        // WHEN getting the DisplayContent for the new virtual display.
        DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId);
        ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
                DEFAULT_DISPLAY);
        session.setVirtualDisplayId(displayId);
        mWm.mContentRecordingController.setContentRecordingSessionLocked(session, mWm);
        actualDC.updateRecording();

        // THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off.
        assertThat(actualDC.isCurrentlyRecording()).isFalse();

        display.release();
    }

    @Test
    public void testVirtualDisplayContent_withSurface() {
        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
        // mirror.
        setUpDefaultTaskDisplayAreaWindowToken();

        // GIVEN SurfaceControl can successfully mirror the provided surface.
        Point surfaceSize = new Point(
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
        surfaceControlMirrors(surfaceSize);

        // GIVEN a new VirtualDisplay with an associated surface.
        final VirtualDisplay display = createVirtualDisplay(surfaceSize, new Surface());
        final int displayId = display.getDisplay().getDisplayId();

        // GIVEN a session for this display.
        ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
                DEFAULT_DISPLAY);
        session.setVirtualDisplayId(displayId);
        mWm.mContentRecordingController.setContentRecordingSessionLocked(session, mWm);
        mWm.mRoot.onDisplayAdded(displayId);

        // WHEN getting the DisplayContent for the new virtual display.
        DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId);
        actualDC.updateRecording();

        // THEN mirroring is initiated for the default display's DisplayArea.
        assertThat(actualDC.isCurrentlyRecording()).isTrue();

        display.release();
    }

    @Test
    public void testVirtualDisplayContent_displayMirroring() {
        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
        // mirror.
        setUpDefaultTaskDisplayAreaWindowToken();

        // GIVEN SurfaceControl can successfully mirror the provided surface.
        Point surfaceSize = new Point(
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
        surfaceControlMirrors(surfaceSize);
        // Initially disable getDisplayIdToMirror since the DMS may create the DC outside the direct
        // call in the test. We need to spy on the DC before updateRecording is called or we can't
        // verify setDisplayMirroring is called
        doReturn(INVALID_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());

        // GIVEN a new VirtualDisplay with an associated surface.
        final VirtualDisplay display = createVirtualDisplay(surfaceSize, new Surface());
        final int displayId = display.getDisplay().getDisplayId();

        // GIVEN a session for this display.
        mWm.mRoot.onDisplayAdded(displayId);

        // WHEN getting the DisplayContent for the new virtual display.
        DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId);
        spyOn(actualDC);
        // Return the default display as the value to mirror to ensure the VD with flag mirroring
        // creates a ContentRecordingSession automatically.
        doReturn(DEFAULT_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());
        actualDC.updateRecording();

        // THEN mirroring is initiated for the default display's DisplayArea.
        verify(actualDC).setDisplayMirroring();
        assertThat(actualDC.isCurrentlyRecording()).isTrue();
        display.release();
    }

    /**
     * Creates a WindowToken associated with the default task DisplayArea, in order for that
     * DisplayArea to be mirrored.
     */
    private void setUpDefaultTaskDisplayAreaWindowToken() {
        // GIVEN the default task display area is represented by the WindowToken.
        spyOn(mWm.mWindowContextListenerController);
        doReturn(mDefaultDisplay.getDefaultTaskDisplayArea()).when(
                mWm.mWindowContextListenerController).getContainer(any());
    }

    /**
     * SurfaceControl successfully creates a mirrored surface of the given size.
     */
    private SurfaceControl surfaceControlMirrors(Point surfaceSize) {
        // Do not set the parent, since the mirrored surface is the root of a new surface hierarchy.
        SurfaceControl mirroredSurface = new SurfaceControl.Builder()
                .setName("mirroredSurface")
                .setBufferSize(surfaceSize.x, surfaceSize.y)
                .setCallsite("mirrorSurface")
                .build();
        doReturn(mirroredSurface).when(() -> SurfaceControl.mirrorSurface(any()));
        doReturn(surfaceSize).when(mWm.mDisplayManagerInternal).getDisplaySurfaceDefaultSize(
                anyInt());
        return mirroredSurface;
    }

    private VirtualDisplay createVirtualDisplay(Point size, Surface surface) {
        return mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay", size.x, size.y,
                DisplayMetrics.DENSITY_140, surface, VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
    }

    @Test
    public void testKeepClearAreasMultipleWindows() {
        final WindowState w1 = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent, "w1");
+42 −80
Original line number Diff line number Diff line
@@ -21,9 +21,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_OWN_FOCUS;
import static android.view.Display.INVALID_DISPLAY;
@@ -63,6 +60,8 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.description;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -71,9 +70,7 @@ import static org.mockito.Mockito.when;
import android.app.ActivityThread;
import android.app.IApplicationThread;
import android.content.pm.ActivityInfo;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.VirtualDisplay;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -82,7 +79,6 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.util.MergedConfiguration;
import android.view.ContentRecordingSession;
import android.view.IWindow;
@@ -90,7 +86,6 @@ import android.view.IWindowSessionCallback;
import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowInsets;
@@ -575,13 +570,14 @@ public class WindowManagerServiceTests extends WindowTestsBase {
        mWm.mPerDisplayFocusEnabled = false;

        // Create one extra display
        final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false);
        final VirtualDisplay virtualDisplayOwnTouchMode =
                createVirtualDisplay(/* ownFocus= */ true);
        final DisplayContent display = createMockSimulatedDisplay();
        display.getDisplayInfo().flags &= ~FLAG_OWN_FOCUS;
        final DisplayContent displayOwnTouchMode = createMockSimulatedDisplay();
        displayOwnTouchMode.getDisplayInfo().flags |= FLAG_OWN_FOCUS;
        final int numberOfDisplays = mWm.mRoot.mChildren.size();
        assertThat(numberOfDisplays).isAtLeast(3);
        final int numberOfGlobalTouchModeDisplays = (int) mWm.mRoot.mChildren.stream()
                .filter(d -> (d.getDisplay().getFlags() & FLAG_OWN_FOCUS) == 0)
                .filter(d -> (d.getDisplayInfo().flags & FLAG_OWN_FOCUS) == 0)
                .count();
        assertThat(numberOfGlobalTouchModeDisplays).isAtLeast(2);

@@ -601,12 +597,13 @@ public class WindowManagerServiceTests extends WindowTestsBase {
    }

    @Test
    public void testSetInTouchMode_multiDisplay_perDisplayFocus_singleDisplayTouchModeUpdate() {
    public void testSetInTouchMode_multiDisplay_singleDisplayTouchModeUpdate() {
        // Enable global touch mode
        mWm.mPerDisplayFocusEnabled = true;

        // Create one extra display
        final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false);
        final DisplayContent virtualDisplay = createMockSimulatedDisplay();
        virtualDisplay.getDisplayInfo().flags &= ~FLAG_OWN_FOCUS;
        final int numberOfDisplays = mWm.mRoot.mChildren.size();
        assertThat(numberOfDisplays).isAtLeast(2);

@@ -618,99 +615,64 @@ public class WindowManagerServiceTests extends WindowTestsBase {
        when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid,
                android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true);

        mWm.setInTouchMode(!currentTouchMode, virtualDisplay.getDisplay().getDisplayId());
        mWm.setInTouchMode(!currentTouchMode, virtualDisplay.mDisplayId);

        // Ensure that new display touch mode state has changed.
        verify(mWm.mInputManager).setInTouchMode(
                !currentTouchMode, callingPid, callingUid, /* hasPermission= */ true,
                virtualDisplay.getDisplay().getDisplayId());
    }
                virtualDisplay.mDisplayId);

    @Test
    public void testSetInTouchMode_multiDisplay_ownTouchMode_singleDisplayTouchModeUpdate() {
        // Disable global touch mode
        // Disable global touch mode and make the virtual display own focus.
        mWm.mPerDisplayFocusEnabled = false;

        // Create one extra display
        final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ true);
        final int numberOfDisplays = mWm.mRoot.mChildren.size();
        assertThat(numberOfDisplays).isAtLeast(2);

        // Get current touch mode state and setup WMS to run setInTouchMode
        boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY);
        int callingPid = Binder.getCallingPid();
        int callingUid = Binder.getCallingUid();
        doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean());
        when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid,
                android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true);

        mWm.setInTouchMode(!currentTouchMode, virtualDisplay.getDisplay().getDisplayId());
        virtualDisplay.getDisplayInfo().flags |= FLAG_OWN_FOCUS;
        clearInvocations(mWm.mInputManager);
        mWm.setInTouchMode(!currentTouchMode, virtualDisplay.mDisplayId);

        // Ensure that new display touch mode state has changed.
        verify(mWm.mInputManager).setInTouchMode(
                !currentTouchMode, callingPid, callingUid, /* hasPermission= */ true,
                virtualDisplay.getDisplay().getDisplayId());
                virtualDisplay.mDisplayId);
    }

    @Test
    public void testSetInTouchModeOnAllDisplays_perDisplayFocusDisabled() {
        testSetInTouchModeOnAllDisplays(/* perDisplayFocusEnabled= */ false);
    }

    @Test
    public void testSetInTouchModeOnAllDisplays_perDisplayFocusEnabled() {
        testSetInTouchModeOnAllDisplays(/* perDisplayFocusEnabled= */ true);
    }

    private void testSetInTouchModeOnAllDisplays(boolean perDisplayFocusEnabled) {
        // Set global touch mode with the value passed as argument.
        mWm.mPerDisplayFocusEnabled = perDisplayFocusEnabled;

    public void testSetInTouchModeOnAllDisplays() {
        // Create a couple of extra displays.
        // setInTouchModeOnAllDisplays should ignore the ownFocus setting.
        final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false);
        final VirtualDisplay virtualDisplayOwnFocus = createVirtualDisplay(/* ownFocus= */ true);
        final DisplayContent display = createMockSimulatedDisplay();
        display.getDisplayInfo().flags &= ~FLAG_OWN_FOCUS;
        final DisplayContent displayOwnTouchMode = createMockSimulatedDisplay();
        displayOwnTouchMode.getDisplayInfo().flags |= FLAG_OWN_FOCUS;

        int callingPid = Binder.getCallingPid();
        int callingUid = Binder.getCallingUid();
        doReturn(true).when(mWm.mInputManager).setInTouchMode(anyBoolean(), anyInt(),
                anyInt(), anyBoolean(), anyInt());
        doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean());
        when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid,
                android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true);

        final Runnable verification = () -> {
            for (boolean inTouchMode : new boolean[] { true, false }) {
                mWm.setInTouchModeOnAllDisplays(inTouchMode);
            for (int i = 0; i < mWm.mRoot.mChildren.size(); ++i) {
                DisplayContent dc = mWm.mRoot.mChildren.get(i);
                for (int i = 0; i < mRootWindowContainer.getChildCount(); ++i) {
                    final DisplayContent dc = mRootWindowContainer.getChildAt(i);
                    // All displays that are not already in the desired touch mode are requested to
                    // change their touch mode.
                    if (dc.isInTouchMode() != inTouchMode) {
                    verify(mWm.mInputManager).setInTouchMode(
                            true, callingPid, callingUid, /* hasPermission= */ true,
                            dc.getDisplay().getDisplayId());
                }
                        verify(mWm.mInputManager, description("perDisplayFocusEnabled="
                                + mWm.mPerDisplayFocusEnabled)).setInTouchMode(true,
                                callingPid, callingUid, /* hasPermission= */ true, dc.mDisplayId);
                    }
                }
            }
        };

    private VirtualDisplay createVirtualDisplay(boolean ownFocus) {
        // Create virtual display
        Point surfaceSize = new Point(
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
        int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC;
        if (ownFocus) {
            flags |= VIRTUAL_DISPLAY_FLAG_OWN_FOCUS | VIRTUAL_DISPLAY_FLAG_TRUSTED;
        }
        VirtualDisplay virtualDisplay = mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay",
                surfaceSize.x, surfaceSize.y, DisplayMetrics.DENSITY_140, new Surface(), flags);
        final int displayId = virtualDisplay.getDisplay().getDisplayId();
        mWm.mRoot.onDisplayAdded(displayId);

        // Ensure that virtual display was properly created and stored in WRC
        assertThat(mWm.mRoot.getDisplayContent(
                virtualDisplay.getDisplay().getDisplayId())).isNotNull();
        mWm.mPerDisplayFocusEnabled = false;
        verification.run();

        return virtualDisplay;
        clearInvocations(mWm.mInputManager);
        mWm.mPerDisplayFocusEnabled = true;
        verification.run();
    }

    @Test
+1 −0
Original line number Diff line number Diff line
@@ -901,6 +901,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
        DisplayInfo displayInfo = new DisplayInfo();
        displayInfo.copyFrom(mDisplayInfo);
        displayInfo.type = Display.TYPE_VIRTUAL;
        displayInfo.state = Display.STATE_ON;
        displayInfo.ownerUid = SYSTEM_UID;
        return createNewDisplay(displayInfo, DISPLAY_IME_POLICY_FALLBACK_DISPLAY, overrideSettings);
    }