Skip to content

Commit

Permalink
Fallback to RenderScriptBlur in case when RenderEffectBlur is request…
Browse files Browse the repository at this point in the history
…ed to be rendered on a software canvas.

Fixes #190.
Add convenience `setupWith` method that picks the best available blur method.
Make RenderScriptBlur not final.
Add NonNull annotations.
  • Loading branch information
Dimezis committed Nov 21, 2022
1 parent 650cfe8 commit 9c5068d
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions library/src/main/java/eightbitlab/com/blurview/BlurView.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
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;
import android.widget.FrameLayout;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;

/**
* FrameLayout that blurs its underlying content.
Expand Down Expand Up @@ -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.
* <p>
* 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

/**
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package eightbitlab.com.blurview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.RenderEffect;
Expand All @@ -8,6 +9,7 @@
import android.os.Build;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

/**
Expand All @@ -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();
Expand All @@ -45,6 +54,9 @@ public Bitmap blur(Bitmap bitmap, float blurRadius) {
@Override
public void destroy() {
node.discardDisplayList();
if (fallbackAlgorithm != null) {
fallbackAlgorithm.destroy();
}
}

@Override
Expand All @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -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);

Expand Down

0 comments on commit 9c5068d

Please sign in to comment.