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

Commit 910509a5 authored by Pierre Barbier de Reuille's avatar Pierre Barbier de Reuille
Browse files

Adapt recorded scaling in X and Y

The new scaling takes into account the asymmetry in pixel size on the
external display for better rendering.

Bug: 304248677
Test: atest WmTests:ContentRecorderTests
Change-Id: I7502538c5423343da93c20bfb7c6c8bea33dd7d2
parent 25016080
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -2887,6 +2887,12 @@
      "group": "WM_DEBUG_RESIZE",
      "at": "com\/android\/server\/wm\/WindowState.java"
    },
    "419378610": {
      "message": "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "422634333": {
      "message": "First draw done in potential wallpaper target %s",
      "level": "VERBOSE",
@@ -4339,12 +4345,6 @@
      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
    },
    "1936800105": {
      "message": "Content Recording: Apply transformations of shift %d x %d, scale %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "1945495497": {
      "message": "Focused window didn't have a valid surface drawn.",
      "level": "DEBUG",
+65 −14
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.media.projection.IMediaProjectionManager;
import android.os.IBinder;
@@ -36,16 +37,28 @@ import android.os.ServiceManager;
import android.view.ContentRecordingSession;
import android.view.ContentRecordingSession.RecordContent;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.SurfaceControl;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.display.feature.DisplayManagerFlags;

/**
 * Manages content recording for a particular {@link DisplayContent}.
 */
final class ContentRecorder implements WindowContainerListener {

    /**
     * Maximum acceptable anisotropy for the output image.
     *
     * Necessary to avoid unnecessary scaling when the anisotropy is almost the same, as it is not
     * exact anyway. For external displays, we expect an anisoptry of about 2% even if the pixels
     * are, in fact, square due to the imprecision of the display's actual size (rounded to the
     * nearest cm).
     */
    private static final float MAX_ANISOTROPY = 0.025f;

    /**
     * The display content this class is handling recording for.
     */
@@ -87,15 +100,20 @@ final class ContentRecorder implements WindowContainerListener {
    @Configuration.Orientation
    private int mLastOrientation = ORIENTATION_UNDEFINED;

    private final boolean mCorrectForAnisotropicPixels;

    ContentRecorder(@NonNull DisplayContent displayContent) {
        this(displayContent, new RemoteMediaProjectionManagerWrapper(displayContent.mDisplayId));
        this(displayContent, new RemoteMediaProjectionManagerWrapper(displayContent.mDisplayId),
                new DisplayManagerFlags().isConnectedDisplayManagementEnabled());
    }

    @VisibleForTesting
    ContentRecorder(@NonNull DisplayContent displayContent,
            @NonNull MediaProjectionManagerWrapper mediaProjectionManager) {
            @NonNull MediaProjectionManagerWrapper mediaProjectionManager,
            boolean correctForAnisotropicPixels) {
        mDisplayContent = displayContent;
        mMediaProjectionManager = mediaProjectionManager;
        mCorrectForAnisotropicPixels = correctForAnisotropicPixels;
    }

    /**
@@ -460,6 +478,33 @@ final class ContentRecorder implements WindowContainerListener {
        }
    }

    private void computeScaling(int inputSizeX, int inputSizeY,
            float inputDpiX, float inputDpiY,
            int outputSizeX, int outputSizeY,
            float outputDpiX, float outputDpiY,
            PointF scaleOut) {
        float relAnisotropy = (inputDpiY / inputDpiX) / (outputDpiY / outputDpiX);
        if (!mCorrectForAnisotropicPixels
                || (relAnisotropy > (1 - MAX_ANISOTROPY) && relAnisotropy < (1 + MAX_ANISOTROPY))) {
            // Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the
            // output surface.
            float scaleX = outputSizeX / (float) inputSizeX;
            float scaleY = outputSizeY / (float) inputSizeY;
            float scale = Math.min(scaleX, scaleY);
            scaleOut.x = scale;
            scaleOut.y = scale;
            return;
        }

        float relDpiX = outputDpiX / inputDpiX;
        float relDpiY = outputDpiY / inputDpiY;

        float scale = Math.min(outputSizeX / relDpiX / inputSizeX,
                outputSizeY / relDpiY / inputSizeY);
        scaleOut.x = scale * relDpiX;
        scaleOut.y = scale * relDpiY;
    }

    /**
     * Apply transformations to the mirrored surface to ensure the captured contents are scaled to
     * fit and centred in the output surface.
@@ -473,13 +518,19 @@ final class ContentRecorder implements WindowContainerListener {
     */
    @VisibleForTesting void updateMirroredSurface(SurfaceControl.Transaction transaction,
            Rect recordedContentBounds, Point surfaceSize) {
        // Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the
        // output surface.
        float scaleX = surfaceSize.x / (float) recordedContentBounds.width();
        float scaleY = surfaceSize.y / (float) recordedContentBounds.height();
        float scale = Math.min(scaleX, scaleY);
        int scaledWidth = Math.round(scale * (float) recordedContentBounds.width());
        int scaledHeight = Math.round(scale * (float) recordedContentBounds.height());

        DisplayInfo inputDisplayInfo = mRecordedWindowContainer.mDisplayContent.getDisplayInfo();
        DisplayInfo outputDisplayInfo = mDisplayContent.getDisplayInfo();

        PointF scale = new PointF();
        computeScaling(recordedContentBounds.width(), recordedContentBounds.height(),
                inputDisplayInfo.physicalXDpi, inputDisplayInfo.physicalYDpi,
                surfaceSize.x, surfaceSize.y,
                outputDisplayInfo.physicalXDpi, outputDisplayInfo.physicalYDpi,
                scale);

        int scaledWidth = Math.round(scale.x * (float) recordedContentBounds.width());
        int scaledHeight = Math.round(scale.y * (float) recordedContentBounds.height());

        // Calculate the shift to apply to the root mirror SurfaceControl to centre the mirrored
        // contents in the output surface.
@@ -493,10 +544,10 @@ final class ContentRecorder implements WindowContainerListener {
        }

        ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                "Content Recording: Apply transformations of shift %d x %d, scale %f, crop (aka "
                        + "recorded content size) %d x %d for display %d; display has size %d x "
                        + "%d; surface has size %d x %d",
                shiftedX, shiftedY, scale, recordedContentBounds.width(),
                "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop "
                        + "(aka recorded content size) %d x %d for display %d; display has size "
                        + "%d x %d; surface has size %d x %d",
                shiftedX, shiftedY, scale.x, scale.y, recordedContentBounds.width(),
                recordedContentBounds.height(), mDisplayContent.getDisplayId(),
                mDisplayContent.getConfiguration().screenWidthDp,
                mDisplayContent.getConfiguration().screenHeightDp, surfaceSize.x, surfaceSize.y);
@@ -508,7 +559,7 @@ final class ContentRecorder implements WindowContainerListener {
                        recordedContentBounds.height())
                // Scale the root mirror SurfaceControl, based upon the size difference between the
                // source (DisplayArea to capture) and output (surface the app reads images from).
                .setMatrix(mRecordedSurface, scale, 0 /* dtdx */, 0 /* dtdy */, scale)
                .setMatrix(mRecordedSurface, scale.x, 0 /* dtdx */, 0 /* dtdy */, scale.y)
                // Position needs to be updated when the mirrored DisplayArea has changed, since
                // the content will no longer be centered in the output surface.
                .setPosition(mRecordedSurface, shiftedX /* x */, shiftedY /* y */);
+194 −23

File changed.

Preview size limit exceeded, changes collapsed.