diff --git a/library/src/main/java/eightbitlab/com/blurview/BlurAlgorithm.java b/library/src/main/java/eightbitlab/com/blurview/BlurAlgorithm.java index aa174f7..786de69 100644 --- a/library/src/main/java/eightbitlab/com/blurview/BlurAlgorithm.java +++ b/library/src/main/java/eightbitlab/com/blurview/BlurAlgorithm.java @@ -11,7 +11,7 @@ public interface BlurAlgorithm { * @param blurRadius blur radius * @return blurred bitmap */ - Bitmap blur(Bitmap bitmap, float blurRadius); + Bitmap blur(@NonNull Bitmap bitmap, @NonNull float blurRadius); /** * Frees allocated resources diff --git a/library/src/main/java/eightbitlab/com/blurview/BlurView.java b/library/src/main/java/eightbitlab/com/blurview/BlurView.java index 4c926d9..f5b82b1 100644 --- a/library/src/main/java/eightbitlab/com/blurview/BlurView.java +++ b/library/src/main/java/eightbitlab/com/blurview/BlurView.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; +import android.os.Build; import android.util.AttributeSet; import android.util.Log; import android.view.ViewGroup; @@ -12,6 +13,7 @@ import androidx.annotation.ColorInt; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; /** * FrameLayout that blurs its underlying content. @@ -92,6 +94,24 @@ public BlurViewFacade setupWith(@NonNull ViewGroup rootView, BlurAlgorithm algor return blurController; } + /** + * @param rootView root to start blur from. + * Can be Activity's root content layout (android.R.id.content) + * or (preferably) some of your layouts. The lower amount of Views are in the root, the better for performance. + *

+ * BlurAlgorithm is automatically picked based on the API version. + * It uses RenderEffectBlur on API 31+, and RenderScriptBlur on older versions. + * @return {@link BlurView} to setup needed params. + */ + @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) + public BlurViewFacade setupWith(@NonNull ViewGroup rootView) { + this.blurController.destroy(); + BlurController blurController = new PreDrawBlurController(this, rootView, overlayColor, getBlurAlgorithm()); + this.blurController = blurController; + + return blurController; + } + // Setters duplicated to be able to conveniently change these settings outside of setupWith chain /** @@ -122,4 +142,16 @@ public BlurViewFacade setBlurAutoUpdate(boolean enabled) { public BlurViewFacade setBlurEnabled(boolean enabled) { return blurController.setBlurEnabled(enabled); } + + @NonNull + @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) + private BlurAlgorithm getBlurAlgorithm() { + BlurAlgorithm algorithm; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + algorithm = new RenderEffectBlur(); + } else { + algorithm = new RenderScriptBlur(getContext()); + } + return algorithm; + } } diff --git a/library/src/main/java/eightbitlab/com/blurview/PreDrawBlurController.java b/library/src/main/java/eightbitlab/com/blurview/PreDrawBlurController.java index 66f2272..4fe7f2c 100644 --- a/library/src/main/java/eightbitlab/com/blurview/PreDrawBlurController.java +++ b/library/src/main/java/eightbitlab/com/blurview/PreDrawBlurController.java @@ -69,6 +69,10 @@ public boolean onPreDraw() { this.blurView = blurView; this.overlayColor = overlayColor; this.blurAlgorithm = algorithm; + if (algorithm instanceof RenderEffectBlur) { + // noinspection NewApi + ((RenderEffectBlur) algorithm).setContext(blurView.getContext()); + } int measuredWidth = blurView.getMeasuredWidth(); int measuredHeight = blurView.getMeasuredHeight(); diff --git a/library/src/main/java/eightbitlab/com/blurview/RenderEffectBlur.java b/library/src/main/java/eightbitlab/com/blurview/RenderEffectBlur.java index 930d80b..fc93b18 100644 --- a/library/src/main/java/eightbitlab/com/blurview/RenderEffectBlur.java +++ b/library/src/main/java/eightbitlab/com/blurview/RenderEffectBlur.java @@ -1,5 +1,6 @@ package eightbitlab.com.blurview; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.RenderEffect; @@ -8,6 +9,7 @@ import android.os.Build; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; /** @@ -23,12 +25,19 @@ public class RenderEffectBlur implements BlurAlgorithm { private final RenderNode node = new RenderNode("BlurViewNode"); private int height, width; + private float lastBlurRadius = 1f; + + @Nullable + public BlurAlgorithm fallbackAlgorithm; + private Context context; public RenderEffectBlur() { } @Override - public Bitmap blur(Bitmap bitmap, float blurRadius) { + public Bitmap blur(@NonNull Bitmap bitmap, float blurRadius) { + lastBlurRadius = blurRadius; + if (bitmap.getHeight() != height || bitmap.getWidth() != width) { height = bitmap.getHeight(); width = bitmap.getWidth(); @@ -45,6 +54,9 @@ public Bitmap blur(Bitmap bitmap, float blurRadius) { @Override public void destroy() { node.discardDisplayList(); + if (fallbackAlgorithm != null) { + fallbackAlgorithm.destroy(); + } } @Override @@ -64,7 +76,19 @@ public float scaleFactor() { } @Override - public void render(@NonNull Canvas canvas, @NonNull Bitmap ignored) { - canvas.drawRenderNode(node); + public void render(@NonNull Canvas canvas, @NonNull Bitmap bitmap) { + if (canvas.isHardwareAccelerated()) { + canvas.drawRenderNode(node); + } else { + if (fallbackAlgorithm == null) { + fallbackAlgorithm = new RenderScriptBlur(context); + } + fallbackAlgorithm.blur(bitmap, lastBlurRadius); + fallbackAlgorithm.render(canvas, bitmap); + } + } + + void setContext(@NonNull Context context) { + this.context = context; } } diff --git a/library/src/main/java/eightbitlab/com/blurview/RenderScriptBlur.java b/library/src/main/java/eightbitlab/com/blurview/RenderScriptBlur.java index 5d0453e..60d6118 100644 --- a/library/src/main/java/eightbitlab/com/blurview/RenderScriptBlur.java +++ b/library/src/main/java/eightbitlab/com/blurview/RenderScriptBlur.java @@ -23,7 +23,7 @@ * RenderEffectBlur is the best alternative at the moment. */ @Deprecated -public final class RenderScriptBlur implements BlurAlgorithm { +public class RenderScriptBlur implements BlurAlgorithm { private final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); private final RenderScript renderScript; private final ScriptIntrinsicBlur blurScript; @@ -36,12 +36,12 @@ public final class RenderScriptBlur implements BlurAlgorithm { * @param context Context to create the {@link RenderScript} */ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) - public RenderScriptBlur(Context context) { + public RenderScriptBlur(@NonNull Context context) { renderScript = RenderScript.create(context); blurScript = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript)); } - private boolean canReuseAllocation(Bitmap bitmap) { + private boolean canReuseAllocation(@NonNull Bitmap bitmap) { return bitmap.getHeight() == lastBitmapHeight && bitmap.getWidth() == lastBitmapWidth; } @@ -52,7 +52,7 @@ private boolean canReuseAllocation(Bitmap bitmap) { */ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) @Override - public final Bitmap blur(Bitmap bitmap, float blurRadius) { + public Bitmap blur(@NonNull Bitmap bitmap, float blurRadius) { //Allocation will use the same backing array of pixels as bitmap if created with USAGE_SHARED flag Allocation inAllocation = Allocation.createFromBitmap(renderScript, bitmap);