├── .gitignore ├── .repo ├── bk-demo.gif ├── bk-gh-readme-header.svg └── bk-gh-readme-spectrum-button.svg ├── LICENSE ├── README.md ├── blurkit ├── .gitignore ├── build.gradle ├── deploy.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── io │ │ └── alterac │ │ └── blurkit │ │ └── BlurKitInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── io │ │ │ └── alterac │ │ │ └── blurkit │ │ │ ├── BlurKit.java │ │ │ ├── BlurKitException.java │ │ │ ├── BlurLayout.java │ │ │ └── RoundedImageView.java │ └── res │ │ ├── drawable │ │ └── original_bk_logo.bmp │ │ └── values │ │ └── attrs.xml │ └── test │ └── java │ └── io │ └── alterac │ └── blurkit │ ├── BlurLayoutTest.java │ └── RoundedImageViewTest.java ├── build.gradle ├── demo ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ └── io │ │ └── alterac │ │ └── blurkit │ │ └── demo │ │ └── MainActivity.java │ └── res │ ├── drawable-nodpi │ └── peppers.png │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | *.prefs 23 | .classpath 24 | 25 | # Proguard folder generated by Eclipse 26 | proguard/ 27 | 28 | # Log Files 29 | *.log 30 | 31 | # Android Studio Navigation editor temp files 32 | .navigation/ 33 | 34 | # Android Studio captures folder 35 | captures/ 36 | 37 | # Intellij 38 | *.iml 39 | .idea/workspace.xml 40 | 41 | # Keystore files 42 | *.jks 43 | 44 | .idea 45 | .project 46 | -------------------------------------------------------------------------------- /.repo/bk-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CameraKit/blurkit-android/f0d181a3850db20f495d5b2c7b825d1fd790d7f2/.repo/bk-demo.gif -------------------------------------------------------------------------------- /.repo/bk-gh-readme-header.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.repo/bk-gh-readme-spectrum-button.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 WonderKiln 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | BlurKit Header 3 |

4 | 5 |

6 | 7 | Join Spectrum 8 | 9 | 10 | Buddy.Works 11 | 12 |

13 | 14 | ## What Is BlurKit? 15 | BlurKit is an extraordinarily easy to use and performant utility to render real time blur effects in Android. 16 | 17 |

18 | BlurKit Demo 19 |

20 | 21 | ## Perfomance 22 | 23 | BlurKit is faster than other blurring libraries due to a number of bitmap retrieval and drawing optimizations. We've been logging benchmarks for the basic high-intensity tasks for a 300dp x 100dp BlurView: 24 | 25 | | Task | BlurKit time | Avg. time without BlurKit | 26 | | --------------------------| -------------------| ----------------------- | 27 | | Retrieve source bitmap | 1-2 ms | 8-25 ms | 28 | | Blur and draw to BlurView | 1-2 ms | 10-50ms | 29 | 30 | This results in an average work/frame time of 2-4ms, which will be a seamless experience for most users and apps. 31 | 32 | ## Setup 33 | Add __BlurKit__ to the dependencies block of the app level `build.gradle`: 34 | ```groovy 35 | dependencies { 36 | implementation 'io.alterac.blurkit:blurkit:1.1.0' 37 | } 38 | ``` 39 | 40 | ## Usage 41 | ### BlurLayout 42 | Add a `BlurLayout` to your XML layout just like any other view. 43 | 44 | ```xml 45 | 49 | ``` 50 | In the `Main_Activity.java` you need to override the `onStart()` and `onStop()` methods to include the `BlurLayout` functionality. 51 | ```java 52 | BlurLayout blurLayout; 53 | 54 | @Override 55 | protected void onCreate(Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | setContentView(R.layout.activity_main); 58 | blurLayout = findViewById(R.id.blurLayout); 59 | } 60 | 61 | @Override 62 | protected void onStart() { 63 | super.onStart(); 64 | blurLayout.startBlur(); 65 | } 66 | 67 | @Override 68 | protected void onStop() { 69 | blurLayout.pauseBlur(); 70 | super.onStop(); 71 | } 72 | ``` 73 | 74 | The layout background will continuously blur the content behind it. If you know your background content will be somewhat static, you can set the layout `fps` to `0`. At any time you can re-blur the background content by calling `invalidate()` on the `BlurLayout`. 75 | 76 | ```xml 77 | 82 | ``` 83 | 84 | Other attributes you can configure are the blur radius and the downscale factor. Getting these to work together well can take some experimentation. The downscale factor is a performance optimization; the bitmap for the background content will be downsized by this factor before being drawn and blurred. 85 | 86 | ```xml 87 | 94 | ``` 95 | 96 | ### Creating BlurKit Outside Of A Layout 97 | You can use the `BlurKit` class which has a few useful blurring utilities. Before using this class outside of a `BlurLayout`, you need to initialize `BlurKit`. 98 | 99 | ```java 100 | public class MyApplication extends Application { 101 | @Override 102 | public void onCreate() { 103 | BlurKit.init(this); 104 | } 105 | } 106 | ``` 107 | 108 | You can blur a `View`, or a `Bitmap` directly. 109 | 110 | ```java 111 | // View 112 | BlurKit.getInstance().blur(View src, int radius); 113 | 114 | // Bitmap 115 | BlurKit.getInstance().blur(Bitmap src, int radius); 116 | ``` 117 | 118 | You can also __fastBlur__ a `View`. This optimizes the view blurring process by allocating a downsized bitmap and using a `Matrix` with the bitmaps `Canvas` to prescale the drawing of the view to the bitmap. 119 | 120 | ```java 121 | BlurKit.getInstance().fastBlur(View src, int radius, float downscaleFactor); 122 | ``` 123 | 124 | 125 | 126 | ## Upcoming Features 127 | - [ ] `SurfaceView` support 128 | - [ ] Support for use outside of an `Activity` (dialogs, etc.) 129 | - [ ] Enhance retrieval of background content to only include views drawn behind the `BlurLayout`. 130 | 131 | ## License 132 | BlurKit is [MIT licensed](https://github.com/CameraKit/blurkit-android/blob/master/LICENSE). 133 | 134 | --- 135 | Blurkit is a sister project of [CameraKit](https://github.com/CameraKit/camerakit-android) and maintained by the CameraKit team. 136 | -------------------------------------------------------------------------------- /blurkit/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /blurkit/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | id 'com.github.dcendents.android-maven' version '1.5' 4 | } 5 | 6 | ext { 7 | PUBLISH_GROUP_ID = 'io.alterac.blurkit' 8 | PUBLISH_ARTIFACT_ID = 'blurkit' 9 | PUBLISH_VERSION = '1.1.0' 10 | } 11 | 12 | android { 13 | compileSdkVersion versions.compileSdk 14 | buildToolsVersion '28.0.3' 15 | 16 | defaultConfig { 17 | minSdkVersion versions.minSdk 18 | targetSdkVersion versions.targetSdk 19 | versionCode 1 20 | versionName "1.1.0" 21 | renderscriptTargetApi 28 22 | renderscriptSupportModeEnabled true 23 | testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' 24 | } 25 | testOptions { 26 | unitTests.returnDefaultValues = true 27 | } 28 | buildTypes { 29 | release { 30 | minifyEnabled false 31 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 32 | } 33 | } 34 | } 35 | 36 | dependencies { 37 | testImplementation 'junit:junit:4.12' 38 | testImplementation 'org.mockito:mockito-core:1.10.19' 39 | androidTestImplementation 'com.android.support:support-annotations:28.0.0' 40 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 41 | androidTestImplementation 'com.android.support.test:rules:1.0.2' 42 | androidTestImplementation 'org.hamcrest:hamcrest-library:1.3' 43 | 44 | } 45 | 46 | install { 47 | repositories.mavenInstaller { 48 | pom.project { 49 | groupId project.group 50 | artifactId 'blurkit' 51 | packaging 'aar' 52 | } 53 | } 54 | } 55 | 56 | apply from : 'deploy.gradle' 57 | -------------------------------------------------------------------------------- /blurkit/deploy.gradle: -------------------------------------------------------------------------------- 1 | def getBintrayUser() { 2 | if (System.getenv('BINTRAY_USER')) { 3 | logger.lifecycle(System.getenv('BINTRAY_USER')) 4 | return System.getenv('BINTRAY_USER') 5 | } else if (rootProject.file('local.properties').exists()) { 6 | Properties properties = new Properties() 7 | properties.load(rootProject.file('local.properties').newDataInputStream()) 8 | return properties.getProperty('bintray.user') 9 | } else { 10 | logger.lifecycle("Warning: Could not find BINTRAY_USER in environment or local.properties") 11 | } 12 | } 13 | 14 | def getBintrayKey() { 15 | if (System.getenv('BINTRAY_KEY')) { 16 | logger.lifecycle(System.getenv('BINTRAY_KEY')) 17 | return System.getenv('BINTRAY_KEY') 18 | } else if (rootProject.file('local.properties').exists()) { 19 | Properties properties = new Properties() 20 | properties.load(rootProject.file('local.properties').newDataInputStream()) 21 | return properties.getProperty('bintray.key') 22 | } else { 23 | logger.lifecycle("Warning: Could not find BINTRAY_KEY in environment or local.properties") 24 | } 25 | } 26 | 27 | apply plugin: 'com.jfrog.bintray' 28 | 29 | bintray { 30 | user = getBintrayUser() 31 | key = getBintrayKey() 32 | configurations = ['archives'] 33 | pkg { 34 | repo = 'other' 35 | name = 'blurkit-android' 36 | userOrg = 'camerakit' 37 | vcsUrl = 'https://github.com/CameraKit/blurkit-android.git' 38 | licenses = ['MIT'] 39 | 40 | version { 41 | name = project.version 42 | released = new Date() 43 | } 44 | } 45 | } 46 | 47 | task cleanForDeployment { 48 | doLast { 49 | logger.lifecycle('BlurKit: Deployment: Cleaning...') 50 | logger.lifecycle('Deleting: ' + project.buildDir) 51 | delete project.buildDir 52 | } 53 | } 54 | 55 | task buildForDeployment { 56 | logger.lifecycle('BlurKit: Deployment: Building...') 57 | shouldRunAfter(cleanForDeployment) 58 | finalizedBy assemble 59 | 60 | doFirst { 61 | android.variantFilter { variant -> 62 | if (variant.buildType.name == 'debug') { 63 | variant.setIgnore(true) 64 | } 65 | } 66 | } 67 | } 68 | 69 | task deployRelease { 70 | logger.lifecycle('BlurKit - Starting Release Deployment') 71 | shouldRunAfter(buildForDeployment) 72 | 73 | dependsOn cleanForDeployment 74 | dependsOn buildForDeployment 75 | finalizedBy bintrayUpload 76 | 77 | doLast { 78 | logger.lifecycle(bintrayUpload.getVersionName()) 79 | bintrayUpload.setVersionName(bintrayUpload.getVersionName()) 80 | bintrayUpload.setUserOrg('camerakit') 81 | bintrayUpload.setRepoName('other') 82 | 83 | logger.lifecycle('Deploying version ' + bintrayUpload.getVersionName() + ' in ' + bintrayUpload.getRepoName()) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /blurkit/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/dylanmcintyre/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /blurkit/src/androidTest/java/io/alterac/blurkit/BlurKitInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package io.alterac.blurkit; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.support.test.InstrumentationRegistry; 7 | import android.support.test.runner.AndroidJUnit4; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | 13 | import static org.junit.Assert.assertFalse; 14 | import static org.junit.Assert.assertTrue; 15 | 16 | @RunWith(AndroidJUnit4.class) 17 | public class BlurKitInstrumentedTest { 18 | 19 | private Context context; 20 | BlurKit blurKit; 21 | 22 | private Bitmap original; 23 | private Bitmap blur1; 24 | private Bitmap blur2; 25 | 26 | @Before 27 | public void setupTests() { 28 | context = InstrumentationRegistry.getContext(); 29 | blurKit = new BlurKit(); 30 | BlurKit.init(context); 31 | 32 | original = BitmapFactory.decodeResource(context.getResources(), R.drawable.original_bk_logo); 33 | blur1 = original.copy(original.getConfig(), true); 34 | blur2 = original.copy(original.getConfig(), true); 35 | } 36 | 37 | @Test 38 | public void blurTest() { 39 | blur1 = blurKit.blur(blur1, 10); 40 | blur2 = blurKit.blur(blur2, 10); 41 | 42 | assertTrue(blur1.sameAs(blur2)); 43 | assertFalse(blur1.sameAs(original)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /blurkit/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /blurkit/src/main/java/io/alterac/blurkit/BlurKit.java: -------------------------------------------------------------------------------- 1 | package io.alterac.blurkit; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Matrix; 7 | import android.view.View; 8 | import android.renderscript.Allocation; 9 | import android.renderscript.Element; 10 | import android.renderscript.RenderScript; 11 | import android.renderscript.ScriptIntrinsicBlur; 12 | 13 | public class BlurKit { 14 | 15 | private static final float FULL_SCALE = 1f; 16 | 17 | private static BlurKit instance; 18 | 19 | private static RenderScript rs; 20 | 21 | public static void init(Context context) { 22 | if (instance != null) { 23 | return; 24 | } 25 | 26 | instance = new BlurKit(); 27 | rs = RenderScript.create(context.getApplicationContext()); 28 | } 29 | 30 | public Bitmap blur(Bitmap src, int radius) { 31 | final Allocation input = Allocation.createFromBitmap(rs, src); 32 | final Allocation output = Allocation.createTyped(rs, input.getType()); 33 | final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); 34 | script.setRadius(radius); 35 | script.setInput(input); 36 | script.forEach(output); 37 | output.copyTo(src); 38 | return src; 39 | } 40 | 41 | public Bitmap blur(View src, int radius) { 42 | Bitmap bitmap = getBitmapForView(src); 43 | return blur(bitmap, radius); 44 | } 45 | 46 | public Bitmap fastBlur(View src, int radius, float downscaleFactor) { 47 | Bitmap bitmap = getBitmapForView(src, downscaleFactor); 48 | return blur(bitmap, radius); 49 | } 50 | 51 | private Bitmap getBitmapForView(View src, float downscaleFactor) { 52 | Bitmap bitmap = Bitmap.createBitmap( 53 | (int) (src.getWidth() * downscaleFactor), 54 | (int) (src.getHeight() * downscaleFactor), 55 | Bitmap.Config.ARGB_8888 56 | ); 57 | 58 | Canvas canvas = new Canvas(bitmap); 59 | Matrix matrix = new Matrix(); 60 | matrix.preScale(downscaleFactor, downscaleFactor); 61 | canvas.setMatrix(matrix); 62 | src.draw(canvas); 63 | 64 | return bitmap; 65 | } 66 | 67 | private Bitmap getBitmapForView(View src) { 68 | Bitmap bitmap = Bitmap.createBitmap( 69 | src.getWidth(), 70 | src.getHeight(), 71 | Bitmap.Config.ARGB_8888 72 | ); 73 | 74 | Canvas canvas = new Canvas(bitmap); 75 | src.draw(canvas); 76 | 77 | return bitmap; 78 | } 79 | 80 | public static BlurKit getInstance() { 81 | if (instance == null) { 82 | throw new RuntimeException("BlurKit not initialized!"); 83 | } 84 | 85 | return instance; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /blurkit/src/main/java/io/alterac/blurkit/BlurKitException.java: -------------------------------------------------------------------------------- 1 | package io.alterac.blurkit; 2 | 3 | public class BlurKitException extends Exception { 4 | 5 | public BlurKitException(String message) { 6 | super(message); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /blurkit/src/main/java/io/alterac/blurkit/BlurLayout.java: -------------------------------------------------------------------------------- 1 | package io.alterac.blurkit; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.res.TypedArray; 6 | import android.graphics.Bitmap; 7 | import android.graphics.Canvas; 8 | import android.graphics.Matrix; 9 | import android.graphics.Point; 10 | import android.graphics.PointF; 11 | import android.graphics.Rect; 12 | import android.util.AttributeSet; 13 | import android.view.Choreographer; 14 | import android.view.View; 15 | import android.view.ViewGroup; 16 | import android.widget.FrameLayout; 17 | import android.widget.ImageView; 18 | 19 | import java.lang.ref.WeakReference; 20 | 21 | /** 22 | * A {@link ViewGroup} that blurs all content behind it. Automatically creates bitmap of parent content 23 | * and finds its relative position to the top parent to draw properly regardless of where the layout is 24 | * placed. 25 | */ 26 | public class BlurLayout extends FrameLayout { 27 | 28 | public static final float DEFAULT_DOWNSCALE_FACTOR = 0.12f; 29 | public static final int DEFAULT_BLUR_RADIUS = 12; 30 | public static final int DEFAULT_FPS = 60; 31 | public static final float DEFAULT_CORNER_RADIUS = 0.f; 32 | public static final float DEFAULT_ALPHA = Float.NaN; 33 | 34 | // Customizable attributes 35 | 36 | /** Factor to scale the view bitmap with before blurring. */ 37 | private float mDownscaleFactor; 38 | 39 | /** Blur radius passed directly to stackblur library. */ 40 | private int mBlurRadius; 41 | 42 | /** Number of blur invalidations to do per second. */ 43 | private int mFPS; 44 | 45 | /** Corner radius for the layouts blur. To make rounded rects and circles. */ 46 | private float mCornerRadius; 47 | 48 | /** Alpha value to set transparency */ 49 | private float mAlpha; 50 | 51 | /** Is blur running? */ 52 | private boolean mRunning; 53 | 54 | /** Is window attached? */ 55 | private boolean mAttachedToWindow; 56 | 57 | /** Do we need to recalculate the position each invalidation? */ 58 | private boolean mPositionLocked; 59 | 60 | /** Do we need to regenerate the view bitmap each invalidation? */ 61 | private boolean mViewLocked; 62 | 63 | // Calculated class dependencies 64 | 65 | /** ImageView to show the blurred content. */ 66 | private RoundedImageView mImageView; 67 | 68 | /** Reference to View for top-parent. For retrieval see {@link #getActivityView() getActivityView}. */ 69 | private WeakReference mActivityView; 70 | 71 | /** A saved point to re-use when {@link #lockPosition()} called. */ 72 | private Point mLockedPoint; 73 | 74 | /** A saved bitmap for the view to re-use when {@link #lockView()} called. */ 75 | private Bitmap mLockedBitmap; 76 | 77 | public BlurLayout(Context context) { 78 | super(context, null); 79 | } 80 | 81 | public BlurLayout(Context context, AttributeSet attrs) { 82 | super(context, attrs); 83 | 84 | if (!isInEditMode()) { 85 | BlurKit.init(context); 86 | } 87 | 88 | TypedArray a = context.getTheme().obtainStyledAttributes( 89 | attrs, 90 | io.alterac.blurkit.R.styleable.BlurLayout, 91 | 0, 0); 92 | 93 | try { 94 | mDownscaleFactor = a.getFloat(R.styleable.BlurLayout_blk_downscaleFactor, DEFAULT_DOWNSCALE_FACTOR); 95 | mBlurRadius = a.getInteger(R.styleable.BlurLayout_blk_blurRadius, DEFAULT_BLUR_RADIUS); 96 | mFPS = a.getInteger(R.styleable.BlurLayout_blk_fps, DEFAULT_FPS); 97 | mCornerRadius = a.getDimension(R.styleable.BlurLayout_blk_cornerRadius, DEFAULT_CORNER_RADIUS); 98 | mAlpha = a.getDimension(R.styleable.BlurLayout_blk_alpha, DEFAULT_ALPHA); 99 | } finally { 100 | a.recycle(); 101 | } 102 | 103 | mImageView = new RoundedImageView(getContext()); 104 | mImageView.setScaleType(ImageView.ScaleType.FIT_XY); 105 | addView(mImageView); 106 | 107 | setCornerRadius(mCornerRadius); 108 | } 109 | 110 | /** Choreographer callback that re-draws the blur and schedules another callback. */ 111 | private Choreographer.FrameCallback invalidationLoop = new Choreographer.FrameCallback() { 112 | @Override 113 | public void doFrame(long frameTimeNanos) { 114 | invalidate(); 115 | Choreographer.getInstance().postFrameCallbackDelayed(this, 1000 / mFPS); 116 | } 117 | }; 118 | 119 | /** Start BlurLayout continuous invalidation. **/ 120 | public void startBlur() { 121 | if (mRunning) { 122 | return; 123 | } 124 | 125 | if (mFPS > 0) { 126 | mRunning = true; 127 | Choreographer.getInstance().postFrameCallback(invalidationLoop); 128 | } 129 | } 130 | 131 | /** Pause BlurLayout continuous invalidation. **/ 132 | public void pauseBlur() { 133 | if (!mRunning) { 134 | return; 135 | } 136 | 137 | mRunning = false; 138 | Choreographer.getInstance().removeFrameCallback(invalidationLoop); 139 | } 140 | 141 | @Override 142 | protected void onAttachedToWindow() { 143 | super.onAttachedToWindow(); 144 | mAttachedToWindow = true; 145 | startBlur(); 146 | } 147 | 148 | @Override 149 | protected void onDetachedFromWindow() { 150 | super.onDetachedFromWindow(); 151 | mAttachedToWindow = false; 152 | pauseBlur(); 153 | } 154 | 155 | @Override 156 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 157 | super.onSizeChanged(w, h, oldw, oldh); 158 | invalidate(); 159 | } 160 | 161 | @Override 162 | public void invalidate() { 163 | super.invalidate(); 164 | Bitmap bitmap = blur(); 165 | if (bitmap != null) { 166 | mImageView.setImageBitmap(bitmap); 167 | } 168 | } 169 | 170 | /** 171 | * Recreates blur for content and sets it as the background. 172 | */ 173 | private Bitmap blur() { 174 | if (getContext() == null || isInEditMode()) { 175 | return null; 176 | } 177 | 178 | // Check the reference to the parent view. 179 | // If not available, attempt to make it. 180 | if (mActivityView == null || mActivityView.get() == null) { 181 | mActivityView = new WeakReference<>(getActivityView()); 182 | if (mActivityView.get() == null) { 183 | return null; 184 | } 185 | } 186 | 187 | Point pointRelativeToActivityView; 188 | if (mPositionLocked) { 189 | // Generate a locked point if null. 190 | if (mLockedPoint == null) { 191 | mLockedPoint = getPositionInScreen(); 192 | } 193 | 194 | // Use locked point. 195 | pointRelativeToActivityView = mLockedPoint; 196 | } else { 197 | // Calculate the relative point to the parent view. 198 | pointRelativeToActivityView = getPositionInScreen(); 199 | } 200 | 201 | // Set alpha to 0 before creating the parent view bitmap. 202 | // The blur view shouldn't be visible in the created bitmap. 203 | super.setAlpha(0); 204 | 205 | // Screen sizes for bound checks 206 | int screenWidth = mActivityView.get().getWidth(); 207 | int screenHeight = mActivityView.get().getHeight(); 208 | 209 | // The final dimensions of the blurred bitmap. 210 | int width = (int) (getWidth() * mDownscaleFactor); 211 | int height = (int) (getHeight() * mDownscaleFactor); 212 | 213 | // The X/Y position of where to crop the bitmap. 214 | int x = (int) (pointRelativeToActivityView.x * mDownscaleFactor); 215 | int y = (int) (pointRelativeToActivityView.y * mDownscaleFactor); 216 | 217 | // Padding to add to crop pre-blur. 218 | // Blurring straight to edges has side-effects so padding is added. 219 | int xPadding = getWidth() / 8; 220 | int yPadding = getHeight() / 8; 221 | 222 | // Calculate padding independently for each side, checking edges. 223 | int leftOffset = -xPadding; 224 | leftOffset = x + leftOffset >= 0 ? leftOffset : 0; 225 | 226 | int rightOffset = xPadding; 227 | rightOffset = x + screenWidth - rightOffset <= screenWidth ? rightOffset : screenWidth + screenWidth - x; 228 | 229 | int topOffset = -yPadding; 230 | topOffset = y + topOffset >= 0 ? topOffset : 0; 231 | 232 | int bottomOffset = yPadding; 233 | bottomOffset = y + getHeight() + bottomOffset <= screenHeight ? bottomOffset : 0; 234 | 235 | // Parent view bitmap, downscaled with mDownscaleFactor 236 | Bitmap bitmap; 237 | if (mViewLocked) { 238 | // It's possible for mLockedBitmap to be null here even with view locked. 239 | // lockView() should always properly set mLockedBitmap if this code is reached 240 | // (it passed previous checks), so recall lockView and assume it's good. 241 | if (mLockedBitmap == null) { 242 | lockView(); 243 | } 244 | 245 | if (width == 0 || height == 0) { 246 | return null; 247 | } 248 | 249 | bitmap = Bitmap.createBitmap(mLockedBitmap, x, y, width, height); 250 | } else { 251 | try { 252 | // Create parent view bitmap, cropped to the BlurLayout area with above padding. 253 | bitmap = getDownscaledBitmapForView( 254 | mActivityView.get(), 255 | new Rect( 256 | pointRelativeToActivityView.x + leftOffset, 257 | pointRelativeToActivityView.y + topOffset, 258 | pointRelativeToActivityView.x + getWidth() + Math.abs(leftOffset) + rightOffset, 259 | pointRelativeToActivityView.y + getHeight() + Math.abs(topOffset) + bottomOffset 260 | ), 261 | mDownscaleFactor 262 | ); 263 | } catch (BlurKitException e) { 264 | return null; 265 | } catch (NullPointerException e) { 266 | return null; 267 | } 268 | 269 | } 270 | 271 | if (!mViewLocked) { 272 | // Blur the bitmap. 273 | bitmap = BlurKit.getInstance().blur(bitmap, mBlurRadius); 274 | 275 | //Crop the bitmap again to remove the padding. 276 | bitmap = Bitmap.createBitmap( 277 | bitmap, 278 | (int) (Math.abs(leftOffset) * mDownscaleFactor), 279 | (int) (Math.abs(topOffset) * mDownscaleFactor), 280 | width, 281 | height 282 | ); 283 | 284 | } 285 | 286 | // Make self visible again. 287 | if (Float.isNaN(mAlpha)) { 288 | super.setAlpha(1); 289 | } else { 290 | super.setAlpha(mAlpha); 291 | } 292 | 293 | // Set background as blurred bitmap. 294 | return bitmap; 295 | } 296 | 297 | /** 298 | * Casts context to Activity and attempts to create a view reference using the window decor view. 299 | * @return View reference for whole activity. 300 | */ 301 | private View getActivityView() { 302 | Activity activity; 303 | try { 304 | activity = (Activity) getContext(); 305 | } catch (ClassCastException e) { 306 | return null; 307 | } 308 | 309 | return activity.getWindow().getDecorView().findViewById(android.R.id.content); 310 | } 311 | 312 | /** 313 | * Returns the position in screen. Left abstract to allow for specific implementations such as 314 | * caching behavior. 315 | */ 316 | private Point getPositionInScreen() { 317 | PointF pointF = getPositionInScreen(this); 318 | return new Point((int) pointF.x, (int) pointF.y); 319 | } 320 | 321 | /** 322 | * Finds the Point of the parent view, and offsets result by self getX() and getY(). 323 | * @return Point determining position of the passed in view inside all of its ViewParents. 324 | */ 325 | private PointF getPositionInScreen(View view) { 326 | if (getParent() == null) { 327 | return new PointF(); 328 | } 329 | 330 | ViewGroup parent; 331 | try { 332 | parent = (ViewGroup) view.getParent(); 333 | } catch (Exception e) { 334 | return new PointF(); 335 | } 336 | 337 | if (parent == null) { 338 | return new PointF(); 339 | } 340 | 341 | PointF point = getPositionInScreen(parent); 342 | point.offset(view.getX(), view.getY()); 343 | return point; 344 | } 345 | 346 | /** 347 | * Users a View reference to create a bitmap, and downscales it using the passed in factor. 348 | * Uses a Rect to crop the view into the bitmap. 349 | * @return Bitmap made from view, downscaled by downscaleFactor. 350 | * @throws NullPointerException 351 | */ 352 | private Bitmap getDownscaledBitmapForView(View view, Rect crop, float downscaleFactor) throws BlurKitException, NullPointerException { 353 | View screenView = view.getRootView(); 354 | 355 | int width = (int) (crop.width() * downscaleFactor); 356 | int height = (int) (crop.height() * downscaleFactor); 357 | 358 | if (screenView.getWidth() <= 0 || screenView.getHeight() <= 0 || width <= 0 || height <= 0) { 359 | throw new BlurKitException("No screen available (width or height = 0)"); 360 | } 361 | 362 | float dx = -crop.left * downscaleFactor; 363 | float dy = -crop.top * downscaleFactor; 364 | 365 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 366 | Canvas canvas = new Canvas(bitmap); 367 | Matrix matrix = new Matrix(); 368 | matrix.preScale(downscaleFactor, downscaleFactor); 369 | matrix.postTranslate(dx, dy); 370 | canvas.setMatrix(matrix); 371 | screenView.draw(canvas); 372 | 373 | return bitmap; 374 | } 375 | 376 | /** 377 | * Sets downscale factor to use pre-blur. 378 | * See {@link #mDownscaleFactor}. 379 | */ 380 | public void setDownscaleFactor(float downscaleFactor) { 381 | this.mDownscaleFactor = downscaleFactor; 382 | 383 | // This field is now bad (it's pre-scaled with downscaleFactor so will need to be re-made) 384 | this.mLockedBitmap = null; 385 | 386 | invalidate(); 387 | } 388 | 389 | /** 390 | * Get downscale factor. 391 | * See {@link #mDownscaleFactor}. 392 | */ 393 | public float getDownscaleFactor() { 394 | return this.mDownscaleFactor; 395 | } 396 | 397 | /** 398 | * Sets blur radius to use on downscaled bitmap. 399 | * See {@link #mBlurRadius}. 400 | */ 401 | public void setBlurRadius(int blurRadius) { 402 | this.mBlurRadius = blurRadius; 403 | 404 | // This field is now bad (it's pre-blurred with blurRadius so will need to be re-made) 405 | this.mLockedBitmap = null; 406 | 407 | invalidate(); 408 | } 409 | 410 | /** 411 | * Get blur radius to use on downscaled bitmap. 412 | * See {@link #mBlurRadius}. 413 | */ 414 | public int getBlurRadius() { 415 | return this.mBlurRadius; 416 | } 417 | 418 | /** 419 | * Sets FPS to invalidate blur. 420 | * See {@link #mFPS}. 421 | */ 422 | public void setFPS(int fps) { 423 | if (mRunning) { 424 | pauseBlur(); 425 | } 426 | 427 | this.mFPS = fps; 428 | 429 | if (mAttachedToWindow) { 430 | startBlur(); 431 | } 432 | } 433 | 434 | /** 435 | * Get FPS value. 436 | * See {@link #mFPS}. 437 | */ 438 | public int getFPS() { 439 | return this.mFPS; 440 | } 441 | 442 | public void setCornerRadius(float cornerRadius) { 443 | this.mCornerRadius = cornerRadius; 444 | if (mImageView != null) { 445 | mImageView.setCornerRadius(cornerRadius); 446 | } 447 | invalidate(); 448 | } 449 | 450 | /** 451 | * Get corner radius value. 452 | * See {@link #mFPS}. 453 | */ 454 | public float getCornerRadius() { 455 | return mCornerRadius; 456 | } 457 | 458 | /** 459 | * Set the alpha value 460 | * See {@link #mAlpha} 461 | */ 462 | public void setAlpha(float alpha) { 463 | mAlpha = alpha; 464 | if (!mViewLocked) { 465 | super.setAlpha(mAlpha); 466 | } 467 | } 468 | 469 | /** 470 | * Get alpha value. 471 | * See {@link #mAlpha} 472 | */ 473 | public float getAlpha() { 474 | return mAlpha; 475 | } 476 | 477 | /** 478 | * Save the view bitmap to be re-used each frame instead of regenerating. 479 | * See {@link #mViewLocked}. 480 | */ 481 | public void lockView() { 482 | mViewLocked = true; 483 | 484 | if (mActivityView != null && mActivityView.get() != null) { 485 | View view = mActivityView.get().getRootView(); 486 | try { 487 | super.setAlpha(0f); 488 | 489 | mLockedBitmap = getDownscaledBitmapForView(view, new Rect(0, 0, view.getWidth(), view.getHeight()), mDownscaleFactor); 490 | 491 | if (Float.isNaN(mAlpha)) { 492 | super.setAlpha(1); 493 | } else { 494 | super.setAlpha(mAlpha); 495 | } 496 | 497 | mLockedBitmap = BlurKit.getInstance().blur(mLockedBitmap, mBlurRadius); 498 | } catch (Exception e) { 499 | // ignore 500 | } 501 | } 502 | } 503 | 504 | /** 505 | * Stop using saved view bitmap. View bitmap will now be re-made each frame. 506 | * See {@link #mViewLocked}. 507 | */ 508 | public void unlockView() { 509 | mViewLocked = false; 510 | mLockedBitmap = null; 511 | } 512 | 513 | /** 514 | * Get the view locked value. 515 | * See {@link #mViewLocked}. 516 | */ 517 | public boolean getViewLocked() { 518 | return mViewLocked; 519 | } 520 | 521 | /** 522 | * Save the view position to be re-used each frame instead of regenerating. 523 | * See {@link #mPositionLocked}. 524 | */ 525 | public void lockPosition() { 526 | mPositionLocked = true; 527 | mLockedPoint = getPositionInScreen(); 528 | } 529 | 530 | /** 531 | * Stop using saved point. Point will now be re-made each frame. 532 | * See {@link #mPositionLocked}. 533 | */ 534 | public void unlockPosition() { 535 | mPositionLocked = false; 536 | mLockedPoint = null; 537 | } 538 | 539 | /** 540 | * Get the locked position value. 541 | * See {@link #mPositionLocked}. 542 | */ 543 | public boolean getPositionLocked() { 544 | return mPositionLocked; 545 | } 546 | 547 | } 548 | -------------------------------------------------------------------------------- /blurkit/src/main/java/io/alterac/blurkit/RoundedImageView.java: -------------------------------------------------------------------------------- 1 | package io.alterac.blurkit; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.PorterDuff; 7 | import android.graphics.PorterDuffXfermode; 8 | import android.graphics.RectF; 9 | import android.graphics.Xfermode; 10 | import android.graphics.drawable.BitmapDrawable; 11 | import android.graphics.drawable.Drawable; 12 | import android.util.AttributeSet; 13 | import android.widget.ImageView; 14 | 15 | public class RoundedImageView extends ImageView { 16 | 17 | private float mCornerRadius = 0; 18 | public static final int DEFAULT_COLOR = 0xff000000; 19 | public static final int DEFAULT_RGB = 0; 20 | 21 | private RectF rectF; 22 | private PorterDuffXfermode porterDuffXfermode; 23 | 24 | public RoundedImageView(Context context) { 25 | super(context, null); 26 | rectF = new RectF(); 27 | porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN); 28 | } 29 | 30 | public RoundedImageView(Context context, AttributeSet attributes) { 31 | super(context, attributes); 32 | rectF = new RectF(); 33 | porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN); 34 | } 35 | 36 | @Override 37 | protected void onDraw(Canvas canvas) { 38 | Drawable myDrawable = getDrawable(); 39 | if (myDrawable!=null && myDrawable instanceof BitmapDrawable && mCornerRadius > 0) { 40 | rectF.set(myDrawable.getBounds()); 41 | int prevCount = canvas.saveLayer(rectF, null, Canvas.ALL_SAVE_FLAG); 42 | getImageMatrix().mapRect(rectF); 43 | 44 | Paint paint = ((BitmapDrawable) myDrawable).getPaint(); 45 | paint.setAntiAlias(true); 46 | paint.setColor(DEFAULT_COLOR); 47 | Xfermode prevMode = paint.getXfermode(); 48 | 49 | canvas.drawARGB(DEFAULT_RGB, DEFAULT_RGB, DEFAULT_RGB, DEFAULT_RGB); 50 | canvas.drawRoundRect(rectF, mCornerRadius, mCornerRadius, paint); 51 | 52 | paint.setXfermode(porterDuffXfermode); 53 | super.onDraw(canvas); 54 | 55 | paint.setXfermode(prevMode); 56 | canvas.restoreToCount(prevCount); 57 | } else { 58 | super.onDraw(canvas); 59 | } 60 | } 61 | 62 | public void setCornerRadius(float cornerRadius) { 63 | this.mCornerRadius = cornerRadius; 64 | } 65 | 66 | public float getCornerRadius() { 67 | return this.mCornerRadius; 68 | } 69 | } -------------------------------------------------------------------------------- /blurkit/src/main/res/drawable/original_bk_logo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CameraKit/blurkit-android/f0d181a3850db20f495d5b2c7b825d1fd790d7f2/blurkit/src/main/res/drawable/original_bk_logo.bmp -------------------------------------------------------------------------------- /blurkit/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /blurkit/src/test/java/io/alterac/blurkit/BlurLayoutTest.java: -------------------------------------------------------------------------------- 1 | package io.alterac.blurkit; 2 | 3 | import android.content.Context; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.mockito.Mock; 8 | import org.mockito.MockitoAnnotations; 9 | 10 | import static junit.framework.Assert.assertEquals; 11 | 12 | public class BlurLayoutTest { 13 | 14 | @Mock 15 | private Context mockContext; 16 | 17 | public static final int TEST_INT = 1; 18 | private static final float TEST_FLOAT = 1.1f; 19 | 20 | private BlurLayout blurLayout; 21 | 22 | @Before 23 | public void setupTests() { 24 | MockitoAnnotations.initMocks(this); 25 | 26 | blurLayout = new BlurLayout(mockContext); 27 | } 28 | 29 | @Test 30 | public void setFPSTest() { 31 | blurLayout.setFPS(TEST_INT); 32 | assertEquals(TEST_INT, blurLayout.getFPS()); 33 | } 34 | 35 | @Test 36 | public void setDownscaleFactor() { 37 | blurLayout.setDownscaleFactor(TEST_FLOAT); 38 | assertEquals(TEST_FLOAT, blurLayout.getDownscaleFactor()); 39 | } 40 | 41 | @Test 42 | public void setBlurRadiusTest() { 43 | blurLayout.setBlurRadius(TEST_INT); 44 | assertEquals(TEST_INT, blurLayout.getBlurRadius()); 45 | } 46 | 47 | @Test 48 | public void setCornerRadiusTest() { 49 | blurLayout.setCornerRadius(TEST_FLOAT); 50 | assertEquals(TEST_FLOAT, blurLayout.getCornerRadius()); 51 | } 52 | 53 | @Test 54 | public void unlockViewTest() { 55 | blurLayout.unlockView(); 56 | } 57 | 58 | @Test 59 | public void lockViewTest() { 60 | blurLayout.lockView(); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /blurkit/src/test/java/io/alterac/blurkit/RoundedImageViewTest.java: -------------------------------------------------------------------------------- 1 | package io.alterac.blurkit; 2 | 3 | import android.content.Context; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.mockito.Mock; 8 | import org.mockito.MockitoAnnotations; 9 | 10 | import static junit.framework.Assert.assertEquals; 11 | 12 | public class RoundedImageViewTest { 13 | 14 | @Mock 15 | private Context mockContext; 16 | 17 | private static final float TEST_FLOAT = 1.1f; 18 | 19 | private RoundedImageView roundedImageView; 20 | 21 | @Before 22 | public void setupTests() { 23 | MockitoAnnotations.initMocks(this); 24 | 25 | roundedImageView = new RoundedImageView(mockContext); 26 | } 27 | 28 | @Test 29 | public void setCornerRadiusTest() { 30 | roundedImageView.setCornerRadius(TEST_FLOAT); 31 | assertEquals(TEST_FLOAT, roundedImageView.getCornerRadius()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | google() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.3.0' 10 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.1' 11 | } 12 | } 13 | 14 | allprojects { project -> 15 | group = 'io.alterac.blurkit' 16 | version = '1.1.1' 17 | 18 | repositories { 19 | google() 20 | jcenter() 21 | } 22 | 23 | ext { 24 | versions = [ 25 | minSdk : 17, 26 | targetSdk : 28, 27 | compileSdk : 28, 28 | ] 29 | } 30 | } 31 | 32 | task clean(type: Delete) { 33 | delete rootProject.buildDir 34 | } 35 | -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /demo/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion '28.0.3' 6 | defaultConfig { 7 | applicationId "io.alterac.blurkit.demo" 8 | minSdkVersion 21 9 | targetSdkVersion 28 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | renderscriptTargetApi 28 14 | renderscriptSupportModeEnabled true 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation 'com.android.support:appcompat-v7:28.0.0' 26 | implementation project(':blurkit') 27 | } 28 | -------------------------------------------------------------------------------- /demo/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/dylanmcintyre/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /demo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /demo/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CameraKit/blurkit-android/f0d181a3850db20f495d5b2c7b825d1fd790d7f2/demo/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /demo/src/main/java/io/alterac/blurkit/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package io.alterac.blurkit.demo; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | 8 | import io.alterac.blurkit.BlurLayout; 9 | 10 | public class MainActivity extends AppCompatActivity { 11 | 12 | private BlurLayout blurLayout; 13 | private float movement = 150; 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_main); 19 | blurLayout = (BlurLayout) findViewById(R.id.blurLayout); 20 | 21 | blurLayout.animate().translationY(movement).setDuration(1500).setListener(new AnimatorListenerAdapter() { 22 | @Override 23 | public void onAnimationEnd(Animator animation) { 24 | super.onAnimationEnd(animation); 25 | movement = movement > 0 ? -150 : 150; 26 | blurLayout.animate().translationY(movement).setDuration(1500).setListener(this).start(); 27 | } 28 | }).start(); 29 | } 30 | 31 | @Override 32 | protected void onStart() { 33 | super.onStart(); 34 | blurLayout.startBlur(); 35 | blurLayout.lockView(); 36 | } 37 | 38 | @Override 39 | protected void onStop() { 40 | super.onStop(); 41 | blurLayout.pauseBlur(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable-nodpi/peppers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CameraKit/blurkit-android/f0d181a3850db20f495d5b2c7b825d1fd790d7f2/demo/src/main/res/drawable-nodpi/peppers.png -------------------------------------------------------------------------------- /demo/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CameraKit/blurkit-android/f0d181a3850db20f495d5b2c7b825d1fd790d7f2/demo/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CameraKit/blurkit-android/f0d181a3850db20f495d5b2c7b825d1fd790d7f2/demo/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CameraKit/blurkit-android/f0d181a3850db20f495d5b2c7b825d1fd790d7f2/demo/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CameraKit/blurkit-android/f0d181a3850db20f495d5b2c7b825d1fd790d7f2/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CameraKit/blurkit-android/f0d181a3850db20f495d5b2c7b825d1fd790d7f2/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /demo/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | BlurKit Demo 3 | 4 | -------------------------------------------------------------------------------- /demo/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CameraKit/blurkit-android/f0d181a3850db20f495d5b2c7b825d1fd790d7f2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jan 21 14:18:36 EST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':demo', ':blurkit' 2 | --------------------------------------------------------------------------------