Skip to content

Commit

Permalink
Adding libraries manually
Browse files Browse the repository at this point in the history
  • Loading branch information
Maliotis committed May 27, 2020
1 parent 42e69a1 commit 0de219a
Show file tree
Hide file tree
Showing 11 changed files with 733 additions and 0 deletions.
Binary file removed iosalert/libs/annotation-1.0.0.jar
Binary file not shown.
Binary file removed iosalert/libs/blurview-1.6.2.aar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
package com.maliotis.iosalert.blurview;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;

/**
* Blur Controller that handles all blur logic for the attached View.
* It honors View size changes, View animation and Visibility changes.
* <p>
* The basic idea is to draw the view hierarchy on a bitmap, excluding the attached View,
* then blur and draw it on the system Canvas.
* <p>
* It uses {@link ViewTreeObserver.OnPreDrawListener} to detect when
* blur should be updated.
* <p>
* Blur is done on the main thread.
*/
final class BlockingBlurController implements BlurController {

// Bitmap size should be divisible by ROUNDING_VALUE to meet stride requirement.
// This will help avoiding an extra bitmap allocation when passing the bitmap to RenderScript for blur.
// Usually it's 16, but on Samsung devices it's 64 for some reason.
private static final int ROUNDING_VALUE = 64;
@ColorInt
static final int TRANSPARENT = 0;

private final float scaleFactor = DEFAULT_SCALE_FACTOR;
private float blurRadius = DEFAULT_BLUR_RADIUS;
private float roundingWidthScaleFactor = 1f;
private float roundingHeightScaleFactor = 1f;

private BlurAlgorithm blurAlgorithm;
private Canvas internalCanvas;
private Bitmap internalBitmap;

@SuppressWarnings("WeakerAccess")
final View blurView;
private int overlayColor;
private final ViewGroup rootView;
private final int[] rootLocation = new int[2];
private final int[] blurViewLocation = new int[2];

private final ViewTreeObserver.OnPreDrawListener drawListener = new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
// Not invalidating a View here, just updating the Bitmap.
// This relies on the HW accelerated bitmap drawing behavior in Android
// If the bitmap was drawn on HW accelerated canvas, it holds a reference to it and on next
// drawing pass the updated content of the bitmap will be rendered on the screen

updateBlur();
return true;
}
};

private boolean blurEnabled = true;
private boolean initialized;

@Nullable
private Drawable frameClearDrawable;
private boolean hasFixedTransformationMatrix;
private final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);

/**
* @param blurView View which will draw it's blurred underlying content
* @param rootView Root View where blurView's underlying content starts drawing.
* Can be Activity's root content layout (android.R.id.content)
* or some of your custom root layouts.
*/
BlockingBlurController(@NonNull View blurView, @NonNull ViewGroup rootView, @ColorInt int overlayColor) {
this.rootView = rootView;
this.blurView = blurView;
this.overlayColor = overlayColor;
this.blurAlgorithm = new NoOpBlurAlgorithm();

int measuredWidth = blurView.getMeasuredWidth();
int measuredHeight = blurView.getMeasuredHeight();

if (isZeroSized(measuredWidth, measuredHeight)) {
deferBitmapCreation();
return;
}

init(measuredWidth, measuredHeight);
}

private int downScaleSize(float value) {
return (int) Math.ceil(value / scaleFactor);
}

/**
* Rounds a value to the nearest divisible by {@link #ROUNDING_VALUE} to meet stride requirement
*/
private int roundSize(int value) {
if (value % ROUNDING_VALUE == 0) {
return value;
}
return value - (value % ROUNDING_VALUE) + ROUNDING_VALUE;
}

@SuppressWarnings("WeakerAccess")
void init(int measuredWidth, int measuredHeight) {
if (isZeroSized(measuredWidth, measuredHeight)) {
blurView.setWillNotDraw(true);
return;
}

blurView.setWillNotDraw(false);
allocateBitmap(measuredWidth, measuredHeight);
internalCanvas = new Canvas(internalBitmap);
initialized = true;

if (hasFixedTransformationMatrix) {
setupInternalCanvasMatrix();
}
}

private boolean isZeroSized(int measuredWidth, int measuredHeight) {
return downScaleSize(measuredHeight) == 0 || downScaleSize(measuredWidth) == 0;
}

@SuppressWarnings("WeakerAccess")
void updateBlur() {
if (!blurEnabled || !initialized) {
return;
}

if (frameClearDrawable == null) {
internalBitmap.eraseColor(Color.TRANSPARENT);
} else {
frameClearDrawable.draw(internalCanvas);
}

if (hasFixedTransformationMatrix) {
rootView.draw(internalCanvas);
} else {
internalCanvas.save();
setupInternalCanvasMatrix();
rootView.draw(internalCanvas);
internalCanvas.restore();
}

blurAndSave();
}

/**
* Deferring initialization until view is laid out
*/
private void deferBitmapCreation() {
blurView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
blurView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
legacyRemoveOnGlobalLayoutListener();
}

int measuredWidth = blurView.getMeasuredWidth();
int measuredHeight = blurView.getMeasuredHeight();

init(measuredWidth, measuredHeight);
}

@SuppressWarnings("deprecation")
void legacyRemoveOnGlobalLayoutListener() {
blurView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}

private void allocateBitmap(int measuredWidth, int measuredHeight) {
int nonRoundedScaledWidth = downScaleSize(measuredWidth);
int nonRoundedScaledHeight = downScaleSize(measuredHeight);

int scaledWidth = roundSize(nonRoundedScaledWidth);
int scaledHeight = roundSize(nonRoundedScaledHeight);

roundingHeightScaleFactor = (float) nonRoundedScaledHeight / scaledHeight;
roundingWidthScaleFactor = (float) nonRoundedScaledWidth / scaledWidth;

internalBitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, blurAlgorithm.getSupportedBitmapConfig());
}

/**
* Set up matrix to draw starting from blurView's position
*/
private void setupInternalCanvasMatrix() {
rootView.getLocationOnScreen(rootLocation);
blurView.getLocationOnScreen(blurViewLocation);

int left = blurViewLocation[0] - rootLocation[0];
int top = blurViewLocation[1] - rootLocation[1];

float scaleFactorX = scaleFactor * roundingWidthScaleFactor;
float scaleFactorY = scaleFactor * roundingHeightScaleFactor;

float scaledLeftPosition = -left / scaleFactorX;
float scaledTopPosition = -top / scaleFactorY;

internalCanvas.translate(scaledLeftPosition, scaledTopPosition);
internalCanvas.scale(1 / scaleFactorX, 1 / scaleFactorY);
}

@Override
public boolean draw(Canvas canvas) {
if (!blurEnabled || !initialized) {
return true;
}
// Not blurring own children
if (canvas == internalCanvas) {
return false;
}

updateBlur();

canvas.save();
canvas.scale(scaleFactor * roundingWidthScaleFactor, scaleFactor * roundingHeightScaleFactor);
canvas.drawBitmap(internalBitmap, 0, 0, paint);
canvas.restore();

if (overlayColor != TRANSPARENT) {
canvas.drawColor(overlayColor);
}
return true;
}

private void blurAndSave() {
internalBitmap = blurAlgorithm.blur(internalBitmap, blurRadius);
if (!blurAlgorithm.canModifyBitmap()) {
internalCanvas.setBitmap(internalBitmap);
}
}

@Override
public void updateBlurViewSize() {
int measuredWidth = blurView.getMeasuredWidth();
int measuredHeight = blurView.getMeasuredHeight();

init(measuredWidth, measuredHeight);
}

@Override
public void destroy() {
setBlurAutoUpdate(false);
blurAlgorithm.destroy();
initialized = false;
}

@Override
public BlurViewFacade setBlurRadius(float radius) {
this.blurRadius = radius;
return this;
}

@Override
public BlurViewFacade setBlurAlgorithm(BlurAlgorithm algorithm) {
this.blurAlgorithm = algorithm;
return this;
}

@Override
public BlurViewFacade setFrameClearDrawable(@Nullable Drawable frameClearDrawable) {
this.frameClearDrawable = frameClearDrawable;
return this;
}

@Override
public BlurViewFacade setBlurEnabled(boolean enabled) {
this.blurEnabled = enabled;
setBlurAutoUpdate(enabled);
blurView.invalidate();
return this;
}

public BlurViewFacade setBlurAutoUpdate(final boolean enabled) {
blurView.getViewTreeObserver().removeOnPreDrawListener(drawListener);
if (enabled) {
blurView.getViewTreeObserver().addOnPreDrawListener(drawListener);
}
return this;
}

@Override
public BlurViewFacade setHasFixedTransformationMatrix(boolean hasFixedTransformationMatrix) {
this.hasFixedTransformationMatrix = hasFixedTransformationMatrix;
return this;
}

@Override
public BlurViewFacade setOverlayColor(int overlayColor) {
if (this.overlayColor != overlayColor) {
this.overlayColor = overlayColor;
blurView.invalidate();
}
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.maliotis.iosalert.blurview;

import android.graphics.Bitmap;
import android.support.annotation.NonNull;

public interface BlurAlgorithm {
/**
* @param bitmap bitmap to be blurred
* @param blurRadius blur radius
* @return blurred bitmap
*/
Bitmap blur(Bitmap bitmap, float blurRadius);

/**
* Frees allocated resources
*/
void destroy();

/**
* @return true if this algorithm returns the same instance of bitmap as it accepted
* false if it creates a new instance.
* <p>
* If you return false from this method, you'll be responsible to swap bitmaps in your
* {@link BlurAlgorithm#blur(Bitmap, float)} implementation
* (assign input bitmap to your field and return the instance algorithm just blurred).
*/
boolean canModifyBitmap();

/**
* Retrieve the {@link Bitmap.Config} on which the {@link BlurAlgorithm}
* can actually work.
*
* @return bitmap config supported by the given blur algorithm.
*/
@NonNull
Bitmap.Config getSupportedBitmapConfig();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.maliotis.iosalert.blurview;

import android.graphics.Canvas;

interface BlurController extends BlurViewFacade {

float DEFAULT_SCALE_FACTOR = 8f;
float DEFAULT_BLUR_RADIUS = 16f;

/**
* Draws blurred content on given canvas
*
* @return true if BlurView should proceed with drawing itself and its children
*/
boolean draw(Canvas canvas);

/**
* Must be used to notify Controller when BlurView's size has changed
*/
void updateBlurViewSize();

/**
* Frees allocated resources
*/
void destroy();
}
Loading

0 comments on commit 0de219a

Please sign in to comment.