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

Commit 51e55cff authored by Pablo Gamito's avatar Pablo Gamito Committed by Automerger Merge Worker
Browse files

Merge "Improve performance of edge extension animation" into tm-dev am: 47aa2ca8 am: e02a4598

parents 213ceeed e02a4598
Loading
Loading
Loading
Loading
+75 −35
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.server.wm;
package com.android.server.wm;


import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.util.TimeUtils.NANOS_PER_MS;
import static android.util.TimeUtils.NANOS_PER_MS;
import static android.view.Choreographer.CALLBACK_TRAVERSAL;
import static android.view.Choreographer.CALLBACK_TRAVERSAL;
import static android.view.Choreographer.getSfInstance;
import static android.view.Choreographer.getSfInstance;
@@ -26,14 +27,13 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Rect;
import android.hardware.power.Boost;
import android.hardware.power.Boost;
import android.os.Handler;
import android.os.Handler;
import android.os.PowerManagerInternal;
import android.os.PowerManagerInternal;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Log;
import android.view.Choreographer;
import android.view.Choreographer;
@@ -50,6 +50,8 @@ import com.android.server.AnimationThread;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;
import java.util.function.Supplier;


/**
/**
@@ -83,6 +85,12 @@ class SurfaceAnimationRunner {
    private final PowerManagerInternal mPowerManagerInternal;
    private final PowerManagerInternal mPowerManagerInternal;
    private boolean mApplyScheduled;
    private boolean mApplyScheduled;


    // Executor to perform the edge extension.
    // With two threads because in practice we will want to extend two surfaces in one animation,
    // in which case we want to be able to parallelize those two extensions to cut down latency in
    // starting the animation.
    private final ExecutorService mEdgeExtensionExecutor = Executors.newFixedThreadPool(2);

    @GuardedBy("mLock")
    @GuardedBy("mLock")
    @VisibleForTesting
    @VisibleForTesting
    final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>();
    final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>();
@@ -173,7 +181,7 @@ class SurfaceAnimationRunner {


                // We must wait for t to be committed since otherwise the leash doesn't have the
                // We must wait for t to be committed since otherwise the leash doesn't have the
                // windows we want to screenshot and extend as children.
                // windows we want to screenshot and extend as children.
                t.addTransactionCommittedListener(Runnable::run, () -> {
                t.addTransactionCommittedListener(mEdgeExtensionExecutor, () -> {
                    final WindowAnimationSpec animationSpec = a.asWindowAnimationSpec();
                    final WindowAnimationSpec animationSpec = a.asWindowAnimationSpec();


                    final Transaction edgeExtensionCreationTransaction = new Transaction();
                    final Transaction edgeExtensionCreationTransaction = new Transaction();
@@ -403,30 +411,17 @@ class SurfaceAnimationRunner {
    private void createExtensionSurface(SurfaceControl leash, Rect edgeBounds,
    private void createExtensionSurface(SurfaceControl leash, Rect edgeBounds,
            Rect extensionRect, int xPos, int yPos, String layerName,
            Rect extensionRect, int xPos, int yPos, String layerName,
            Transaction startTransaction) {
            Transaction startTransaction) {
        synchronized (mEdgeExtensionLock) {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createExtensionSurface");
            if (!mEdgeExtensions.containsKey(leash)) {
        doCreateExtensionSurface(leash, edgeBounds, extensionRect, xPos, yPos, layerName,
                // Animation leash has already been removed so we shouldn't perform any extension
                return;
            }
            createExtensionSurfaceLocked(leash, edgeBounds, extensionRect, xPos, yPos, layerName,
                startTransaction);
                startTransaction);
        }
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
    }


    private void createExtensionSurfaceLocked(SurfaceControl surfaceToExtend, Rect edgeBounds,
    private void doCreateExtensionSurface(SurfaceControl leash, Rect edgeBounds,
            Rect extensionRect, int xPos, int yPos, String layerName,
            Rect extensionRect, int xPos, int yPos, String layerName,
            Transaction startTransaction) {
            Transaction startTransaction) {
        final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder()
                .setName(layerName)
                .setParent(surfaceToExtend)
                .setHidden(true)
                .setCallsite("DefaultTransitionHandler#startAnimation")
                .setOpaque(true)
                .setBufferSize(extensionRect.width(), extensionRect.height())
                .build();

        SurfaceControl.LayerCaptureArgs captureArgs =
        SurfaceControl.LayerCaptureArgs captureArgs =
                new SurfaceControl.LayerCaptureArgs.Builder(surfaceToExtend)
                new SurfaceControl.LayerCaptureArgs.Builder(leash /* surfaceToExtend */)
                        .setSourceCrop(edgeBounds)
                        .setSourceCrop(edgeBounds)
                        .setFrameScale(1)
                        .setFrameScale(1)
                        .setPixelFormat(PixelFormat.RGBA_8888)
                        .setPixelFormat(PixelFormat.RGBA_8888)
@@ -437,31 +432,76 @@ class SurfaceAnimationRunner {
                SurfaceControl.captureLayers(captureArgs);
                SurfaceControl.captureLayers(captureArgs);


        if (edgeBuffer == null) {
        if (edgeBuffer == null) {
            // The leash we are trying to screenshot may have been removed by this point, which is
            // likely the reason for ending up with a null edgeBuffer, in which case we just want to
            // return and do nothing.
            Log.e("SurfaceAnimationRunner", "Failed to create edge extension - "
            Log.e("SurfaceAnimationRunner", "Failed to create edge extension - "
                    + "edge buffer is null");
                    + "edge buffer is null");
            return;
            return;
        }
        }


        android.graphics.BitmapShader shader =
        final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder()
                new android.graphics.BitmapShader(edgeBuffer.asBitmap(),
                .setName(layerName)
                        android.graphics.Shader.TileMode.CLAMP,
                .setHidden(true)
                        android.graphics.Shader.TileMode.CLAMP);
                .setCallsite("DefaultTransitionHandler#startAnimation")
        final Paint paint = new Paint();
                .setOpaque(true)
        paint.setShader(shader);
                .setBufferSize(edgeBounds.width(), edgeBounds.height())
                .build();


        final Surface surface = new Surface(edgeExtensionLayer);
        final Surface surface = new Surface(edgeExtensionLayer);
        Canvas c = surface.lockHardwareCanvas();
        surface.attachAndQueueBufferWithColorSpace(edgeBuffer.getHardwareBuffer(),
        c.drawRect(extensionRect, paint);
                edgeBuffer.getColorSpace());
        surface.unlockCanvasAndPost(c);
        surface.release();
        surface.release();


        final float scaleX = getScaleXForExtensionSurface(edgeBounds, extensionRect);
        final float scaleY = getScaleYForExtensionSurface(edgeBounds, extensionRect);

        synchronized (mEdgeExtensionLock) {
            if (!mEdgeExtensions.containsKey(leash)) {
                // The animation leash has already been removed, so we don't want to attach the
                // edgeExtension layer and should immediately remove it instead.
                startTransaction.remove(edgeExtensionLayer);
                return;
            }

            startTransaction.setScale(edgeExtensionLayer, scaleX, scaleY);
            startTransaction.reparent(edgeExtensionLayer, leash);
            startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE);
            startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE);
            startTransaction.setPosition(edgeExtensionLayer, xPos, yPos);
            startTransaction.setPosition(edgeExtensionLayer, xPos, yPos);
            startTransaction.setVisibility(edgeExtensionLayer, true);
            startTransaction.setVisibility(edgeExtensionLayer, true);


        mEdgeExtensions.get(surfaceToExtend).add(edgeExtensionLayer);
            mEdgeExtensions.get(leash).add(edgeExtensionLayer);
        }
    }

    private float getScaleXForExtensionSurface(Rect edgeBounds, Rect extensionRect) {
        if (edgeBounds.width() == extensionRect.width()) {
            // Top or bottom edge extension, no need to scale the X axis of the extension surface.
            return 1;
        }
        if (edgeBounds.width() == 1) {
            // Left or right edge extension, scale the surface to be the extensionRect's width.
            return extensionRect.width();
        }
        }


        throw new RuntimeException("Unexpected edgeBounds and extensionRect widths");
    }

    private float getScaleYForExtensionSurface(Rect edgeBounds, Rect extensionRect) {
        if (edgeBounds.height() == extensionRect.height()) {
            // Left or right edge extension, no need to scale the Y axis of the extension surface.
            return 1;
        }
        if (edgeBounds.height() == 1) {
            // Top or bottom edge extension, scale the surface to be the extensionRect's height.
            return extensionRect.height();
        }

        throw new RuntimeException("Unexpected edgeBounds and extensionRect heights");
    }



    private static final class RunningAnimation {
    private static final class RunningAnimation {
        final AnimationSpec mAnimSpec;
        final AnimationSpec mAnimSpec;
        final SurfaceControl mLeash;
        final SurfaceControl mLeash;