summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Galia Peycheva <galinap@google.com> 2021-01-22 21:46:41 +0100
committer Galia Peycheva <galinap@google.com> 2021-02-12 16:17:12 +0100
commit792b9eb8dc86af32841c3347ea1ef88dde0f9a87 (patch)
tree4ca16c152e3fa2446f4f82e91d2394e398387737
parent8b8c4301ac102b50d7ab4461c0773f66228281ba (diff)
Add window background blur public api
This CL exposes Window#setBackgroundBlurRadius as public Api. It creates a region behind the window (with the dimensions of the window background drawable), which is blurred with the given radius. It also adds windowBackgroundBlurRadius dimension as an xml attribute on Window. Bug: 167166562 Bug: 177524486 Test: m Test: m doc-comment-check-docs Test: atest BlurTests Change-Id: I5c0ff3c7fc7a64e6b2e2339eccc23374ec3b5fd9
-rw-r--r--core/api/current.txt2
-rw-r--r--core/java/android/view/Window.java24
-rw-r--r--core/java/com/android/internal/policy/DecorView.java55
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java14
-rw-r--r--core/res/res/values/attrs.xml7
-rw-r--r--core/res/res/values/public.xml1
6 files changed, 96 insertions, 7 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index c72608f89fac..2ba2bb2903a1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1614,6 +1614,7 @@ package android {
field public static final int windowAllowReturnTransitionOverlap = 16843835; // 0x101043b
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
+ field public static final int windowBackgroundBlurRadius = 16844331; // 0x101062b
field public static final int windowBackgroundFallback = 16844035; // 0x1010503
field public static final int windowBlurBehindEnabled = 16844316; // 0x101061c
field public static final int windowBlurBehindRadius = 16844315; // 0x101061b
@@ -49353,6 +49354,7 @@ package android.view {
method public void setAllowEnterTransitionOverlap(boolean);
method public void setAllowReturnTransitionOverlap(boolean);
method public void setAttributes(android.view.WindowManager.LayoutParams);
+ method public void setBackgroundBlurRadius(int);
method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
method public void setBackgroundDrawableResource(@DrawableRes int);
method public void setCallback(android.view.Window.Callback);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index af18293398da..4ecdd78f5a42 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1703,6 +1703,30 @@ public abstract class Window {
public abstract void setBackgroundDrawable(Drawable drawable);
/**
+ * Blurs the screen behind the window within the bounds of the window.
+ *
+ * The density of the blur is set by the blur radius. The radius defines the size
+ * of the neighbouring area, from which pixels will be averaged to form the final
+ * color for each pixel. The operation approximates a Gaussian blur.
+ * A radius of 0 means no blur. The higher the radius, the denser the blur.
+ *
+ * The window background drawable is drawn on top of the blurred region. The blur
+ * region bounds and rounded corners will mimic those of the background drawable.
+ *
+ * For the blur region to be visible, the window has to be translucent. See
+ * {@link android.R.styleable#Window_windowIsTranslucent}.
+ *
+ * Note the difference with {@link android.view.WindowManager.LayoutParams#blurBehindRadius},
+ * which blurs the whole screen behind the window. Background blur blurs the screen behind
+ * only within the bounds of the window.
+ *
+ * @param blurRadius The blur radius to use for window background blur in pixels
+ *
+ * @see android.R.styleable#Window_windowBackgroundBlurRadius
+ */
+ public void setBackgroundBlurRadius(int blurRadius) {}
+
+ /**
* Set the value for a drawable feature of this window, from a resource
* identifier. You must have called requestFeature(featureId) before
* calling this function.
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index adebde016bb3..9840013935f8 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -110,6 +110,7 @@ import android.widget.FrameLayout;
import android.widget.PopupWindow;
import com.android.internal.R;
+import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
import com.android.internal.policy.PhoneWindow.PanelFeatureState;
import com.android.internal.policy.PhoneWindow.PhoneWindowMenuCallback;
import com.android.internal.view.FloatingActionMode;
@@ -255,6 +256,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
private Drawable mOriginalBackgroundDrawable;
private Drawable mLastOriginalBackgroundDrawable;
private Drawable mResizingBackgroundDrawable;
+ private BackgroundBlurDrawable mBackgroundBlurDrawable;
/**
* Temporary holder for a window background when it is set before {@link #mWindow} is
@@ -280,9 +282,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
private final Paint mLegacyNavigationBarBackgroundPaint = new Paint();
private Insets mBackgroundInsets = Insets.NONE;
private Insets mLastBackgroundInsets = Insets.NONE;
+ private int mLastBackgroundBlurRadius = 0;
private boolean mDrawLegacyNavigationBarBackground;
private PendingInsetsController mPendingInsetsController = new PendingInsetsController();
+ private final ViewTreeObserver.OnPreDrawListener mBackgroundBlurOnPreDrawListener = () -> {
+ updateBackgroundBlur();
+ return true;
+ };
DecorView(Context context, int featureId, PhoneWindow window,
WindowManager.LayoutParams params) {
@@ -1263,18 +1270,27 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
if (mBackgroundInsets == null) {
mBackgroundInsets = Insets.NONE;
}
+
if (mBackgroundInsets.equals(mLastBackgroundInsets)
+ && mWindow.mBackgroundBlurRadius == mLastBackgroundBlurRadius
&& mLastOriginalBackgroundDrawable == mOriginalBackgroundDrawable) {
return;
}
- if (mOriginalBackgroundDrawable == null || mBackgroundInsets.equals(Insets.NONE)) {
- // Call super since we are intercepting setBackground on this class.
- super.setBackgroundDrawable(mOriginalBackgroundDrawable);
- } else {
+ Drawable destDrawable = mOriginalBackgroundDrawable;
+ if (mWindow.mBackgroundBlurRadius > 0 && getViewRootImpl() != null
+ && mWindow.isTranslucent()) {
+ if (mBackgroundBlurDrawable == null) {
+ mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable();
+ }
+ destDrawable = new LayerDrawable(new Drawable[] {mBackgroundBlurDrawable,
+ mOriginalBackgroundDrawable});
+ mLastBackgroundBlurRadius = mWindow.mBackgroundBlurRadius;
+ }
- // Call super since we are intercepting setBackground on this class.
- super.setBackgroundDrawable(new InsetDrawable(mOriginalBackgroundDrawable,
+
+ if (destDrawable != null && !mBackgroundInsets.equals(Insets.NONE)) {
+ destDrawable = new InsetDrawable(destDrawable,
mBackgroundInsets.left, mBackgroundInsets.top,
mBackgroundInsets.right, mBackgroundInsets.bottom) {
@@ -1286,12 +1302,32 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
public boolean getPadding(Rect padding) {
return getDrawable().getPadding(padding);
}
- });
+ };
}
+
+ // Call super since we are intercepting setBackground on this class.
+ super.setBackgroundDrawable(destDrawable);
+
mLastBackgroundInsets = mBackgroundInsets;
mLastOriginalBackgroundDrawable = mOriginalBackgroundDrawable;
}
+ private void updateBackgroundBlur() {
+ if (mBackgroundBlurDrawable == null) return;
+
+ // If the blur radius is 0, the blur region won't be sent to surface flinger, so we don't
+ // need to calculate the corner radius.
+ if (mWindow.mBackgroundBlurRadius > 0) {
+ if (mOriginalBackgroundDrawable != null) {
+ final Outline outline = new Outline();
+ mOriginalBackgroundDrawable.getOutline(outline);
+ mBackgroundBlurDrawable.setCornerRadius(outline.mMode == Outline.MODE_ROUND_RECT
+ ? outline.getRadius() : 0);
+ }
+ }
+ mBackgroundBlurDrawable.setBlurRadius(mWindow.mBackgroundBlurRadius);
+ }
+
@Override
public Drawable getBackground() {
return mOriginalBackgroundDrawable;
@@ -1722,6 +1758,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
cb.onAttachedToWindow();
}
+ getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
+ updateBackgroundDrawable();
+
if (mFeatureId == -1) {
/*
* The main window has been attached, try to restore any panels
@@ -1755,6 +1794,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
cb.onDetachedFromWindow();
}
+ getViewTreeObserver().removeOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
+
if (mWindow.mDecorContentParent != null) {
mWindow.mDecorContentParent.dismissPopups();
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 5df175e8aee5..d06413c3ca15 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -258,6 +258,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
Drawable mBackgroundDrawable = null;
Drawable mBackgroundFallbackDrawable = null;
+ int mBackgroundBlurRadius = 0;
+
private boolean mLoadElevation = true;
private float mElevation;
@@ -1523,6 +1525,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
@Override
+ public final void setBackgroundBlurRadius(int blurRadius) {
+ super.setBackgroundBlurRadius(blurRadius);
+ if (getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_CROSS_LAYER_BLUR)) {
+ mBackgroundBlurRadius = Math.max(blurRadius, 0);
+ }
+ }
+
+ @Override
public final void setFeatureDrawableResource(int featureId, int resId) {
if (resId != 0) {
DrawableFeatureState st = getDrawableState(featureId, true);
@@ -2549,6 +2560,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
android.R.styleable.Window_windowBlurBehindRadius, 0);
}
+ setBackgroundBlurRadius(a.getDimensionPixelSize(
+ R.styleable.Window_windowBackgroundBlurRadius, 0));
+
if (params.windowAnimations == 0) {
params.windowAnimations = a.getResourceId(
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index aeb4fc468fe4..823e10edaad5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -362,6 +362,12 @@
surface when the app has not drawn any content into this area. One example is
when the user is resizing a window of an activity in multi-window mode. -->
<attr name="windowBackgroundFallback" format="reference|color" />
+ <!-- Blur the screen behind the window with the bounds of the window.
+ The radius defines the size of the neighbouring area, from which pixels will be
+ averaged to form the final color for each pixel in the region.
+ A radius of 0 means no blur. The higher the radius, the denser the blur.
+ Corresponds to {@link android.view.Window#setBackgroundBlurRadius}. -->
+ <attr name="windowBackgroundBlurRadius" format="dimension" />
<!-- Drawable to use as a frame around the window. -->
<attr name="windowFrame" format="reference" />
<!-- Flag indicating whether there should be no title on this window. -->
@@ -1966,6 +1972,7 @@
<declare-styleable name="Window">
<attr name="windowBackground" />
<attr name="windowBackgroundFallback" />
+ <attr name="windowBackgroundBlurRadius" />
<attr name="windowContentOverlay" />
<attr name="windowFrame" />
<attr name="windowNoTitle" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 068987ec8afe..3c97aec5d55d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3065,6 +3065,7 @@
<public name="clipToOutline" />
<public name="edgeEffectType" />
<public name="knownCerts" />
+ <public name="windowBackgroundBlurRadius"/>
</public-group>
<public-group type="drawable" first-id="0x010800b5">