Support frame-synchronized clipping on SurfaceView
Bug: 123306815
Test: See ag/9384030, manual test of bubbles expand collapse animation
Change-Id: I5350501667fe729a0c668e8f6edaf30070a2e1ec
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index e891828..b56c00e 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -29,6 +29,7 @@
import android.content.Intent;
import android.graphics.Insets;
import android.graphics.Matrix;
+import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
@@ -101,6 +102,8 @@
private Insets mForwardedInsets;
+ private float mCornerRadius;
+
public ActivityView(Context context) {
this(context, null /* attrs */);
}
@@ -204,6 +207,45 @@
}
/**
+ * @hide
+ */
+ public float getCornerRadius() {
+ return mSurfaceView.getCornerRadius();
+ }
+
+ /**
+ * Control whether the surface is clipped to the same bounds as the View. If true, then
+ * the bounds set by {@link #setSurfaceClipBounds(Rect)} are applied to the surface as
+ * window-crop.
+ *
+ * @param clippingEnabled whether to enable surface clipping
+ * @hide
+ */
+ public void setSurfaceClippingEnabled(boolean clippingEnabled) {
+ mSurfaceView.setEnableSurfaceClipping(clippingEnabled);
+ }
+
+ /**
+ * Sets an area on the contained surface to which it will be clipped
+ * when it is drawn. Setting the value to null will remove the clip bounds
+ * and the surface will draw normally, using its full bounds.
+ *
+ * @param clipBounds The rectangular area, in the local coordinates of
+ * this view, to which future drawing operations will be clipped.
+ * @hide
+ */
+ public void setSurfaceClipBounds(Rect clipBounds) {
+ mSurfaceView.setClipBounds(clipBounds);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean getSurfaceClipBounds(Rect outRect) {
+ return mSurfaceView.getClipBounds(outRect);
+ }
+
+ /**
* Launch a new activity into this container.
* <p>Activity resolved by the provided {@link Intent} must have
* {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 90e69f3..9acebe1 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -166,6 +166,7 @@
boolean mUseAlpha = false;
float mSurfaceAlpha = 1f;
+ boolean mClipSurfaceToBounds;
@UnsupportedAppUsage
boolean mHaveFrame = false;
@@ -554,9 +555,52 @@
super.dispatchDraw(canvas);
}
+ /**
+ * Control whether the surface is clipped to the same bounds as the View. If true, then
+ * the bounds set by {@link #setClipBounds(Rect)} are applied to the surface as window-crop.
+ *
+ * @param enabled whether to enable surface clipping
+ * @hide
+ */
+ public void setEnableSurfaceClipping(boolean enabled) {
+ mClipSurfaceToBounds = enabled;
+ invalidate();
+ }
+
+ @Override
+ public void setClipBounds(Rect clipBounds) {
+ super.setClipBounds(clipBounds);
+
+ if (!mClipSurfaceToBounds) {
+ return;
+ }
+
+ // When cornerRadius is non-zero, a draw() is required to update
+ // the viewport (rounding the corners of the clipBounds).
+ if (mCornerRadius > 0f && !isAboveParent()) {
+ invalidate();
+ }
+
+ if (mSurfaceControl != null) {
+ if (mClipBounds != null) {
+ mTmpRect.set(mClipBounds);
+ } else {
+ mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
+ }
+ SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(this);
+ applier.scheduleApply(
+ new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(mSurfaceControl)
+ .withWindowCrop(mTmpRect)
+ .build());
+ }
+ }
+
private void clearSurfaceViewPort(Canvas canvas) {
if (mCornerRadius > 0f) {
canvas.getClipBounds(mTmpRect);
+ if (mClipSurfaceToBounds && mClipBounds != null) {
+ mTmpRect.intersect(mClipBounds);
+ }
canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
mCornerRadius, mCornerRadius, mRoundedViewportPaint);
} else {
@@ -582,6 +626,16 @@
}
/**
+ * Returns the corner radius for the SurfaceView.
+
+ * @return the radius of the corners in pixels
+ * @hide
+ */
+ public float getCornerRadius() {
+ return mCornerRadius;
+ }
+
+ /**
* Control whether the surface view's surface is placed on top of another
* regular surface view in the window (but still behind the window itself).
* This is typically used to place overlays on top of an underlying media
@@ -832,7 +886,11 @@
// crop the buffer to the surface size since the buffer producer may
// use SCALING_MODE_SCALE and submit a larger size than the surface
// size.
- mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight);
+ if (mClipSurfaceToBounds && mClipBounds != null) {
+ mSurfaceControl.setWindowCrop(mClipBounds);
+ } else {
+ mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight);
+ }
}
mSurfaceControl.setCornerRadius(mCornerRadius);
if (sizeChanged && !creating) {