summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimationRunner.java110
1 files changed, 75 insertions, 35 deletions
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 83be73a47eb4..4068a97a881a 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -16,6 +16,7 @@
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.view.Choreographer.CALLBACK_TRAVERSAL;
import static android.view.Choreographer.getSfInstance;
@@ -26,14 +27,13 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
-import android.graphics.Canvas;
import android.graphics.Insets;
-import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.power.Boost;
import android.os.Handler;
import android.os.PowerManagerInternal;
+import android.os.Trace;
import android.util.ArrayMap;
import android.util.Log;
import android.view.Choreographer;
@@ -50,6 +50,8 @@ import com.android.server.AnimationThread;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import java.util.ArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.function.Supplier;
/**
@@ -83,6 +85,12 @@ class SurfaceAnimationRunner {
private final PowerManagerInternal mPowerManagerInternal;
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")
@VisibleForTesting
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
// windows we want to screenshot and extend as children.
- t.addTransactionCommittedListener(Runnable::run, () -> {
+ t.addTransactionCommittedListener(mEdgeExtensionExecutor, () -> {
final WindowAnimationSpec animationSpec = a.asWindowAnimationSpec();
final Transaction edgeExtensionCreationTransaction = new Transaction();
@@ -403,30 +411,17 @@ class SurfaceAnimationRunner {
private void createExtensionSurface(SurfaceControl leash, Rect edgeBounds,
Rect extensionRect, int xPos, int yPos, String layerName,
Transaction startTransaction) {
- synchronized (mEdgeExtensionLock) {
- if (!mEdgeExtensions.containsKey(leash)) {
- // Animation leash has already been removed so we shouldn't perform any extension
- return;
- }
- createExtensionSurfaceLocked(leash, edgeBounds, extensionRect, xPos, yPos, layerName,
- startTransaction);
- }
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createExtensionSurface");
+ doCreateExtensionSurface(leash, edgeBounds, extensionRect, xPos, yPos, layerName,
+ 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,
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 =
- new SurfaceControl.LayerCaptureArgs.Builder(surfaceToExtend)
+ new SurfaceControl.LayerCaptureArgs.Builder(leash /* surfaceToExtend */)
.setSourceCrop(edgeBounds)
.setFrameScale(1)
.setPixelFormat(PixelFormat.RGBA_8888)
@@ -437,31 +432,76 @@ class SurfaceAnimationRunner {
SurfaceControl.captureLayers(captureArgs);
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 - "
+ "edge buffer is null");
return;
}
- android.graphics.BitmapShader shader =
- new android.graphics.BitmapShader(edgeBuffer.asBitmap(),
- android.graphics.Shader.TileMode.CLAMP,
- android.graphics.Shader.TileMode.CLAMP);
- final Paint paint = new Paint();
- paint.setShader(shader);
+ final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder()
+ .setName(layerName)
+ .setHidden(true)
+ .setCallsite("DefaultTransitionHandler#startAnimation")
+ .setOpaque(true)
+ .setBufferSize(edgeBounds.width(), edgeBounds.height())
+ .build();
final Surface surface = new Surface(edgeExtensionLayer);
- Canvas c = surface.lockHardwareCanvas();
- c.drawRect(extensionRect, paint);
- surface.unlockCanvasAndPost(c);
+ surface.attachAndQueueBufferWithColorSpace(edgeBuffer.getHardwareBuffer(),
+ edgeBuffer.getColorSpace());
surface.release();
- startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE);
- startTransaction.setPosition(edgeExtensionLayer, xPos, yPos);
- startTransaction.setVisibility(edgeExtensionLayer, true);
+ final float scaleX = getScaleXForExtensionSurface(edgeBounds, extensionRect);
+ final float scaleY = getScaleYForExtensionSurface(edgeBounds, extensionRect);
- mEdgeExtensions.get(surfaceToExtend).add(edgeExtensionLayer);
+ 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.setPosition(edgeExtensionLayer, xPos, yPos);
+ startTransaction.setVisibility(edgeExtensionLayer, true);
+
+ 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 {
final AnimationSpec mAnimSpec;
final SurfaceControl mLeash;