Merge changes from topic "blur_system_api"

* changes:
  Make BackgroundBlurDrawable a SystemApi
  Make window background blurs SystemApi
  Add permission for blur SystemApi
diff --git a/core/api/current.txt b/core/api/current.txt
index ba49b67..27660ec 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1055,11 +1055,11 @@
     field public static final int parentActivityName = 16843687; // 0x10103a7
     field @Deprecated public static final int password = 16843100; // 0x101015c
     field public static final int path = 16842794; // 0x101002a
-    field public static final int pathAdvancedPattern = 16844319; // 0x101061f
+    field public static final int pathAdvancedPattern = 16844320; // 0x1010620
     field public static final int pathData = 16843781; // 0x1010405
     field public static final int pathPattern = 16842796; // 0x101002c
     field public static final int pathPrefix = 16842795; // 0x101002b
-    field public static final int pathSuffix = 16844317; // 0x101061d
+    field public static final int pathSuffix = 16844318; // 0x101061e
     field public static final int patternPathData = 16843978; // 0x10104ca
     field public static final int permission = 16842758; // 0x1010006
     field public static final int permissionFlags = 16843719; // 0x10103c7
@@ -1152,7 +1152,7 @@
     field public static final int reqNavigation = 16843306; // 0x101022a
     field public static final int reqTouchScreen = 16843303; // 0x1010227
     field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603
-    field public static final int requireDeviceScreenOn = 16844316; // 0x101061c
+    field public static final int requireDeviceScreenOn = 16844317; // 0x101061d
     field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
@@ -1293,10 +1293,10 @@
     field public static final int spotShadowAlpha = 16843967; // 0x10104bf
     field public static final int src = 16843033; // 0x1010119
     field public static final int ssp = 16843747; // 0x10103e3
-    field public static final int sspAdvancedPattern = 16844320; // 0x1010620
+    field public static final int sspAdvancedPattern = 16844321; // 0x1010621
     field public static final int sspPattern = 16843749; // 0x10103e5
     field public static final int sspPrefix = 16843748; // 0x10103e4
-    field public static final int sspSuffix = 16844318; // 0x101061e
+    field public static final int sspSuffix = 16844319; // 0x101061f
     field public static final int stackFromBottom = 16843005; // 0x10100fd
     field public static final int stackViewStyle = 16843838; // 0x101043e
     field public static final int starStyle = 16842882; // 0x1010082
@@ -49461,7 +49461,6 @@
     field public static final int FLAGS_CHANGED = 4; // 0x4
     field public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 1; // 0x1
     field public static final int FLAG_ALT_FOCUSABLE_IM = 131072; // 0x20000
-    field @Deprecated public static final int FLAG_BLUR_BEHIND = 4; // 0x4
     field public static final int FLAG_DIM_BEHIND = 2; // 0x2
     field @Deprecated public static final int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
     field @Deprecated public static final int FLAG_DITHER = 4096; // 0x1000
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d91ea2c..a7602f8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -254,6 +254,7 @@
     field public static final String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
     field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
     field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
+    field public static final String USE_BACKGROUND_BLUR = "android.permission.USE_BACKGROUND_BLUR";
     field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
     field public static final String WHITELIST_AUTO_REVOKE_PERMISSIONS = "android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS";
     field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
@@ -285,6 +286,8 @@
     field public static final int sdkVersion = 16844304; // 0x1010610
     field public static final int supportsAmbientMode = 16844173; // 0x101058d
     field public static final int userRestriction = 16844164; // 0x1010584
+    field public static final int windowBackgroundBlurEnabled = 16844316; // 0x101061c
+    field public static final int windowBackgroundBlurRadius = 16844315; // 0x101061b
   }
 
   public static final class R.bool {
@@ -2579,6 +2582,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 {
@@ -13363,9 +13378,11 @@
   public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
     method public final long getUserActivityTimeout();
     method public final void setUserActivityTimeout(long);
+    field @RequiresPermission(android.Manifest.permission.USE_BACKGROUND_BLUR) public static final int FLAG_BLUR_BEHIND = 4; // 0x4
     field @RequiresPermission(android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS) public static final int SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000
     field @RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW) public static final int SYSTEM_FLAG_SHOW_FOR_ALL_USERS = 16; // 0x10
     field @RequiresPermission(android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY) public static final int SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY = 8; // 0x8
+    field @RequiresPermission(android.Manifest.permission.USE_BACKGROUND_BLUR) public int backgroundBlurRadius;
   }
 
   @IntDef(flag=true, prefix={"SYSTEM_FLAG_"}, value={android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS, android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowManager.LayoutParams.SystemFlags {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b8840ba..04fe897 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 426edbc..d694962 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -115,6 +115,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;
@@ -186,7 +187,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;
@@ -670,6 +670,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
@@ -10046,13 +10054,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/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 45fa41b..c2d990a 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1508,9 +1508,13 @@
          *  Use {@link #dimAmount} to control the amount of dim. */
         public static final int FLAG_DIM_BEHIND        = 0x00000002;
 
-        /** Window flag: blur everything behind this window.
-         * @deprecated Blurring is no longer supported. */
-        @Deprecated
+        /** Window flag: enable blurring behind this window.
+         * To set the amount of blur, use {@link #backgroundBlurRadius}
+         *
+         * @hide
+         */
+        @RequiresPermission(permission.USE_BACKGROUND_BLUR)
+        @SystemApi
         public static final int FLAG_BLUR_BEHIND        = 0x00000004;
 
         /** Window flag: this window won't ever get key input focus, so the
@@ -3225,10 +3229,14 @@
         public boolean preferMinimalPostProcessing = false;
 
         /**
-         * Indicates that this window wants to have blurred content behind it.
+         * When {@link FLAG_BLUR_BEHIND} is set, this is the amount of blur in pixels that this
+         * window will use to blur behind itself.
+         * The range is from 0, which means no blur, to 150.
          *
          * @hide
          */
+        @SystemApi
+        @RequiresPermission(permission.USE_BACKGROUND_BLUR)
         public int backgroundBlurRadius = 0;
 
         /**
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 141dc79..3be841c 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2540,8 +2540,14 @@
             }
         }
 
-        params.backgroundBlurRadius = a.getDimensionPixelSize(
-                R.styleable.Window_windowBackgroundBlurRadius, 0);
+        if (a.getBoolean(R.styleable.Window_windowBackgroundBlurEnabled, false)) {
+            if ((getForcedWindowFlags() & WindowManager.LayoutParams.FLAG_BLUR_BEHIND) == 0) {
+                params.flags |= WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
+            }
+
+            params.backgroundBlurRadius = a.getDimensionPixelSize(
+                        android.R.styleable.Window_windowBackgroundBlurRadius, 0);
+        }
 
         if (params.windowAnimations == 0) {
             params.windowAnimations = a.getResourceId(
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 253aece..c9579ed 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4087,6 +4087,11 @@
     <permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to use background blur.
+         @hide -->
+    <permission android:name="android.permission.USE_BACKGROUND_BLUR"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to control the lights on the device.
          @hide
          @SystemApi
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index be7ecfc..9bfd5f5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -87,6 +87,16 @@
              theme does not set this value, meaning it is based on whether the
              window is floating. -->
         <attr name="backgroundDimEnabled" format="boolean" />
+        <!-- When windowBackgroundBlurEnabled is set, this is the amount of blur to apply
+             behind the window. The range is from 0, which means no blur, to 150.
+             @hide @SystemApi -->
+        <attr name="windowBackgroundBlurRadius" format="dimension"/>
+        <!-- If set, the area behind the window will be blurred with radius
+             windowBackgroundBlurRadius.
+             @hide @SystemApi -->
+        <attr name="windowBackgroundBlurEnabled" format="boolean" />
+
+
         <!-- Color of background imagery used for popup windows. -->
         <attr name="colorPopupBackground" format="color" />
         <!-- Color used for list divider. -->
@@ -1964,6 +1974,8 @@
         <attr name="textColor" />
         <attr name="backgroundDimEnabled" />
         <attr name="backgroundDimAmount" />
+        <attr name="windowBackgroundBlurEnabled" />
+        <attr name="windowBackgroundBlurRadius" />
         <attr name="windowActionBar" />
         <attr name="windowActionModeOverlay" />
         <attr name="windowActionBarOverlay" />
@@ -2181,10 +2193,6 @@
              the decor view. -->
         <attr name="windowLightNavigationBar" format="boolean" />
 
-        <!-- @hide -->
-        <attr name="windowBackgroundBlurRadius" format="dimension"/>
-
-
         <!-- Controls how the window is laid out if there is a {@code DisplayCutout}.
         <p>
         Defaults to {@code default}.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index bac50f1..ddf3c5f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3049,7 +3049,10 @@
     <public name="windowLayoutAffinity" />
     <public name="canPauseRecording" />
     <!-- @hide -->
+    <!-- @hide @SystemApi -->
     <public name="windowBackgroundBlurRadius"/>
+    <!-- @hide @SystemApi -->
+    <public name="windowBackgroundBlurEnabled"/>
     <public name="requireDeviceScreenOn" />
     <public name="pathSuffix" />
     <public name="sspSuffix" />
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)}.
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e036d87..39fbb34 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -116,6 +116,7 @@
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.MONITOR_INPUT" />
     <uses-permission android:name="android.permission.INPUT_CONSUMER" />
+    <uses-permission android:name="android.permission.USE_BACKGROUND_BLUR" />
 
     <!-- DreamManager -->
     <uses-permission android:name="android.permission.READ_DREAM_STATE" />
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index ff2509b..b1606c5 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -22,6 +22,7 @@
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY;
+import static android.Manifest.permission.USE_BACKGROUND_BLUR;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
 import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
@@ -108,6 +109,7 @@
     final boolean mCanCreateSystemApplicationOverlay;
     final boolean mCanHideNonSystemOverlayWindows;
     final boolean mCanAcquireSleepToken;
+    final boolean mCanUseBackgroundBlur;
     private AlertWindowNotification mAlertWindowNotification;
     private boolean mShowingAlertWindowNotificationAllowed;
     private boolean mClientDead = false;
@@ -136,6 +138,8 @@
                 && !mService.mAtmInternal.isCallerRecents(mUid);
         mCanAcquireSleepToken = service.mContext.checkCallingOrSelfPermission(DEVICE_POWER)
                 == PERMISSION_GRANTED;
+        mCanUseBackgroundBlur = service.mContext.checkCallingOrSelfPermission(USE_BACKGROUND_BLUR)
+                == PERMISSION_GRANTED;
         mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications;
         mDragDropController = mService.mDragDropController;
         StringBuilder sb = new StringBuilder();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a034bac9..4156ed6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1620,7 +1620,7 @@
 
             final WindowState win = new WindowState(this, session, client, token, parentWindow,
                     appOp[0], attrs, viewVisibility, session.mUid, userId,
-                    session.mCanAddInternalSystemWindow);
+                    session.mCanAddInternalSystemWindow, session.mCanUseBackgroundBlur);
             if (win.mDeathRecipient == null) {
                 // Client has apparently died, so there is no reason to
                 // continue.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 13b9765..b7602fe 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -45,6 +45,7 @@
 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
@@ -297,6 +298,8 @@
     final int mShowUserId;
     /** The owner has {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} */
     final boolean mOwnerCanAddInternalSystemWindow;
+    /** The owner has {@link android.Manifest.permission#USE_BACKGROUND_BLUR} */
+    final boolean mOwnerCanUseBackgroundBlur;
     final WindowId mWindowId;
     WindowToken mToken;
     // The same object as mToken if this is an app window and null for non-app windows.
@@ -854,9 +857,11 @@
 
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
             WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
-            int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow) {
+            int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
+            boolean ownerCanUseBackgroundBlur) {
         this(service, s, c, token, parentWindow, appOp, a, viewVisibility, ownerId, showUserId,
-                ownerCanAddInternalSystemWindow, new PowerManagerWrapper() {
+                ownerCanAddInternalSystemWindow, ownerCanUseBackgroundBlur,
+                new PowerManagerWrapper() {
                     @Override
                     public void wakeUp(long time, @WakeReason int reason, String details) {
                         service.mPowerManager.wakeUp(time, reason, details);
@@ -872,7 +877,7 @@
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
             WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
             int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
-            PowerManagerWrapper powerManagerWrapper) {
+            boolean ownerCanUseBackgroundBlur, PowerManagerWrapper powerManagerWrapper) {
         super(service);
         mTmpTransaction = service.mTransactionFactory.get();
         mSession = s;
@@ -883,6 +888,7 @@
         mOwnerUid = ownerId;
         mShowUserId = showUserId;
         mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
+        mOwnerCanUseBackgroundBlur = ownerCanUseBackgroundBlur;
         mWindowId = new WindowId(this);
         mAttrs.copyFrom(a);
         mLastSurfaceInsets.set(mAttrs.surfaceInsets);
@@ -5245,7 +5251,7 @@
         if (!mAnimatingExit && mAppDied) {
             mIsDimming = true;
             getDimmer().dimAbove(getSyncTransaction(), this, DEFAULT_DIM_AMOUNT_DEAD_WINDOW);
-        } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || mAttrs.backgroundBlurRadius != 0)
+        } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || isBlurEnabled())
                    && isVisibleNow() && !mHidden) {
             // Only show the Dimmer when the following is satisfied:
             // 1. The window has the flag FLAG_DIM_BEHIND or background blur is requested
@@ -5254,11 +5260,15 @@
             // 4. The WS is not hidden.
             mIsDimming = true;
             final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
-            getDimmer().dimBelow(
-                    getSyncTransaction(), this, mAttrs.dimAmount, mAttrs.backgroundBlurRadius);
+            final int blurRadius = isBlurEnabled() ? mAttrs.backgroundBlurRadius : 0;
+            getDimmer().dimBelow(getSyncTransaction(), this, dimAmount, blurRadius);
         }
     }
 
+    private boolean isBlurEnabled() {
+        return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 && mOwnerCanUseBackgroundBlur;
+    }
+
 
     /**
      * Notifies SF about the priority of the window, if it changed. SF then uses this information
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index 6f5a874..5c67db7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -514,7 +514,7 @@
         return new WindowState(mWm, mock(Session.class), new TestIWindow(), token,
                 null /* parentWindow */, 0 /* appOp */, new WindowManager.LayoutParams(),
                 View.VISIBLE, 0 /* ownerId */, 0 /* showUserId */,
-                false /* ownerCanAddInternalSystemWindow */);
+                false /* ownerCanAddInternalSystemWindow */, false /* ownerCanUseBackgroundBlur */);
     }
 
     private WindowToken createWindowToken(int type) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 8b93372..c85991d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -340,7 +340,7 @@
 
         final WindowState w = new WindowState(service, session, iWindow, token, parent,
                 OP_NONE, attrs, VISIBLE, ownerId, userId,
-                ownerCanAddInternalSystemWindow,
+                ownerCanAddInternalSystemWindow, false /* ownerCanUseBackgroundBlur */,
                 powerManagerWrapper);
         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
         // adding it to the token...
@@ -1213,7 +1213,8 @@
         TestWindowState(WindowManagerService service, Session session, IWindow window,
                 WindowManager.LayoutParams attrs, WindowToken token) {
             super(service, session, window, token, null, OP_NONE, attrs, 0, 0, 0,
-                    false /* ownerCanAddInternalSystemWindow */);
+                    false /* ownerCanAddInternalSystemWindow */,
+                    false /* ownerCanUseBackgroundBlur */);
         }
 
         @Override