Loading .gitignore +1 −0 Original line number Diff line number Diff line Loading @@ -67,3 +67,4 @@ lint/tmp/ #ktlint ktlint keystore/platform.jks app/build.gradle +19 −5 Original line number Diff line number Diff line Loading @@ -11,6 +11,17 @@ def versionMajor = 1 def versionMinor = 3 def versionPatch = 2 Properties localProps = new Properties() File localPropsFile = project.rootProject.file('local.properties') if (localPropsFile.exists()) { localProps.load(localPropsFile.newDataInputStream()) } def appendDebugSuffix = (localProps.getProperty('appendDebugSuffix') ?: "true").toBoolean() def keyStorePath = localProps.getProperty('keyStorePath') ?: "/keystore/debug.keystore" def keyStorePassword = localProps.getProperty('keyStorePassword') ?: "android" def signingKeyAlias = localProps.getProperty('keyAlias') ?: "androiddebugkey" def signingKeyPassword = localProps.getProperty('keyPassword') ?: "android" android { compileSdkVersion Versions.compile_sdk defaultConfig { Loading @@ -28,9 +39,12 @@ android { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.debug } debug { if (appendDebugSuffix) { applicationIdSuffix '.debug' } signingConfig signingConfigs.debug } Loading @@ -46,10 +60,10 @@ android { signingConfigs { debug { storeFile file(getRootDir().path + "/keystore/debug.keystore") storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' storeFile file(getRootDir().path + keyStorePath) storePassword keyStorePassword keyAlias signingKeyAlias keyPassword signingKeyPassword } } Loading app/src/main/java/foundation/e/blisslauncher/core/Utilities.java +3 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,9 @@ public class Utilities { /** * Use hard coded values to compile with android source. */ public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= 30; public static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= 26; Loading app/src/main/java/foundation/e/blisslauncher/core/blur/BlurDrawable.kt 0 → 100644 +90 −0 Original line number Diff line number Diff line package foundation.e.blisslauncher.core.blur import android.graphics.Bitmap import android.graphics.BitmapShader import android.graphics.Canvas import android.graphics.ColorFilter import android.graphics.Paint import android.graphics.PixelFormat import android.graphics.RectF import android.graphics.Shader import android.graphics.drawable.Drawable class BlurDrawable internal constructor(private val blurWallpaperProvider: BlurWallpaperProvider) : Drawable(), BlurWallpaperProvider.Listener { private var blurAlpha = 255 private val blurPaint = Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG) private var blurBitmap: Bitmap? = null set(value) { if (field != value) { field = value blurPaint.shader = value?.let { BitmapShader(it, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) } } } private val blurBounds = RectF() private var offsetX = 0f private var offsetY = 0f override fun draw(canvas: Canvas) { val width = blurBounds.right.toInt() - blurBounds.left.toInt() val height = blurBounds.bottom.toInt() - blurBounds.top.toInt() if (width <= 0 || height <= 0) return if (blurAlpha == 0) return blurBitmap = blurWallpaperProvider.wallpapers?.second if (blurBitmap == null) { blurBitmap = blurWallpaperProvider.placeholder } val left = blurBounds.left + offsetX val top = blurBounds.top + offsetY val right = blurBounds.right + offsetX val bottom = blurBounds.bottom + offsetY canvas.translate(-left, -top) canvas.drawRect(left, top, right, bottom, blurPaint) canvas.translate(left, top) } override fun setAlpha(alpha: Int) { blurAlpha = alpha blurPaint.alpha = alpha } override fun getAlpha(): Int { return blurAlpha } override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) = setBlurBounds(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) fun setBlurBounds(left: Float, top: Float, right: Float, bottom: Float) { if (blurBounds.left != left || blurBounds.top != top || blurBounds.right != right || blurBounds.bottom != bottom ) { blurBounds.set(left, top, right, bottom) } } fun setOffsets(offsetX: Float, offsetY: Float) { this.offsetX = offsetX this.offsetY = offsetY } override fun getOpacity(): Int = PixelFormat.TRANSLUCENT override fun onWallpaperChanged() { invalidateSelf() } override fun setColorFilter(colorFilter: ColorFilter?) { } fun startListening() = blurWallpaperProvider.addListener(this) fun stopListening() = blurWallpaperProvider.removeListener(this) } app/src/main/java/foundation/e/blisslauncher/core/blur/BlurViewDelegate.kt 0 → 100644 +204 −0 Original line number Diff line number Diff line package foundation.e.blisslauncher.core.blur import android.graphics.BlendMode import android.graphics.Canvas import android.graphics.Outline import android.graphics.Paint import android.graphics.drawable.Drawable import android.util.AttributeSet import android.view.View import android.view.ViewOutlineProvider import android.view.ViewTreeObserver import android.widget.ScrollView import foundation.e.blisslauncher.R import foundation.e.blisslauncher.core.customviews.HorizontalPager import foundation.e.blisslauncher.core.utils.OffsetParent class BlurViewDelegate( private val view: View, attrs: AttributeSet? = null ) : View.OnAttachStateChangeListener, BlurWallpaperProvider.Listener { private val context = view.context private val blurWallpaperProvider by lazy { BlurWallpaperProvider.getInstance(context) } private var fullBlurDrawable: BlurDrawable? = null private var blurAlpha = 255 private val blurDrawableCallback by lazy { object : Drawable.Callback { override fun unscheduleDrawable(who: Drawable, what: Runnable) { } override fun invalidateDrawable(who: Drawable) { view.post(view::invalidate) } override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long) { } } } private var offsetParents = listOf<OffsetParent>() set(value) { field.forEach { it.removeOnOffsetChangeListener(onOffsetChangeListener) } field = value field.forEach { it.addOnOffsetChangeListener(onOffsetChangeListener) } } private val scrollViews = mutableListOf<View>() private var isScrolling = false private var previousScrollX = 0 private var previousScrollY = 0 private var parentOffsetX = 0f private var parentOffsetY = 0f private val onGlobalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener { updateBounds() } private val onScrollChangedListener = ViewTreeObserver.OnScrollChangedListener { isScrolling = true view.invalidate() } private val onOffsetChangeListener = object : OffsetParent.OnOffsetChangeListener { override fun onOffsetChange() { computeParentOffset() } } var blurCornerRadius = 0f val outlineProvider = object : ViewOutlineProvider() { override fun getOutline(view: View, outline: Outline) { outline.setRoundRect(0, 0, view.width, view.height, blurCornerRadius) } } var overlayColor: Int = 0 set(value) { field = value overlayPaint.color = value } private val overlayPaint = Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG).apply { blendMode = BlendMode.OVERLAY } init { createFullBlurDrawable() view.addOnAttachStateChangeListener(this) if (attrs != null) { val a = context.obtainStyledAttributes(attrs, R.styleable.BlurLayout) blurCornerRadius = a.getDimension( R.styleable.BlurLayout_blurCornerRadius, 0f ) overlayColor = a.getColor( R.styleable.BlurLayout_blurOverlayColor, 0 ) a.recycle() } } override fun onViewAttachedToWindow(v: View) { BlurWallpaperProvider.getInstance(context).addListener(this) fullBlurDrawable?.startListening() view.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener) view.viewTreeObserver.addOnScrollChangedListener(onScrollChangedListener) onGlobalLayoutListener.onGlobalLayout() } override fun onViewDetachedFromWindow(v: View) { BlurWallpaperProvider.getInstance(context).removeListener(this) fullBlurDrawable?.stopListening() view.viewTreeObserver.removeOnGlobalLayoutListener(onGlobalLayoutListener) view.viewTreeObserver.removeOnScrollChangedListener(onScrollChangedListener) scrollViews.clear() offsetParents = listOf() } fun draw(canvas: Canvas) { if (isScrolling) { computeScrollOffset() updateOffsets() } fullBlurDrawable?.apply { alpha = blurAlpha this.draw(canvas) } if (overlayColor != 0) { canvas.drawRect( view.left.toFloat(), view.top.toFloat(), view.right.toFloat(), view.bottom.toFloat(), overlayPaint ) } } private fun createFullBlurDrawable() { fullBlurDrawable?.let { if (view.isAttachedToWindow) it.stopListening() } fullBlurDrawable = blurWallpaperProvider.createBlurDrawable().apply { callback = blurDrawableCallback setBounds(view.left, view.top, view.right, view.bottom) if (view.isAttachedToWindow) startListening() } } override fun onEnabledChanged() { createFullBlurDrawable() } private fun updateBounds() { scrollViews.clear() val offsetParents = mutableListOf<OffsetParent>() var left = 0 var top = 0 var current: View? = view while (current != null) { left += current.left top += current.top if (current is ScrollView || current is HorizontalPager) { scrollViews.add(current) } else if (current is OffsetParent) { offsetParents.add(current) } current = current.parent as? View } val right = left + view.width val bottom = top + view.height fullBlurDrawable?.setBlurBounds(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) view.invalidate() this.offsetParents = offsetParents computeScrollOffset() computeParentOffset() } private fun computeScrollOffset() { var scrollX = 0 var scrollY = 0 scrollViews.forEach { scrollX -= it.scrollX scrollY -= it.scrollY } if (previousScrollX == scrollX && previousScrollY == scrollY) { isScrolling = false return } previousScrollX = scrollX previousScrollY = scrollY } private fun computeParentOffset() { var offsetX = 0f var offsetY = 0f offsetParents.forEach { offsetX += it.offsetX offsetY += it.offsetY } this.parentOffsetX = offsetX this.parentOffsetY = offsetY updateOffsets() view.invalidate() } private fun updateOffsets() { fullBlurDrawable?.setOffsets(previousScrollX.toFloat() + parentOffsetX, previousScrollY.toFloat() + parentOffsetY) } } Loading
.gitignore +1 −0 Original line number Diff line number Diff line Loading @@ -67,3 +67,4 @@ lint/tmp/ #ktlint ktlint keystore/platform.jks
app/build.gradle +19 −5 Original line number Diff line number Diff line Loading @@ -11,6 +11,17 @@ def versionMajor = 1 def versionMinor = 3 def versionPatch = 2 Properties localProps = new Properties() File localPropsFile = project.rootProject.file('local.properties') if (localPropsFile.exists()) { localProps.load(localPropsFile.newDataInputStream()) } def appendDebugSuffix = (localProps.getProperty('appendDebugSuffix') ?: "true").toBoolean() def keyStorePath = localProps.getProperty('keyStorePath') ?: "/keystore/debug.keystore" def keyStorePassword = localProps.getProperty('keyStorePassword') ?: "android" def signingKeyAlias = localProps.getProperty('keyAlias') ?: "androiddebugkey" def signingKeyPassword = localProps.getProperty('keyPassword') ?: "android" android { compileSdkVersion Versions.compile_sdk defaultConfig { Loading @@ -28,9 +39,12 @@ android { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.debug } debug { if (appendDebugSuffix) { applicationIdSuffix '.debug' } signingConfig signingConfigs.debug } Loading @@ -46,10 +60,10 @@ android { signingConfigs { debug { storeFile file(getRootDir().path + "/keystore/debug.keystore") storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' storeFile file(getRootDir().path + keyStorePath) storePassword keyStorePassword keyAlias signingKeyAlias keyPassword signingKeyPassword } } Loading
app/src/main/java/foundation/e/blisslauncher/core/Utilities.java +3 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,9 @@ public class Utilities { /** * Use hard coded values to compile with android source. */ public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= 30; public static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= 26; Loading
app/src/main/java/foundation/e/blisslauncher/core/blur/BlurDrawable.kt 0 → 100644 +90 −0 Original line number Diff line number Diff line package foundation.e.blisslauncher.core.blur import android.graphics.Bitmap import android.graphics.BitmapShader import android.graphics.Canvas import android.graphics.ColorFilter import android.graphics.Paint import android.graphics.PixelFormat import android.graphics.RectF import android.graphics.Shader import android.graphics.drawable.Drawable class BlurDrawable internal constructor(private val blurWallpaperProvider: BlurWallpaperProvider) : Drawable(), BlurWallpaperProvider.Listener { private var blurAlpha = 255 private val blurPaint = Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG) private var blurBitmap: Bitmap? = null set(value) { if (field != value) { field = value blurPaint.shader = value?.let { BitmapShader(it, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) } } } private val blurBounds = RectF() private var offsetX = 0f private var offsetY = 0f override fun draw(canvas: Canvas) { val width = blurBounds.right.toInt() - blurBounds.left.toInt() val height = blurBounds.bottom.toInt() - blurBounds.top.toInt() if (width <= 0 || height <= 0) return if (blurAlpha == 0) return blurBitmap = blurWallpaperProvider.wallpapers?.second if (blurBitmap == null) { blurBitmap = blurWallpaperProvider.placeholder } val left = blurBounds.left + offsetX val top = blurBounds.top + offsetY val right = blurBounds.right + offsetX val bottom = blurBounds.bottom + offsetY canvas.translate(-left, -top) canvas.drawRect(left, top, right, bottom, blurPaint) canvas.translate(left, top) } override fun setAlpha(alpha: Int) { blurAlpha = alpha blurPaint.alpha = alpha } override fun getAlpha(): Int { return blurAlpha } override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) = setBlurBounds(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) fun setBlurBounds(left: Float, top: Float, right: Float, bottom: Float) { if (blurBounds.left != left || blurBounds.top != top || blurBounds.right != right || blurBounds.bottom != bottom ) { blurBounds.set(left, top, right, bottom) } } fun setOffsets(offsetX: Float, offsetY: Float) { this.offsetX = offsetX this.offsetY = offsetY } override fun getOpacity(): Int = PixelFormat.TRANSLUCENT override fun onWallpaperChanged() { invalidateSelf() } override fun setColorFilter(colorFilter: ColorFilter?) { } fun startListening() = blurWallpaperProvider.addListener(this) fun stopListening() = blurWallpaperProvider.removeListener(this) }
app/src/main/java/foundation/e/blisslauncher/core/blur/BlurViewDelegate.kt 0 → 100644 +204 −0 Original line number Diff line number Diff line package foundation.e.blisslauncher.core.blur import android.graphics.BlendMode import android.graphics.Canvas import android.graphics.Outline import android.graphics.Paint import android.graphics.drawable.Drawable import android.util.AttributeSet import android.view.View import android.view.ViewOutlineProvider import android.view.ViewTreeObserver import android.widget.ScrollView import foundation.e.blisslauncher.R import foundation.e.blisslauncher.core.customviews.HorizontalPager import foundation.e.blisslauncher.core.utils.OffsetParent class BlurViewDelegate( private val view: View, attrs: AttributeSet? = null ) : View.OnAttachStateChangeListener, BlurWallpaperProvider.Listener { private val context = view.context private val blurWallpaperProvider by lazy { BlurWallpaperProvider.getInstance(context) } private var fullBlurDrawable: BlurDrawable? = null private var blurAlpha = 255 private val blurDrawableCallback by lazy { object : Drawable.Callback { override fun unscheduleDrawable(who: Drawable, what: Runnable) { } override fun invalidateDrawable(who: Drawable) { view.post(view::invalidate) } override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long) { } } } private var offsetParents = listOf<OffsetParent>() set(value) { field.forEach { it.removeOnOffsetChangeListener(onOffsetChangeListener) } field = value field.forEach { it.addOnOffsetChangeListener(onOffsetChangeListener) } } private val scrollViews = mutableListOf<View>() private var isScrolling = false private var previousScrollX = 0 private var previousScrollY = 0 private var parentOffsetX = 0f private var parentOffsetY = 0f private val onGlobalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener { updateBounds() } private val onScrollChangedListener = ViewTreeObserver.OnScrollChangedListener { isScrolling = true view.invalidate() } private val onOffsetChangeListener = object : OffsetParent.OnOffsetChangeListener { override fun onOffsetChange() { computeParentOffset() } } var blurCornerRadius = 0f val outlineProvider = object : ViewOutlineProvider() { override fun getOutline(view: View, outline: Outline) { outline.setRoundRect(0, 0, view.width, view.height, blurCornerRadius) } } var overlayColor: Int = 0 set(value) { field = value overlayPaint.color = value } private val overlayPaint = Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG).apply { blendMode = BlendMode.OVERLAY } init { createFullBlurDrawable() view.addOnAttachStateChangeListener(this) if (attrs != null) { val a = context.obtainStyledAttributes(attrs, R.styleable.BlurLayout) blurCornerRadius = a.getDimension( R.styleable.BlurLayout_blurCornerRadius, 0f ) overlayColor = a.getColor( R.styleable.BlurLayout_blurOverlayColor, 0 ) a.recycle() } } override fun onViewAttachedToWindow(v: View) { BlurWallpaperProvider.getInstance(context).addListener(this) fullBlurDrawable?.startListening() view.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener) view.viewTreeObserver.addOnScrollChangedListener(onScrollChangedListener) onGlobalLayoutListener.onGlobalLayout() } override fun onViewDetachedFromWindow(v: View) { BlurWallpaperProvider.getInstance(context).removeListener(this) fullBlurDrawable?.stopListening() view.viewTreeObserver.removeOnGlobalLayoutListener(onGlobalLayoutListener) view.viewTreeObserver.removeOnScrollChangedListener(onScrollChangedListener) scrollViews.clear() offsetParents = listOf() } fun draw(canvas: Canvas) { if (isScrolling) { computeScrollOffset() updateOffsets() } fullBlurDrawable?.apply { alpha = blurAlpha this.draw(canvas) } if (overlayColor != 0) { canvas.drawRect( view.left.toFloat(), view.top.toFloat(), view.right.toFloat(), view.bottom.toFloat(), overlayPaint ) } } private fun createFullBlurDrawable() { fullBlurDrawable?.let { if (view.isAttachedToWindow) it.stopListening() } fullBlurDrawable = blurWallpaperProvider.createBlurDrawable().apply { callback = blurDrawableCallback setBounds(view.left, view.top, view.right, view.bottom) if (view.isAttachedToWindow) startListening() } } override fun onEnabledChanged() { createFullBlurDrawable() } private fun updateBounds() { scrollViews.clear() val offsetParents = mutableListOf<OffsetParent>() var left = 0 var top = 0 var current: View? = view while (current != null) { left += current.left top += current.top if (current is ScrollView || current is HorizontalPager) { scrollViews.add(current) } else if (current is OffsetParent) { offsetParents.add(current) } current = current.parent as? View } val right = left + view.width val bottom = top + view.height fullBlurDrawable?.setBlurBounds(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) view.invalidate() this.offsetParents = offsetParents computeScrollOffset() computeParentOffset() } private fun computeScrollOffset() { var scrollX = 0 var scrollY = 0 scrollViews.forEach { scrollX -= it.scrollX scrollY -= it.scrollY } if (previousScrollX == scrollX && previousScrollY == scrollY) { isScrolling = false return } previousScrollX = scrollX previousScrollY = scrollY } private fun computeParentOffset() { var offsetX = 0f var offsetY = 0f offsetParents.forEach { offsetX += it.offsetX offsetY += it.offsetY } this.parentOffsetX = offsetX this.parentOffsetY = offsetY updateOffsets() view.invalidate() } private fun updateOffsets() { fullBlurDrawable?.setOffsets(previousScrollX.toFloat() + parentOffsetX, previousScrollY.toFloat() + parentOffsetY) } }