Make BackgroundBlurDrawable a SystemApi
Bug: 177524486
Test: check that using the drawable in the PermissionController works
Change-Id: I0b881ec6e9a41c5aed3ca17589a6d66ced0539bf
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 683ed76..0c4ea3b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2578,6 +2578,18 @@
}
+package android.graphics.drawable {
+
+ public final class BackgroundBlurDrawable extends android.graphics.drawable.Drawable {
+ ctor @RequiresPermission(android.Manifest.permission.USE_BACKGROUND_BLUR) public BackgroundBlurDrawable();
+ method public void setBlurRadius(int);
+ method public void setColor(@ColorInt int);
+ method public void setCornerRadius(float);
+ method public void setCornerRadius(float, float, float, float);
+ }
+
+}
+
package android.hardware {
public final class Sensor {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 25967b3..6a0749e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9802,6 +9802,20 @@
}
}
+ private void notifyAttachForDrawables() {
+ if (mBackground != null) mBackground.onAttached(this);
+ if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
+ mForegroundInfo.mDrawable.onAttached(this);
+ }
+ }
+
+ private void notifyDetachForDrawables() {
+ if (mBackground != null) mBackground.onDetached(this);
+ if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
+ mForegroundInfo.mDrawable.onDetached(this);
+ }
+ }
+
private void setNotifiedContentCaptureAppeared() {
mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED;
mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED;
@@ -20653,6 +20667,7 @@
notifyEnterOrExitForAutoFillIfNeeded(true);
notifyAppearedOrDisappearedForContentCaptureIfNeeded(true);
+ notifyAttachForDrawables();
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -20702,6 +20717,7 @@
notifyEnterOrExitForAutoFillIfNeeded(false);
notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
+ notifyDetachForDrawables();
}
/**
@@ -23830,6 +23846,7 @@
if (mBackground != null) {
if (isAttachedToWindow()) {
mBackground.setVisible(false, false);
+ mBackground.onDetached(this);
}
mBackground.setCallback(null);
unscheduleDrawable(mBackground);
@@ -23879,6 +23896,7 @@
background.setState(getDrawableState());
}
if (isAttachedToWindow()) {
+ background.onAttached(this);
background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
}
@@ -24111,6 +24129,7 @@
if (mForegroundInfo.mDrawable != null) {
if (isAttachedToWindow()) {
mForegroundInfo.mDrawable.setVisible(false, false);
+ mForegroundInfo.mDrawable.onDetached(this);
}
mForegroundInfo.mDrawable.setCallback(null);
unscheduleDrawable(mForegroundInfo.mDrawable);
@@ -24128,6 +24147,7 @@
}
applyForegroundTint();
if (isAttachedToWindow()) {
+ foreground.onAttached(this);
foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
}
// Set callback last, since the view may still be initializing.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7e0ebbc..49bd344 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -117,6 +117,7 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RenderNode;
+import android.graphics.drawable.BackgroundBlurDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.hardware.display.DisplayManager;
@@ -188,7 +189,6 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.SomeArgs;
@@ -672,6 +672,14 @@
new BackgroundBlurDrawable.Aggregator(this);
/**
+ * @return {@link BackgroundBlurDrawable.Aggregator} for this instance.
+ */
+ @NonNull
+ public BackgroundBlurDrawable.Aggregator getBlurRegionAggregator() {
+ return mBlurRegionAggregator;
+ }
+
+ /**
* @return {@link ImeFocusController} for this instance.
*/
@NonNull
@@ -10048,13 +10056,6 @@
}
}
- /**
- * Creates a background blur drawable for the backing {@link Surface}.
- */
- public BackgroundBlurDrawable createBackgroundBlurDrawable() {
- return mBlurRegionAggregator.createBackgroundBlurDrawable(mContext);
- }
-
@Override
public void onDescendantUnbufferedRequested() {
mUnbufferedInputSource = mView.mUnbufferedInputSource;
diff --git a/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java b/graphics/java/android/graphics/drawable/BackgroundBlurDrawable.java
similarity index 78%
rename from core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
rename to graphics/java/android/graphics/drawable/BackgroundBlurDrawable.java
index 96dac56..7e75c5b 100644
--- a/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
+++ b/graphics/java/android/graphics/drawable/BackgroundBlurDrawable.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package com.android.internal.graphics.drawable;
+package android.graphics.drawable;
import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.Context;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
@@ -30,59 +31,71 @@
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RenderNode;
-import android.graphics.drawable.Drawable;
import android.util.ArrayMap;
import android.util.Log;
import android.view.SurfaceControl;
+import android.view.View;
import android.view.ViewRootImpl;
-import com.android.internal.R;
-
/**
* A drawable that keeps track of a blur region, pokes a hole under it, and propagates its state
* to SurfaceFlinger.
+ *
+ * @hide
*/
+@SystemApi
public final class BackgroundBlurDrawable extends Drawable {
-
private static final String TAG = BackgroundBlurDrawable.class.getSimpleName();
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final Aggregator mAggregator;
private final RenderNode mRenderNode;
private final Paint mPaint = new Paint();
private final Path mRectPath = new Path();
private final float[] mTmpRadii = new float[8];
private final SurfaceControl.BlurRegion mBlurRegion = new SurfaceControl.BlurRegion();
+ private Aggregator mAggregator;
+
// This will be called from a thread pool.
private final RenderNode.PositionUpdateListener mPositionUpdateListener =
new RenderNode.PositionUpdateListener() {
@Override
public void positionChanged(long frameNumber, int left, int top, int right,
int bottom) {
- synchronized (mAggregator) {
+ if (mAggregator == null) {
mBlurRegion.rect.set(left, top, right, bottom);
- mAggregator.onBlurRegionUpdated(BackgroundBlurDrawable.this, mBlurRegion);
+ } else {
+ synchronized (mAggregator) {
+ mBlurRegion.rect.set(left, top, right, bottom);
+ mAggregator.onBlurRegionUpdated(BackgroundBlurDrawable.this, mBlurRegion);
+ }
}
}
@Override
public void positionLost(long frameNumber) {
- synchronized (mAggregator) {
+ if (mAggregator == null) {
mBlurRegion.rect.setEmpty();
- mAggregator.onBlurRegionUpdated(BackgroundBlurDrawable.this, mBlurRegion);
+ } else {
+ synchronized (mAggregator) {
+ mBlurRegion.rect.setEmpty();
+ mAggregator.onBlurRegionUpdated(BackgroundBlurDrawable.this, mBlurRegion);
+ }
}
}
};
- private BackgroundBlurDrawable(Aggregator aggregator) {
- mAggregator = aggregator;
+ @RequiresPermission(android.Manifest.permission.USE_BACKGROUND_BLUR)
+ public BackgroundBlurDrawable() {
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
mPaint.setColor(Color.TRANSPARENT);
mRenderNode = new RenderNode("BackgroundBlurDrawable");
mRenderNode.addPositionUpdateListener(mPositionUpdateListener);
}
+ /**
+ * @hide
+ */
@Override
public void draw(@NonNull Canvas canvas) {
if (mRectPath.isEmpty() || !isVisible() || getAlpha() == 0) {
@@ -100,6 +113,9 @@
mPaint.setColor(color);
}
+ /**
+ * @hide
+ */
@Override
public boolean setVisible(boolean visible, boolean restart) {
boolean changed = super.setVisible(visible, restart);
@@ -109,6 +125,9 @@
return changed;
}
+ /**
+ * @hide
+ */
@Override
public void setAlpha(int alpha) {
mBlurRegion.alpha = alpha / 255f;
@@ -139,12 +158,12 @@
*/
public void setCornerRadius(float cornerRadiusTL, float cornerRadiusTR, float cornerRadiusBL,
float cornerRadiusBR) {
- synchronized (mAggregator) {
+ maybeRunSynchronized(() -> {
mBlurRegion.cornerRadiusTL = cornerRadiusTL;
mBlurRegion.cornerRadiusTR = cornerRadiusTR;
mBlurRegion.cornerRadiusBL = cornerRadiusBL;
mBlurRegion.cornerRadiusBR = cornerRadiusBR;
- }
+ });
updatePath();
invalidateSelf();
}
@@ -157,12 +176,13 @@
}
private void updatePath() {
- synchronized (mAggregator) {
+ maybeRunSynchronized(() -> {
mTmpRadii[0] = mTmpRadii[1] = mBlurRegion.cornerRadiusTL;
mTmpRadii[2] = mTmpRadii[3] = mBlurRegion.cornerRadiusTR;
mTmpRadii[4] = mTmpRadii[5] = mBlurRegion.cornerRadiusBL;
mTmpRadii[6] = mTmpRadii[7] = mBlurRegion.cornerRadiusBR;
- }
+ });
+
mRectPath.reset();
if (getAlpha() == 0 || !isVisible()) {
return;
@@ -172,19 +192,62 @@
Path.Direction.CW);
}
+ /**
+ * @hide
+ */
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
throw new IllegalArgumentException("not implemented");
}
+ /**
+ * @hide
+ */
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
/**
+ * @hide
+ */
+ @Override
+ public void onAttached(@NonNull View v) {
+ super.onAttached(v);
+ mAggregator = v.getViewRootImpl().getBlurRegionAggregator();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDetached(@NonNull View v) {
+ super.onDetached(v);
+ mAggregator = null;
+ }
+
+ /**
+ * The Aggregator is called from the RenderThread to aggregate all blur regions and send them
+ * to SurfaceFlinger. Since the BackgroundBlurDrawable could be updated at any time from the
+ * main thread, we need to synchronize the two threads. The BackgroundBlurDrawable may be
+ * instantiated before the ViewRootImpl is created, i.e. before the Aggregator is created.
+ * In that case, updates are not synchronized.
+ */
+ private void maybeRunSynchronized(Runnable r) {
+ if (mAggregator == null) {
+ r.run();
+ } else {
+ synchronized (mAggregator) {
+ r.run();
+ }
+ }
+ }
+
+ /**
* Responsible for keeping track of all blur regions of a {@link ViewRootImpl} and posting a
* message when it's time to propagate them.
+ *
+ * @hide
*/
public static final class Aggregator {
@@ -199,16 +262,6 @@
}
/**
- * Creates a blur region with default radius.
- */
- public BackgroundBlurDrawable createBackgroundBlurDrawable(Context context) {
- BackgroundBlurDrawable drawable = new BackgroundBlurDrawable(this);
- drawable.setBlurRadius(context.getResources().getDimensionPixelSize(
- R.dimen.default_background_blur_radius));
- return drawable;
- }
-
- /**
* Called from RenderThread only, already locked.
* @param drawable
* @param blurRegion
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 28b3b04..7f22dc2 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1465,6 +1465,24 @@
}
/**
+ * Notifies the drawable that it has been attached.
+ *
+ * @param v The view that it is attached to
+ * @hide
+ */
+ public void onAttached(View v) {
+ }
+
+ /**
+ * Notifies the drawable that it has been detached.
+ *
+ * @param v The view that it is detached from
+ * @hide
+ */
+ public void onDetached(View v) {
+ }
+
+ /**
* Sets the source override density for this Drawable. If non-zero, this density is to be used
* for any calls to {@link Resources#getDrawableForDensity(int, int, Theme)} or
* {@link Resources#getValueForDensity(int, int, TypedValue, boolean)}.