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

Commit 472e00b0 authored by Naomi Musgrave's avatar Naomi Musgrave
Browse files

Refactor content recording out of DisplayContent

Bug: 216756854
Test: atest WmTests:ContentRecorderTests
Test: atest WmTests:DisplayContentTests
Change-Id: Idf8f5b22986f889348ca187b2f1f005da163e5e2
parent 27655e1f
Loading
Loading
Loading
Loading
+63 −63
Original line number Diff line number Diff line
@@ -295,6 +295,12 @@
      "group": "WM_DEBUG_STARTING_WINDOW",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-1781861035": {
      "message": "Display %d has content (%b) so pause recording",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "-1777196134": {
      "message": "goodToGo(): No apps to animate, mPendingAnimations=%d",
      "level": "DEBUG",
@@ -343,12 +349,6 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
    },
    "-1734445525": {
      "message": "Display %d has content (%b) so pause recording",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-1730156332": {
      "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
      "level": "VERBOSE",
@@ -445,6 +445,12 @@
      "group": "WM_DEBUG_LOCKTASK",
      "at": "com\/android\/server\/wm\/LockTaskController.java"
    },
    "-1605829532": {
      "message": "Unable to start recording due to null token for display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "-1598452494": {
      "message": "activityDestroyedLocked: r=%s",
      "level": "DEBUG",
@@ -511,12 +517,6 @@
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "-1542296596": {
      "message": "Going ahead with updating recording for display %d to new bounds %s and\/or orientation %d.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-1539974875": {
      "message": "removeAppToken: %s delayed=%b Callers=%s",
      "level": "VERBOSE",
@@ -715,6 +715,12 @@
      "group": "WM_DEBUG_TASKS",
      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
    },
    "-1373875178": {
      "message": "Going ahead with updating recording for display %d to new bounds %s and\/or orientation %d.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "-1364754753": {
      "message": "Task vanished taskId=%d",
      "level": "VERBOSE",
@@ -739,11 +745,11 @@
      "group": "WM_DEBUG_STARTING_WINDOW",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-1323003327": {
      "message": "Unexpectedly null window container; unable to update recording for display %d",
    "-1326876381": {
      "message": "Provided surface for recording on display %d is not present, so do not update the surface",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "-1311436264": {
      "message": "Unregister task fragment organizer=%s uid=%d pid=%d",
@@ -859,12 +865,6 @@
      "group": "WM_DEBUG_WINDOW_INSETS",
      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
    },
    "-1179559337": {
      "message": "Unable to start recording due to invalid region for display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-1176488860": {
      "message": "SURFACE isSecure=%b: %s",
      "level": "INFO",
@@ -1045,12 +1045,6 @@
      "group": "WM_DEBUG_DRAW",
      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
    },
    "-992111757": {
      "message": "Unable to retrieve window container to start recording for display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-986746907": {
      "message": "Starting window removed %s",
      "level": "DEBUG",
@@ -1111,12 +1105,6 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-922507769": {
      "message": "Display %d has no content and is on, so start recording for state %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-917215012": {
      "message": "%s: caller %d is using old GET_TASKS but privileged; allowing",
      "level": "WARN",
@@ -1291,6 +1279,12 @@
      "group": "WM_DEBUG_SCREEN_ON",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "-751255162": {
      "message": "Unable to update recording for display %d to new bounds %s and\/or orientation %d, since the surface is not available.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "-743856570": {
      "message": "shouldWaitAnimatingExit: isAnimating: %s",
      "level": "DEBUG",
@@ -1303,6 +1297,12 @@
      "group": "WM_DEBUG_CONFIGURATION",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-732715767": {
      "message": "Unable to retrieve window container to start recording for display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "-729530161": {
      "message": "Moving to DESTROYED: %s (no app)",
      "level": "VERBOSE",
@@ -1549,18 +1549,6 @@
      "group": "WM_DEBUG_KEEP_SCREEN_ON",
      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
    },
    "-479990726": {
      "message": "Unable to start recording due to null token for display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-473911359": {
      "message": "Display %d was already recording, so apply transformations if necessary",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-463348344": {
      "message": "Removing and adding activity %s to root task at top callers=%s",
      "level": "INFO",
@@ -1669,12 +1657,6 @@
      "group": "WM_DEBUG_TASKS",
      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
    },
    "-370641936": {
      "message": "Unable to update recording for display %d to new bounds %s and\/or orientation %d, since the surface is not available.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "-360208282": {
      "message": "Animating wallpapers: old: %s hidden=%b new: %s hidden=%b",
      "level": "VERBOSE",
@@ -1747,6 +1729,12 @@
      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
    },
    "-302468137": {
      "message": "Display %d was already recording, so apply transformations if necessary",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "-292790591": {
      "message": "Attempted to set IME policy to a display that does not exist: %d",
      "level": "WARN",
@@ -1873,6 +1861,12 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/Task.java"
    },
    "-142844021": {
      "message": "Unable to start recording for display %d since the surface is not available.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "-134091882": {
      "message": "Screenshotting Activity %s",
      "level": "VERBOSE",
@@ -2605,6 +2599,12 @@
      "group": "WM_SHOW_TRANSACTIONS",
      "at": "com\/android\/server\/wm\/Session.java"
    },
    "609880497": {
      "message": "Display %d has no content and is on, so start recording for state %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "620368427": {
      "message": "******* TELLING SURFACE FLINGER WE ARE BOOTED!",
      "level": "INFO",
@@ -3319,6 +3319,12 @@
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "1444064727": {
      "message": "Unexpectedly null window container; unable to update recording for display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "1448683958": {
      "message": "Override pending remote transitionSet=%b adapter=%s",
      "level": "INFO",
@@ -3445,6 +3451,12 @@
      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
      "at": "com\/android\/server\/wm\/AppTransition.java"
    },
    "1608402305": {
      "message": "Unable to start recording due to invalid region for display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "1610646518": {
      "message": "Enqueueing pending finish: %s",
      "level": "VERBOSE",
@@ -3547,12 +3559,6 @@
      "group": "WM_DEBUG_WINDOW_ORGANIZER",
      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
    },
    "1707558369": {
      "message": "Unable to start recording for display %d since the surface is not available.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "1720229827": {
      "message": "Creating animation bounds layer",
      "level": "INFO",
@@ -3685,12 +3691,6 @@
      "group": "WM_DEBUG_STARTING_WINDOW",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "1854279309": {
      "message": "Provided surface for recording on display %d is not present, so do not update the surface",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "1856211951": {
      "message": "moveFocusableActivityToTop: already on top, activity=%s",
      "level": "DEBUG",
+368 −0

File added.

Preview size limit exceeded, changes collapsed.

+20 −265

File changed.

Preview size limit exceeded, changes collapsed.

+239 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;


import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;

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

import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;

import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.VirtualDisplay;
import android.os.Binder;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.view.ContentRecordingSession;
import android.view.Surface;
import android.view.SurfaceControl;

import androidx.test.filters.SmallTest;

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

/**
 * Tests for the {@link ContentRecorder} class.
 *
 * Build/Install/Run:
 *  atest WmTests:ContentRecorderTests
 */
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
public class ContentRecorderTests extends WindowTestsBase {
    private static final IBinder TEST_TOKEN = new RecordingTestToken();
    private final ContentRecordingSession mDefaultSession =
            ContentRecordingSession.createDisplaySession(TEST_TOKEN);
    private static Point sSurfaceSize;
    private ContentRecorder mContentRecorder;
    private SurfaceControl mRecordedSurface;

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

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

        // GIVEN the VirtualDisplay associated with the session (so the display has state ON).
        VirtualDisplay virtualDisplay = mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay",
                sSurfaceSize.x, sSurfaceSize.y,
                DisplayMetrics.DENSITY_140, new Surface(), VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
        final int displayId = virtualDisplay.getDisplay().getDisplayId();
        mDefaultSession.setDisplayId(displayId);

        mWm.mRoot.onDisplayAdded(displayId);
        final DisplayContent mVirtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
        mContentRecorder = new ContentRecorder(mVirtualDisplayContent);
        spyOn(mVirtualDisplayContent);
    }

    @Test
    public void testIsCurrentlyRecording() {
        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();

        mContentRecorder.updateRecording();
        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
    }

    @Test
    public void testUpdateRecording_display() {
        mContentRecorder.setContentRecordingSession(mDefaultSession);
        mContentRecorder.updateRecording();
        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
    }

    @Test
    public void testUpdateRecording_task() {
        mDefaultSession.setContentToRecord(RECORD_CONTENT_TASK);
        mContentRecorder.setContentRecordingSession(mDefaultSession);
        mContentRecorder.updateRecording();
        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
    }

    @Test
    public void testUpdateRecording_wasPaused() {
        mContentRecorder.setContentRecordingSession(mDefaultSession);
        mContentRecorder.updateRecording();

        mContentRecorder.pauseRecording();
        mContentRecorder.updateRecording();
        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
    }

    @Test
    public void testUpdateRecording_wasStopped() {
        mContentRecorder.setContentRecordingSession(mDefaultSession);
        mContentRecorder.updateRecording();

        mContentRecorder.remove();
        mContentRecorder.updateRecording();
        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
    }

    @Test
    public void testOnConfigurationChanged_neverRecording() {
        mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);

        verify(mTransaction, never()).setPosition(eq(mRecordedSurface), anyFloat(), anyFloat());
        verify(mTransaction, never()).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
                anyFloat(), anyFloat());
    }

    @Test
    public void testOnConfigurationChanged_resizesSurface() {
        mContentRecorder.setContentRecordingSession(mDefaultSession);
        mContentRecorder.updateRecording();
        mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);

        verify(mTransaction, atLeastOnce()).setPosition(eq(mRecordedSurface), anyFloat(),
                anyFloat());
        verify(mTransaction, atLeastOnce()).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
                anyFloat(), anyFloat());
    }

    @Test
    public void testPauseRecording_pausesRecording() {
        mContentRecorder.setContentRecordingSession(mDefaultSession);
        mContentRecorder.updateRecording();

        mContentRecorder.pauseRecording();
        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
    }

    @Test
    public void testPauseRecording_neverRecording() {
        mContentRecorder.pauseRecording();
        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
    }

    @Test
    public void testRemove_stopsRecording() {
        mContentRecorder.setContentRecordingSession(mDefaultSession);
        mContentRecorder.updateRecording();

        mContentRecorder.remove();
        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
    }

    @Test
    public void testRemove_neverRecording() {
        mContentRecorder.remove();
        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
    }

    @Test
    public void testUpdateMirroredSurface_capturedAreaResized() {
        mContentRecorder.setContentRecordingSession(mDefaultSession);
        mContentRecorder.updateRecording();

        // WHEN attempting to mirror on the virtual display, and the captured content is resized.
        float xScale = 0.7f;
        float yScale = 2f;
        Rect displayAreaBounds = new Rect(0, 0, Math.round(sSurfaceSize.x * xScale),
                Math.round(sSurfaceSize.y * yScale));
        mContentRecorder.updateMirroredSurface(mTransaction, displayAreaBounds, sSurfaceSize);

        // THEN content in the captured DisplayArea is scaled to fit the surface size.
        verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, 1.0f / yScale, 0, 0,
                1.0f / yScale);
        // THEN captured content is positioned in the centre of the output surface.
        float scaledWidth = displayAreaBounds.width() / xScale;
        float xInset = (sSurfaceSize.x - scaledWidth) / 2;
        verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
    }

    private static class RecordingTestToken extends Binder {
    }

    /**
     * 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;
    }
}
+1 −106

File changed.

Preview size limit exceeded, changes collapsed.

Loading