diff --git a/.gitignore b/.gitignore index 20ff14c5a315ebbe4e347d8f4d4e55559eec1779..ee300829817fe191e43e3a3d6959d00ebd750621 100755 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,4 @@ lint/tmp/ #ktlint ktlint +keystore/platform.jks diff --git a/app/build.gradle b/app/build.gradle index 2488c2f29a7cbde9cbe6be9a2c477cc893708613..44138b180cc112fb8d1e531388940d6dbf72236a 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -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 { @@ -28,9 +39,12 @@ android { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.debug } debug { - applicationIdSuffix '.debug' + if (appendDebugSuffix) { + applicationIdSuffix '.debug' + } signingConfig signingConfigs.debug } @@ -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 } } diff --git a/app/src/main/java/foundation/e/blisslauncher/core/Utilities.java b/app/src/main/java/foundation/e/blisslauncher/core/Utilities.java index 502746241a80d7d684a690bf79d32309d893223f..51492aa865ab082756671eac81e0c7f454d24fc7 100755 --- a/app/src/main/java/foundation/e/blisslauncher/core/Utilities.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/Utilities.java @@ -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; diff --git a/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurDrawable.kt b/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurDrawable.kt new file mode 100644 index 0000000000000000000000000000000000000000..38caeddb83058f1943e125203dabe3867c28a7ee --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurDrawable.kt @@ -0,0 +1,90 @@ +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) +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurViewDelegate.kt b/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurViewDelegate.kt new file mode 100644 index 0000000000000000000000000000000000000000..e2d4c725181ed8239140c21a282406243dede5e2 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurViewDelegate.kt @@ -0,0 +1,204 @@ +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() + set(value) { + field.forEach { it.removeOnOffsetChangeListener(onOffsetChangeListener) } + field = value + field.forEach { it.addOnOffsetChangeListener(onOffsetChangeListener) } + } + private val scrollViews = mutableListOf() + 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() + 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) + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurWallpaperFilter.kt b/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurWallpaperFilter.kt index 30fb67121069fb22dd4e7f7140c4235d9350472b..6c1df95761a1b313767de1c972ed2d8526add8e0 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurWallpaperFilter.kt +++ b/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurWallpaperFilter.kt @@ -3,31 +3,43 @@ package foundation.e.blisslauncher.core.blur import android.content.Context import android.graphics.Bitmap import com.hoko.blur.HokoBlur -import com.hoko.blur.task.AsyncBlurTask -class BlurWallpaperFilter(private val context: Context) : WallpaperFilter { +typealias BitmapPair = Pair - private var blurRadius = 8 +class BlurWallpaperFilter(private val context: Context) : WallpaperFilter { - override fun apply(wallpaper: Bitmap): WallpaperFilter.ApplyTask { - return WallpaperFilter.ApplyTask.create { emitter -> - HokoBlur.with(context) - .scheme(HokoBlur.SCHEME_NATIVE) - .mode(HokoBlur.MODE_STACK) - .radius(blurRadius) - .sampleFactor(8f) - .forceCopy(false) - .needUpscale(true) - .processor() - .asyncBlur(wallpaper, object : AsyncBlurTask.Callback { - override fun onBlurSuccess(bitmap: Bitmap) { - emitter.onSuccess(bitmap) - } + private var blurRadiusSmall = 8 + private var blurRadiusLarge = 25 - override fun onBlurFailed(error: Throwable?) { - emitter.onError(error!!) - } - }) + override fun apply(wallpaper: Bitmap): WallpaperFilter.ApplyTask { + return WallpaperFilter.ApplyTask.create { emitter -> + var wallpaperSmallBlur: Bitmap? = null + var wallpaperLargeBlur: Bitmap? = null + try { + wallpaperSmallBlur = HokoBlur.with(context) + .scheme(HokoBlur.SCHEME_NATIVE) + .mode(HokoBlur.MODE_STACK) + .radius(blurRadiusSmall) + .sampleFactor(8f) + .forceCopy(false) + .needUpscale(true) + .processor() + .blur(wallpaper) + wallpaperLargeBlur = HokoBlur.with(context) + .scheme(HokoBlur.SCHEME_NATIVE) + .mode(HokoBlur.MODE_STACK) + .radius(blurRadiusLarge) + .sampleFactor(16f) + .forceCopy(false) + .needUpscale(true) + .processor() + .blur(wallpaper) + emitter.onSuccess(Pair(wallpaperSmallBlur, wallpaperLargeBlur)) + } catch (t: Throwable) { + wallpaperSmallBlur?.recycle() + wallpaperLargeBlur?.recycle() + emitter.onError(t) + } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurWallpaperProvider.kt b/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurWallpaperProvider.kt index 68b5f1ccc7e5d46855911e7265998eb53274b678..d3b3b34b7495ac251e50e1b1b6402ef9e69f6a38 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurWallpaperProvider.kt +++ b/app/src/main/java/foundation/e/blisslauncher/core/blur/BlurWallpaperProvider.kt @@ -29,10 +29,11 @@ class BlurWallpaperProvider(val context: Context) { private val listeners = ArrayList() private val displayMetrics = DisplayMetrics() - var wallpaper: Bitmap? = null + var wallpapers: Pair? = null private set(value) { if (field != value) { - field?.recycle() + field?.first?.recycle() + field?.second?.recycle() field = value } } @@ -49,7 +50,7 @@ class BlurWallpaperProvider(val context: Context) { private val mUpdateRunnable = Runnable { updateWallpaper() } private val wallpaperFilter = BlurWallpaperFilter(context) - private var applyTask: WallpaperFilter.ApplyTask? = null + private var applyTask: WallpaperFilter.ApplyTask>? = null private var updatePending = false @@ -99,7 +100,7 @@ class BlurWallpaperProvider(val context: Context) { } if (!isEnabled) { - wallpaper = null + wallpapers = null return } @@ -117,7 +118,7 @@ class BlurWallpaperProvider(val context: Context) { wallpaper = applyVibrancy(wallpaper) applyTask = wallpaperFilter.apply(wallpaper).setCallback { result, error -> if (error == null) { - this@BlurWallpaperProvider.wallpaper = result + this@BlurWallpaperProvider.wallpapers = result runOnMainThread(::notifyWallpaperChanged) wallpaper.recycle() } else { @@ -213,6 +214,10 @@ class BlurWallpaperProvider(val context: Context) { return ShaderBlurDrawable(this) } + fun createBlurDrawable(): BlurDrawable { + return BlurDrawable(this) + } + interface Listener { fun onWallpaperChanged() {} fun onEnabledChanged() {} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/blur/ShaderBlurDrawable.kt b/app/src/main/java/foundation/e/blisslauncher/core/blur/ShaderBlurDrawable.kt index b025aebde727ed2221130183c157d8f97d3aa094..27d906d196e5f6c8003e903bb8443aad7340dccb 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/blur/ShaderBlurDrawable.kt +++ b/app/src/main/java/foundation/e/blisslauncher/core/blur/ShaderBlurDrawable.kt @@ -44,7 +44,7 @@ class ShaderBlurDrawable internal constructor(private val blurWallpaperProvider: fun draw(canvas: Canvas, noRadius: Boolean = false) { if (blurAlpha == 0) return - blurBitmap = blurWallpaperProvider.wallpaper + blurBitmap = blurWallpaperProvider.wallpapers?.first if (blurBitmap == null) { blurBitmap = blurWallpaperProvider.placeholder diff --git a/app/src/main/java/foundation/e/blisslauncher/core/blur/WallpaperFilter.kt b/app/src/main/java/foundation/e/blisslauncher/core/blur/WallpaperFilter.kt index c85321ed76fbc85c543ef392945c6c34e189a6a6..07fd3db646a95c3e11c38696f39b50793fd487c3 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/blur/WallpaperFilter.kt +++ b/app/src/main/java/foundation/e/blisslauncher/core/blur/WallpaperFilter.kt @@ -2,20 +2,20 @@ package foundation.e.blisslauncher.core.blur import android.graphics.Bitmap -interface WallpaperFilter { +interface WallpaperFilter { - fun apply(wallpaper: Bitmap): ApplyTask + fun apply(wallpaper: Bitmap): ApplyTask - class ApplyTask { + class ApplyTask { val emitter = Emitter() - private var result: Bitmap? = null + private var result: T? = null private var error: Throwable? = null - private var callback: ((Bitmap?, Throwable?) -> Unit)? = null + private var callback: ((T?, Throwable?) -> Unit)? = null - fun setCallback(callback: (Bitmap?, Throwable?) -> Unit): ApplyTask { + fun setCallback(callback: (T?, Throwable?) -> Unit): ApplyTask { result?.let { callback(it, null) return this @@ -30,7 +30,7 @@ interface WallpaperFilter { inner class Emitter { - fun onSuccess(result: Bitmap) { + fun onSuccess(result: T) { callback?.let { it(result, null) return @@ -49,8 +49,8 @@ interface WallpaperFilter { companion object { - inline fun create(source: (Emitter) -> Unit): ApplyTask { - return ApplyTask().also { source(it.emitter) } + inline fun create(source: (ApplyTask.Emitter) -> Unit): ApplyTask { + return ApplyTask().also { source(it.emitter) } } } } diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlissFrameLayout.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlissFrameLayout.java index 75793eb0325c8a5fa0af4a830718abb4b9277ef2..33de0a70aad6a78d726b2c8356c47d89b23fd361 100755 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlissFrameLayout.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlissFrameLayout.java @@ -156,6 +156,7 @@ public class BlissFrameLayout extends FrameLayout { final SquareFrameLayout icon = findViewById(R.id.app_icon); final SquareImageView squareImageView = findViewById( R.id.icon_image_view); + icon.enableBlur(); LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) icon.getLayoutParams(); layoutParams.leftMargin = mDeviceProfile.iconDrawablePaddingPx / 2; layoutParams.rightMargin = mDeviceProfile.iconDrawablePaddingPx / 2; diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlurBackgroundView.kt b/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlurBackgroundView.kt index 1022a8982eb1da45b3697b15643105f96c149b45..7774143e138872b82710f0f101e8f8dd7fecdcd7 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlurBackgroundView.kt +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlurBackgroundView.kt @@ -2,10 +2,10 @@ package foundation.e.blisslauncher.core.customviews import android.content.Context import android.graphics.Canvas +import android.graphics.Rect import android.graphics.drawable.Drawable import android.util.AttributeSet import android.view.View -import android.view.WindowInsets import foundation.e.blisslauncher.core.blur.BlurWallpaperProvider import foundation.e.blisslauncher.core.blur.ShaderBlurDrawable import foundation.e.blisslauncher.core.runOnMainThread @@ -55,6 +55,7 @@ class BlurBackgroundView(context: Context, attrs: AttributeSet?) : View(context, alpha = blurAlpha this.draw(canvas) } + canvas.drawARGB((blurAlpha * 0.01).toInt(), 0, 0, 0) } override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { @@ -76,5 +77,5 @@ class BlurBackgroundView(context: Context, attrs: AttributeSet?) : View(context, createFullBlurDrawable() } - override fun setInsets(insets: WindowInsets) {} -} \ No newline at end of file + override fun setInsets(insets: Rect) {} +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlurLayout.kt b/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlurLayout.kt new file mode 100644 index 0000000000000000000000000000000000000000..ca66de1bf6a42f94fa55019bf4dcd80923bdcc77 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/BlurLayout.kt @@ -0,0 +1,27 @@ +package foundation.e.blisslauncher.core.customviews + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import android.widget.FrameLayout +import foundation.e.blisslauncher.core.blur.BlurViewDelegate + +open class BlurLayout @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : FrameLayout(context, attrs) { + + private val delegate = BlurViewDelegate(this, attrs) + + init { + setWillNotDraw(false) + clipToOutline = true + + outlineProvider = delegate.outlineProvider + } + + override fun onDraw(canvas: Canvas) { + delegate.draw(canvas) + super.onDraw(canvas) + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/DockGridLayout.kt b/app/src/main/java/foundation/e/blisslauncher/core/customviews/DockGridLayout.kt index 1baf2cc79638fb97b64b6f8c3b156b7feb065044..6a6d6549c30653a7e98527fa9085a26bd6108889 100755 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/DockGridLayout.kt +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/DockGridLayout.kt @@ -2,109 +2,64 @@ package foundation.e.blisslauncher.core.customviews import android.content.Context import android.graphics.Canvas -import android.graphics.drawable.Drawable +import android.graphics.Rect import android.util.AttributeSet -import android.view.WindowInsets import android.widget.GridLayout import foundation.e.blisslauncher.BlissLauncher -import foundation.e.blisslauncher.core.blur.BlurWallpaperProvider -import foundation.e.blisslauncher.core.blur.ShaderBlurDrawable -import foundation.e.blisslauncher.core.runOnMainThread +import foundation.e.blisslauncher.core.blur.BlurViewDelegate +import foundation.e.blisslauncher.core.utils.OffsetParent class DockGridLayout @JvmOverloads constructor( private val mContext: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : GridLayout(mContext, attrs, defStyleAttr), Insettable, - BlurWallpaperProvider.Listener { - private val blurWallpaperProvider: BlurWallpaperProvider - private var fullBlurDrawable: ShaderBlurDrawable? = null - private val blurAlpha = 255 - private val blurDrawableCallback: Drawable.Callback = object : Drawable.Callback { - override fun invalidateDrawable(who: Drawable) { - runOnMainThread { - invalidate() - null - } - } +) : GridLayout(mContext, attrs, defStyleAttr), Insettable, OffsetParent { - override fun scheduleDrawable( - who: Drawable, - what: Runnable, - `when`: Long - ) { - } + private val offsetParentDelegate = OffsetParent.OffsetParentDelegate() - override fun unscheduleDrawable( - who: Drawable, - what: Runnable - ) { - } - } + override val offsetX: Float + get() = translationX + override val offsetY: Float + get() = translationY - override fun onAttachedToWindow() { - super.onAttachedToWindow() - BlurWallpaperProvider.getInstance(mContext).addListener(this) - fullBlurDrawable!!.startListening() - } + private val blurDelegate = BlurViewDelegate(this, attrs) - override fun onDetachedFromWindow() { - super.onDetachedFromWindow() - BlurWallpaperProvider.getInstance(mContext).removeListener(this) - fullBlurDrawable!!.stopListening() + init { + setWillNotDraw(false) } override fun onDraw(canvas: Canvas) { - fullBlurDrawable!!.alpha = blurAlpha - fullBlurDrawable!!.draw(canvas) + blurDelegate.draw(canvas) super.onDraw(canvas) } - override fun onLayout( - changed: Boolean, - left: Int, - top: Int, - right: Int, - bottom: Int - ) { - super.onLayout(changed, left, top, right, bottom) - if (changed) { - fullBlurDrawable!!.setBounds(left, top, right, bottom) - } - } - - override fun setInsets(insets: WindowInsets?) { - if (insets == null) return + override fun setInsets(insets: Rect) { val deviceProfile = BlissLauncher.getApplication(mContext).deviceProfile val lp = layoutParams as InsettableRelativeLayout.LayoutParams - lp.height = deviceProfile.hotseatCellHeightPx + insets.systemWindowInsetBottom + lp.height = deviceProfile.hotseatCellHeightPx + insets.bottom setPadding( deviceProfile.iconDrawablePaddingPx / 2, 0, - deviceProfile.iconDrawablePaddingPx / 2, insets.systemWindowInsetBottom + deviceProfile.iconDrawablePaddingPx / 2, insets.bottom ) layoutParams = lp } - private fun createBlurDrawable() { - if (isAttachedToWindow) { - fullBlurDrawable!!.stopListening() - } - fullBlurDrawable = blurWallpaperProvider.createDrawable() - fullBlurDrawable!!.callback = blurDrawableCallback - fullBlurDrawable!!.setBounds(left, top, right, bottom) - if (isAttachedToWindow) fullBlurDrawable!!.startListening() + override fun setTranslationX(translationX: Float) { + super.setTranslationX(translationX) + offsetParentDelegate.notifyOffsetChanged() } - override fun onEnabledChanged() { - createBlurDrawable() + override fun setTranslationY(translationY: Float) { + super.setTranslationY(translationY) + offsetParentDelegate.notifyOffsetChanged() } - override fun onWallpaperChanged() {} + override fun addOnOffsetChangeListener(listener: OffsetParent.OnOffsetChangeListener) { + offsetParentDelegate.addOnOffsetChangeListener(listener) + } - init { - setWillNotDraw(false) - blurWallpaperProvider = BlurWallpaperProvider.getInstance(mContext) - createBlurDrawable() + override fun removeOnOffsetChangeListener(listener: OffsetParent.OnOffsetChangeListener) { + offsetParentDelegate.removeOnOffsetChangeListener(listener) } -} \ No newline at end of file +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/HorizontalPager.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/HorizontalPager.java index aa8cdf20685d7740151faf1739de51d931b09722..ce528caa3d4a10e4714fd764866760af257226ea 100755 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/HorizontalPager.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/HorizontalPager.java @@ -15,7 +15,6 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; -import android.view.WindowInsets; import android.widget.Scroller; import androidx.core.view.GestureDetectorCompat; @@ -64,7 +63,7 @@ public class HorizontalPager extends ViewGroup implements Insettable { private Set mListeners = new HashSet<>(); private boolean mIsUiCreated; private GestureDetectorCompat gestureDetectorCompat; - private WindowInsets insets; + private Rect insets; private float mLastMotionRawY; public HorizontalPager(Context context, AttributeSet attrs) { @@ -179,11 +178,19 @@ public class HorizontalPager extends ViewGroup implements Insettable { pageWidth = pageWidthSpec == SPEC_UNDEFINED ? getMeasuredWidth() : pageWidthSpec; pageWidth = Math.min(pageWidth, getMeasuredWidth()); + int pageHeight = MeasureSpec.getSize(heightMeasureSpec); final int count = getChildCount(); for (int i = 0; i < count; i++) { - getChildAt(i).measure(MeasureSpec.makeMeasureSpec(pageWidth, MeasureSpec.EXACTLY), - heightMeasureSpec); + int childWidth = pageWidth; + int childHeight = pageHeight; + View child = getChildAt(i); + if (!(child instanceof Insettable)) { + childWidth -= insets.width(); + childHeight -= insets.height(); + } + child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)); } if (firstLayout) { @@ -200,9 +207,17 @@ public class HorizontalPager extends ViewGroup implements Insettable { for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != View.GONE) { - final int childWidth = child.getMeasuredWidth(); - child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight()); + int childWidth = child.getMeasuredWidth(); + int childTop = 0; + if (!(child instanceof Insettable)) { + childLeft += insets.left; + childTop += insets.top; + } + child.layout(childLeft, childTop, childLeft + childWidth, child.getMeasuredHeight()); childLeft += childWidth; + if (!(child instanceof Insettable)) { + childLeft += insets.right; + } } } } @@ -542,11 +557,8 @@ public class HorizontalPager extends ViewGroup implements Insettable { } @Override - public void setInsets(WindowInsets insets) { - if(insets == null) return; - InsettableRelativeLayout.LayoutParams lp = (InsettableRelativeLayout.LayoutParams) getLayoutParams(); - lp.topMargin = insets.getSystemWindowInsetTop(); - setLayoutParams(lp); + public void setInsets(Rect insets) { + if (insets == null) return; updateInsetsForChildren(); this.insets = insets; postInvalidate(); diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/Insettable.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/Insettable.java index 91d686b7790e94b225a93e681041a9443139a4e5..5e89d2590517c84edf2863bd32ec6a0eecc9c3db 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/Insettable.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/Insettable.java @@ -1,7 +1,7 @@ package foundation.e.blisslauncher.core.customviews; +import android.graphics.Rect; import android.view.View; -import android.view.WindowInsets; /** * Allows the implementing {@link View} to not draw underneath system bars. @@ -9,5 +9,5 @@ import android.view.WindowInsets; */ public interface Insettable { - void setInsets(WindowInsets insets); + void setInsets(Rect insets); } diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableFrameLayout.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableFrameLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..af588399b5d76a0d968a9531e212ac573a206176 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableFrameLayout.java @@ -0,0 +1,111 @@ +package foundation.e.blisslauncher.core.customviews; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewDebug; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import foundation.e.blisslauncher.R; + +public class InsettableFrameLayout extends FrameLayout implements Insettable { + + @ViewDebug.ExportedProperty(category = "launcher") + protected Rect mInsets = new Rect(); + + public Rect getInsets() { + return mInsets; + } + + public InsettableFrameLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setFrameLayoutChildInsets(View child, Rect newInsets, Rect oldInsets) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (child instanceof Insettable) { + ((Insettable) child).setInsets(newInsets); + } else if (!lp.ignoreInsets) { + lp.topMargin += (newInsets.top - oldInsets.top); + lp.leftMargin += (newInsets.left - oldInsets.left); + lp.rightMargin += (newInsets.right - oldInsets.right); + lp.bottomMargin += (newInsets.bottom - oldInsets.bottom); + } + child.setLayoutParams(lp); + } + + @Override + public void setInsets(Rect insets) { + final int n = getChildCount(); + for (int i = 0; i < n; i++) { + final View child = getChildAt(i); + setFrameLayoutChildInsets(child, insets, mInsets); + } + mInsets.set(insets); + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new InsettableFrameLayout.LayoutParams(getContext(), attrs); + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + } + + // Override to allow type-checking of LayoutParams. + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof InsettableFrameLayout.LayoutParams; + } + + @Override + protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return new LayoutParams(p); + } + + public static class LayoutParams extends FrameLayout.LayoutParams { + public boolean ignoreInsets = false; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + TypedArray a = c.obtainStyledAttributes(attrs, + R.styleable.InsettableFrameLayout_Layout); + ignoreInsets = a.getBoolean( + R.styleable.InsettableFrameLayout_Layout_layout_ignoreInsets, false); + a.recycle(); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(ViewGroup.LayoutParams lp) { + super(lp); + } + } + + @Override + public void onViewAdded(View child) { + super.onViewAdded(child); + if (!isAttachedToWindow()) { + return; + } + setFrameLayoutChildInsets(child, mInsets, new Rect()); + } + + public static void dispatchInsets(ViewGroup parent, Rect insets) { + final int n = parent.getChildCount(); + for (int i = 0; i < n; i++) { + final View child = parent.getChildAt(i); + if (child instanceof Insettable) { + ((Insettable) child).setInsets(insets); + } + } + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableFrameLayout.kt b/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableFrameLayout.kt deleted file mode 100644 index b6a214d1ce23f676c9ac5eca32789351ad401516..0000000000000000000000000000000000000000 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableFrameLayout.kt +++ /dev/null @@ -1,21 +0,0 @@ -package foundation.e.blisslauncher.core.customviews - -import android.content.Context -import android.util.AttributeSet -import android.view.WindowInsets -import android.widget.FrameLayout -import foundation.e.blisslauncher.BlissLauncher - -class InsettableFrameLayout(private val mContext: Context, attrs: AttributeSet?) : FrameLayout( - mContext, attrs -), Insettable { - - override fun setInsets(insets: WindowInsets?) { - if (insets == null) return - val deviceProfile = BlissLauncher.getApplication(mContext).deviceProfile - setPadding( - paddingLeft, paddingTop, - paddingRight, insets.systemWindowInsetBottom - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableLinearLayout.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableLinearLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..5a37a6aa6ba35c3b18578924274ebc9d2854f9a8 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableLinearLayout.java @@ -0,0 +1,120 @@ +package foundation.e.blisslauncher.core.customviews; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewDebug; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import foundation.e.blisslauncher.R; + +public class InsettableLinearLayout extends LinearLayout implements Insettable { + + @ViewDebug.ExportedProperty(category = "launcher") + protected Rect mInsets = new Rect(); + + private boolean mInsetsSet = false; + + public Rect getInsets() { + return mInsets; + } + + public InsettableLinearLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setLinearLayoutChildInsets(View child, Rect newInsets, Rect oldInsets) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + int childIndex = indexOfChild(child); + int newTop = childIndex == 0 ? newInsets.top : 0; + int oldTop = childIndex == 0 ? oldInsets.top : 0; + int newBottom = childIndex == getChildCount() - 1 ? newInsets.bottom : 0; + int oldBottom = childIndex == getChildCount() - 1 ? oldInsets.bottom : 0; + + if (child instanceof Insettable) { + ((Insettable) child).setInsets(new Rect(newInsets.left, newTop, newInsets.right, newBottom)); + } else if (!lp.ignoreInsets) { + lp.topMargin += (newTop - oldTop); + lp.leftMargin += (newInsets.left - oldInsets.left); + lp.rightMargin += (newInsets.right - oldInsets.right); + lp.bottomMargin += (newBottom - oldBottom); + } + child.setLayoutParams(lp); + } + + @Override + public void setInsets(Rect insets) { + if (getOrientation() != VERTICAL) { + throw new IllegalStateException("Doesn't support horizontal orientation"); + } + mInsetsSet = true; + final int n = getChildCount(); + for (int i = 0; i < n; i++) { + final View child = getChildAt(i); + setLinearLayoutChildInsets(child, insets, mInsets); + } + mInsets.set(insets); + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new InsettableLinearLayout.LayoutParams(getContext(), attrs); + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + } + + // Override to allow type-checking of LayoutParams. + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof InsettableLinearLayout.LayoutParams; + } + + @Override + protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return new LayoutParams(p); + } + + public static class LayoutParams extends LinearLayout.LayoutParams { + boolean ignoreInsets = false; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + TypedArray a = c.obtainStyledAttributes(attrs, + R.styleable.InsettableFrameLayout_Layout); + ignoreInsets = a.getBoolean( + R.styleable.InsettableFrameLayout_Layout_layout_ignoreInsets, false); + a.recycle(); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(ViewGroup.LayoutParams lp) { + super(lp); + } + } + + @Override + public void onViewAdded(View child) { + super.onViewAdded(child); + if (mInsetsSet) { + throw new IllegalStateException("Cannot modify views after insets are set"); + } + } + + @Override + public void onViewRemoved(View child) { + super.onViewRemoved(child); + if (mInsetsSet) { + throw new IllegalStateException("Cannot modify views after insets are set"); + } + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableRelativeLayout.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableRelativeLayout.java index f1122c2ea74c11361f73ffd7569df614e6f4b6db..5337979aa5407e1eef21effeca4b15030bb182ca 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableRelativeLayout.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableRelativeLayout.java @@ -2,6 +2,7 @@ package foundation.e.blisslauncher.core.customviews; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; @@ -14,7 +15,7 @@ import foundation.e.blisslauncher.R; public class InsettableRelativeLayout extends RelativeLayout { private final Context mContext; - protected WindowInsets mInsets; + protected Rect mInsets = new Rect(); public InsettableRelativeLayout(Context context, AttributeSet attrs) { @@ -25,18 +26,18 @@ public class InsettableRelativeLayout extends RelativeLayout { @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { BlissLauncher.getApplication(mContext).resetDeviceProfile(); - updateChildInsets(insets); - mInsets = new WindowInsets(insets); + mInsets.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), + insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()); + updateChildInsets(); return insets; } - private void updateChildInsets(WindowInsets insets) { - if(insets == null) return; + private void updateChildInsets() { int childCount = getChildCount(); for (int index = 0; index < childCount; ++index){ View child = getChildAt(index); if(child instanceof Insettable) { - ((Insettable) child).setInsets(insets); + ((Insettable) child).setInsets(mInsets); } } } @@ -86,6 +87,6 @@ public class InsettableRelativeLayout extends RelativeLayout { @Override public void onViewAdded(View child) { super.onViewAdded(child); - updateChildInsets(mInsets); + updateChildInsets(); } } \ No newline at end of file diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableScrollLayout.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableScrollLayout.java index 126f21834cc0e55fc31ce435b60b6e1a28955520..11fb75640a2a5d9225b202c98a77736bb9ccf682 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableScrollLayout.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/InsettableScrollLayout.java @@ -1,23 +1,102 @@ package foundation.e.blisslauncher.core.customviews; import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Rect; import android.util.AttributeSet; +import android.view.View; +import android.view.ViewDebug; +import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.ScrollView; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; +import foundation.e.blisslauncher.R; -public class InsettableScrollLayout extends ScrollView { +public class InsettableScrollLayout extends ScrollView implements Insettable { - public InsettableScrollLayout(@NonNull Context context) { - super(context); + @ViewDebug.ExportedProperty(category = "launcher") + protected Rect mInsets = new Rect(); + + public Rect getInsets() { + return mInsets; } - public InsettableScrollLayout(@NonNull Context context, @Nullable AttributeSet attrs) { + public InsettableScrollLayout(Context context, AttributeSet attrs) { super(context, attrs); } - public InsettableScrollLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); + public void setFrameLayoutChildInsets(View child, Rect newInsets, Rect oldInsets) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (child instanceof Insettable) { + ((Insettable) child).setInsets(newInsets); + } else if (!lp.ignoreInsets) { + lp.topMargin += (newInsets.top - oldInsets.top); + lp.leftMargin += (newInsets.left - oldInsets.left); + lp.rightMargin += (newInsets.right - oldInsets.right); + lp.bottomMargin += (newInsets.bottom - oldInsets.bottom); + } + child.setLayoutParams(lp); + } + + @Override + public void setInsets(Rect insets) { + final int n = getChildCount(); + for (int i = 0; i < n; i++) { + final View child = getChildAt(i); + setFrameLayoutChildInsets(child, insets, mInsets); + } + mInsets.set(insets); + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(getContext(), attrs); + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + } + + // Override to allow type-checking of LayoutParams. + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof InsettableFrameLayout.LayoutParams; + } + + @Override + protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return new LayoutParams(p); + } + + public static class LayoutParams extends FrameLayout.LayoutParams { + public boolean ignoreInsets = false; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + TypedArray a = c.obtainStyledAttributes(attrs, + R.styleable.InsettableFrameLayout_Layout); + ignoreInsets = a.getBoolean( + R.styleable.InsettableFrameLayout_Layout_layout_ignoreInsets, false); + a.recycle(); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(ViewGroup.LayoutParams lp) { + super(lp); + } + } + + @Override + public void onViewAdded(View child) { + super.onViewAdded(child); + if (!isAttachedToWindow()) { + return; + } + setFrameLayoutChildInsets(child, mInsets, new Rect()); } } diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java index 101be1547f41d321ba33ab3e55ef9a9392586976..ab5559e4bfe251a734ade64c73ac089522312a0c 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java @@ -15,6 +15,7 @@ import android.widget.ImageView; import androidx.annotation.Nullable; import foundation.e.blisslauncher.R; +import foundation.e.blisslauncher.core.blur.BlurViewDelegate; import foundation.e.blisslauncher.features.widgets.CheckLongPressHelper; public class RoundedWidgetView extends AppWidgetHostView { @@ -33,11 +34,20 @@ public class RoundedWidgetView extends AppWidgetHostView { private boolean activated = false; - public RoundedWidgetView(Context context) { + private BlurViewDelegate mBlurDelegate = null; + + public RoundedWidgetView(Context context, boolean blurBackground) { super(context); this.mContext = context; this.cornerRadius = context.getResources().getDimensionPixelSize(R.dimen.corner_radius); mLongPressHelper = new CheckLongPressHelper(this); + if (blurBackground) { + mBlurDelegate = new BlurViewDelegate(this, null); + mBlurDelegate.setBlurCornerRadius(cornerRadius); + setWillNotDraw(false); + setOutlineProvider(mBlurDelegate.getOutlineProvider()); + setClipToOutline(true); + } } @Override @@ -59,6 +69,14 @@ public class RoundedWidgetView extends AppWidgetHostView { canvas.restoreToCount(save); } + @Override + protected void onDraw(Canvas canvas) { + if (mBlurDelegate != null) { + mBlurDelegate.draw(canvas); + } + super.onDraw(canvas); + } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.d(TAG, "onInterceptTouchEvent() called with: ev = [" + ev.getAction() + "]"); diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/SquareFrameLayout.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/SquareFrameLayout.java index 67e4b0c262805ecafdc0f3be37bf21f38049cfe3..468abdcf52954b42506e4c276353e39a75cdf2e9 100755 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/SquareFrameLayout.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/SquareFrameLayout.java @@ -1,18 +1,24 @@ package foundation.e.blisslauncher.core.customviews; import android.content.Context; +import android.graphics.Canvas; import android.util.AttributeSet; import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import foundation.e.blisslauncher.core.DeviceProfile; +import foundation.e.blisslauncher.core.blur.BlurViewDelegate; + /** * Created by falcon on 9/3/18. */ public class SquareFrameLayout extends FrameLayout { + private BlurViewDelegate mBlurDelegate = null; + public SquareFrameLayout(@NonNull Context context) { this(context, null); } @@ -37,4 +43,20 @@ public class SquareFrameLayout extends FrameLayout { int size = width < height ? width : height; setMeasuredDimension(size, size); } + + public void enableBlur() { + mBlurDelegate = new BlurViewDelegate(this, null); + setWillNotDraw(false); + } + + @Override + protected void onDraw(Canvas canvas) { + if (mBlurDelegate != null) { + int count = canvas.save(); + canvas.clipPath(DeviceProfile.path); + mBlurDelegate.draw(canvas); + canvas.restoreToCount(count); + } + super.onDraw(canvas); + } } diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/SwipeSearchContainer.kt b/app/src/main/java/foundation/e/blisslauncher/core/customviews/SwipeSearchContainer.kt new file mode 100644 index 0000000000000000000000000000000000000000..5c9654746dab4fbc92a0d6c17f85eb59cbe5e4bc --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/SwipeSearchContainer.kt @@ -0,0 +1,37 @@ +package foundation.e.blisslauncher.core.customviews + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout +import foundation.e.blisslauncher.core.utils.OffsetParent + +class SwipeSearchContainer @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : FrameLayout(context, attrs), OffsetParent { + + private val offsetParentDelegate = OffsetParent.OffsetParentDelegate() + + override val offsetX: Float + get() = translationX + override val offsetY: Float + get() = translationY + + override fun setTranslationX(translationX: Float) { + super.setTranslationX(translationX) + offsetParentDelegate.notifyOffsetChanged() + } + + override fun setTranslationY(translationY: Float) { + super.setTranslationY(translationY) + offsetParentDelegate.notifyOffsetChanged() + } + + override fun addOnOffsetChangeListener(listener: OffsetParent.OnOffsetChangeListener) { + offsetParentDelegate.addOnOffsetChangeListener(listener) + } + + override fun removeOnOffsetChangeListener(listener: OffsetParent.OnOffsetChangeListener) { + offsetParentDelegate.removeOnOffsetChangeListener(listener) + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/WidgetHost.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/WidgetHost.java index 50c4f2725bd17c30a3be70779d7ba3dfe6419e02..6d03fea9adc414a7906b243826c18c52578283bd 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/WidgetHost.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/WidgetHost.java @@ -3,10 +3,14 @@ package foundation.e.blisslauncher.core.customviews; import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; +import android.content.ComponentName; import android.content.Context; +import android.view.ContextThemeWrapper; +import foundation.e.blisslauncher.core.utils.ThemesKt; import foundation.e.blisslauncher.features.weather.WeatherAppWidgetProvider; import foundation.e.blisslauncher.features.weather.WeatherWidgetHostView; +import foundation.e.blisslauncher.features.widgets.DefaultWidgets; public class WidgetHost extends AppWidgetHost { @@ -17,9 +21,12 @@ public class WidgetHost extends AppWidgetHost { @Override protected AppWidgetHostView onCreateView(Context context, int appWidgetId, AppWidgetProviderInfo appWidget) { if (appWidget.provider.equals(WeatherAppWidgetProvider.COMPONENT_NAME)) { - return new WeatherWidgetHostView(context); + Context themedContext = new ContextThemeWrapper(context, ThemesKt.getActivityThemeRes(context)); + return new WeatherWidgetHostView(themedContext); } - return new RoundedWidgetView(context); + ComponentName provider = appWidget.provider; + boolean isDefaultWidget = DefaultWidgets.INSTANCE.getWidgets().contains(provider); + return new RoundedWidgetView(context, isDefaultWidget); } @Override diff --git a/app/src/main/java/foundation/e/blisslauncher/core/utils/DepthManager.kt b/app/src/main/java/foundation/e/blisslauncher/core/utils/DepthManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..3cb2c714612f25ab649e8c2e54bb81be8964aee4 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/utils/DepthManager.kt @@ -0,0 +1,29 @@ +package foundation.e.blisslauncher.core.utils + +import android.app.WallpaperManager +import android.os.IBinder +import android.view.View +import foundation.e.blisslauncher.features.launcher.LauncherActivity + +class DepthManager(private val launcher: LauncherActivity) { + + private val wallpaperManager = launcher.getSystemService(WallpaperManager::class.java)!! + private val setWallpaperZoomOut = WallpaperManager::class.java.getMethod( + "setWallpaperZoomOut", IBinder::class.java, Float::class.java) + + init { + launcher.rootView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(v: View) { + updateDepth() + } + + override fun onViewDetachedFromWindow(v: View) { + } + }) + } + + fun updateDepth() { + val windowToken = launcher.rootView.windowToken + setWallpaperZoomOut.invoke(wallpaperManager, windowToken, 1) + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/utils/GraphicsUtil.java b/app/src/main/java/foundation/e/blisslauncher/core/utils/GraphicsUtil.java index 05296a8c5733cee582595e9044baee320c8b9b8d..305d123981458f81344f681759b7f42058e14d79 100755 --- a/app/src/main/java/foundation/e/blisslauncher/core/utils/GraphicsUtil.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/utils/GraphicsUtil.java @@ -29,19 +29,22 @@ import java.util.HashMap; import java.util.Map; import foundation.e.blisslauncher.BlissLauncher; +import foundation.e.blisslauncher.R; import foundation.e.blisslauncher.core.DeviceProfile; import foundation.e.blisslauncher.core.database.model.FolderItem; public class GraphicsUtil { private static final String TAG = "BLISS_GRAPHICS"; - private Context mContext; - private int appIconWidth; + private final Context mContext; + private final int appIconWidth; + private final int mFolderPreviewBackgroundColor; public GraphicsUtil(Context context) { this.mContext = context; DeviceProfile deviceProfile = BlissLauncher.getApplication(context).getDeviceProfile(); this.appIconWidth = deviceProfile.iconSizePx; + mFolderPreviewBackgroundColor = mContext.getColor(R.color.folder_preview_background_color); } /** @@ -129,7 +132,7 @@ public class GraphicsUtil { Bitmap mergedBitmap = Bitmap.createBitmap(width, height, Bitmap .Config.ARGB_8888); Canvas canvas = new Canvas(mergedBitmap); - canvas.drawColor(isFolder ? 0x88D3D3D3 : getDominantColor(bitmap)); + canvas.drawColor(isFolder ? mFolderPreviewBackgroundColor : getDominantColor(bitmap)); Paint paint = new Paint( Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG); diff --git a/app/src/main/java/foundation/e/blisslauncher/core/utils/OffsetParent.kt b/app/src/main/java/foundation/e/blisslauncher/core/utils/OffsetParent.kt new file mode 100644 index 0000000000000000000000000000000000000000..9aa08172e423d0188d1ca0138fbeffc52d2665c7 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/utils/OffsetParent.kt @@ -0,0 +1,32 @@ +package foundation.e.blisslauncher.core.utils + +import java.util.concurrent.CopyOnWriteArrayList + +interface OffsetParent { + + val offsetX: Float + val offsetY: Float + + fun addOnOffsetChangeListener(listener: OnOffsetChangeListener) + fun removeOnOffsetChangeListener(listener: OnOffsetChangeListener) + + interface OnOffsetChangeListener { + fun onOffsetChange() + } + + class OffsetParentDelegate() { + private val listeners = CopyOnWriteArrayList() + + fun notifyOffsetChanged() { + listeners.forEach { it.onOffsetChange() } + } + + fun addOnOffsetChangeListener(listener: OnOffsetChangeListener) { + listeners.add(listener) + } + + fun removeOnOffsetChangeListener(listener: OnOffsetChangeListener) { + listeners.remove(listener) + } + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/utils/Themes.kt b/app/src/main/java/foundation/e/blisslauncher/core/utils/Themes.kt new file mode 100644 index 0000000000000000000000000000000000000000..0315bc4510fdfd1bc375e654c309f015c8f6d476 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/utils/Themes.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2022 /e/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package foundation.e.blisslauncher.core.utils + +import android.content.Context +import foundation.e.blisslauncher.R +import foundation.e.blisslauncher.core.wallpaper.WallpaperColorsCompat.Companion.HINT_SUPPORTS_DARK_TEXT +import foundation.e.blisslauncher.core.wallpaper.WallpaperManagerCompat + +@JvmOverloads +fun getActivityThemeRes( + context: Context, + colorHints: Int = WallpaperManagerCompat.getInstance(context).colorHints +): Int { + val supportsDarkText = (colorHints and HINT_SUPPORTS_DARK_TEXT) != 0 + return if (supportsDarkText) R.style.HomeScreenTheme_DarkText else R.style.HomeScreenTheme +} + +fun isWorkspaceDarkText(context: Context) = getAttrBoolean(context, R.attr.isWorkspaceDarkText) + +fun getAttrBoolean(context: Context, attr: Int): Boolean { + val ta = context.obtainStyledAttributes(intArrayOf(attr)) + val value = ta.getBoolean(0, false) + ta.recycle() + return value +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/wallpaper/WallpaperColorsCompat.kt b/app/src/main/java/foundation/e/blisslauncher/core/wallpaper/WallpaperColorsCompat.kt new file mode 100644 index 0000000000000000000000000000000000000000..98430cc69d4855089a223c079423c7425907ab88 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/wallpaper/WallpaperColorsCompat.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2022 /e/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package foundation.e.blisslauncher.core.wallpaper + +import androidx.annotation.IntDef + +data class WallpaperColorsCompat( + val primaryColor: Int, + @ColorsHints val colorHints: Int +) { + + companion object { + + const val HINT_SUPPORTS_DARK_TEXT = 0x1 + const val HINT_SUPPORTS_DARK_THEME = 0x2 + + @IntDef( + value = [HINT_SUPPORTS_DARK_TEXT, HINT_SUPPORTS_DARK_THEME], + flag = true + ) + @Retention( + AnnotationRetention.SOURCE + ) + annotation class ColorsHints + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/core/wallpaper/WallpaperManagerCompat.kt b/app/src/main/java/foundation/e/blisslauncher/core/wallpaper/WallpaperManagerCompat.kt new file mode 100644 index 0000000000000000000000000000000000000000..c0b588ab1f64aaee1043e02e81d08bfb582a5661 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/core/wallpaper/WallpaperManagerCompat.kt @@ -0,0 +1,99 @@ +/* + * Copyright 2022 /e/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package foundation.e.blisslauncher.core.wallpaper + +import android.app.WallpaperColors +import android.app.WallpaperManager +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.util.Log +import foundation.e.blisslauncher.core.utils.SingletonHolder +import foundation.e.blisslauncher.core.utils.ensureOnMainThread +import foundation.e.blisslauncher.core.utils.useApplicationContext +import foundation.e.blisslauncher.core.wallpaper.WallpaperColorsCompat.Companion.HINT_SUPPORTS_DARK_THEME +import java.lang.reflect.Method + +class WallpaperManagerCompat(val context: Context) { + + private val TAG = "WallpaperManagerCompat" + + private val listeners = mutableListOf() + private val wallpaperManager = context.getSystemService(WallpaperManager::class.java)!! + + var wallpaperColors: WallpaperColorsCompat? = null + private set + + val colorHints get() = wallpaperColors?.colorHints ?: 0 + val supportsDarkTheme get() = (colorHints and HINT_SUPPORTS_DARK_THEME) != 0 + + private var wcColorHintsMethod: Method? = null + + init { + try { + wcColorHintsMethod = WallpaperColors::class.java.getDeclaredMethod("getColorHints") + } catch (exc: Exception) { + Log.e(TAG, "getColorHints not available", exc) + } + wallpaperManager.addOnColorsChangedListener( + { colors, which -> + if ((which and WallpaperManager.FLAG_SYSTEM) != 0) { + update(colors) + notifyChange() + } + }, + Handler(Looper.getMainLooper()) + ) + update(wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM)) + } + + private fun update(wallpaperColors: WallpaperColors?) { + if (wallpaperColors == null) { + this.wallpaperColors = null + return + } + var hints = 0 + wcColorHintsMethod?.let { + try { + hints = it.invoke(wallpaperColors) as Int + } catch (e: Exception) { + Log.e(TAG, "error calling color hints", e) + } + } + this.wallpaperColors = WallpaperColorsCompat(wallpaperColors.primaryColor.toArgb(), hints) + } + + fun addOnChangeListener(listener: OnColorsChangedListener) { + listeners.add(listener) + } + + fun removeOnChangeListener(listener: OnColorsChangedListener) { + listeners.remove(listener) + } + + private fun notifyChange() { + listeners.toTypedArray().forEach { + it.onColorsChanged() + } + } + + interface OnColorsChangedListener { + fun onColorsChanged() + } + + companion object : + SingletonHolder(ensureOnMainThread(useApplicationContext(::WallpaperManagerCompat))) +} diff --git a/app/src/main/java/foundation/e/blisslauncher/features/launcher/LauncherActivity.java b/app/src/main/java/foundation/e/blisslauncher/features/launcher/LauncherActivity.java index 8ea1b4ccf6d143c0f24e54c4ce0c250602a958eb..17b37d62f5d3a85f444f280b9c5071e09af17401 100755 --- a/app/src/main/java/foundation/e/blisslauncher/features/launcher/LauncherActivity.java +++ b/app/src/main/java/foundation/e/blisslauncher/features/launcher/LauncherActivity.java @@ -1,5 +1,10 @@ package foundation.e.blisslauncher.features.launcher; +import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; +import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -55,6 +60,7 @@ import android.widget.GridLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; +import android.widget.ScrollView; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; @@ -64,7 +70,6 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.view.GestureDetectorCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager.widget.PagerAdapter; @@ -100,7 +105,6 @@ import foundation.e.blisslauncher.core.customviews.DockGridLayout; import foundation.e.blisslauncher.core.customviews.HorizontalPager; import foundation.e.blisslauncher.core.customviews.InsettableFrameLayout; import foundation.e.blisslauncher.core.customviews.InsettableRelativeLayout; -import foundation.e.blisslauncher.core.customviews.InsettableScrollLayout; import foundation.e.blisslauncher.core.customviews.PageIndicatorLinearLayout; import foundation.e.blisslauncher.core.customviews.RoundedWidgetView; import foundation.e.blisslauncher.core.customviews.SquareFrameLayout; @@ -121,9 +125,12 @@ import foundation.e.blisslauncher.core.events.ShortcutAddEvent; import foundation.e.blisslauncher.core.executors.AppExecutors; import foundation.e.blisslauncher.core.utils.AppUtils; import foundation.e.blisslauncher.core.utils.Constants; +import foundation.e.blisslauncher.core.utils.DepthManager; import foundation.e.blisslauncher.core.utils.GraphicsUtil; import foundation.e.blisslauncher.core.utils.ListUtil; +import foundation.e.blisslauncher.core.utils.ThemesKt; import foundation.e.blisslauncher.core.utils.UserHandle; +import foundation.e.blisslauncher.core.wallpaper.WallpaperManagerCompat; import foundation.e.blisslauncher.features.notification.NotificationRepository; import foundation.e.blisslauncher.features.notification.NotificationService; import foundation.e.blisslauncher.features.shortcuts.DeepShortcutManager; @@ -139,6 +146,7 @@ import foundation.e.blisslauncher.features.weather.WeatherPreferences; import foundation.e.blisslauncher.features.weather.WeatherSourceListenerService; import foundation.e.blisslauncher.features.weather.WeatherUpdateService; import foundation.e.blisslauncher.features.weather.WeatherUtils; +import foundation.e.blisslauncher.features.widgets.DefaultWidgets; import foundation.e.blisslauncher.features.widgets.WidgetManager; import foundation.e.blisslauncher.features.widgets.WidgetViewBuilder; import foundation.e.blisslauncher.features.widgets.WidgetsActivity; @@ -150,14 +158,9 @@ import io.reactivex.observers.DisposableObserver; import io.reactivex.schedulers.Schedulers; import me.relex.circleindicator.CircleIndicator; -import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; -import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; -import static android.view.View.GONE; -import static android.view.View.VISIBLE; - public class LauncherActivity extends AppCompatActivity implements AutoCompleteAdapter.OnSuggestionClickListener, - OnSwipeDownListener { + OnSwipeDownListener, WallpaperManagerCompat.OnColorsChangedListener { public static final int REORDER_TIMEOUT = 350; private final static int EMPTY_LOCATION_DRAG = -999; @@ -239,6 +242,11 @@ public class LauncherActivity extends AppCompatActivity implements private GestureDetectorCompat mDetector; private AlertDialog enableLocationDialog; + private DepthManager mDepthManager; + + private int mThemeRes = R.style.HomeScreenTheme; + private LayoutInflater mLightLayoutInflater; + public static LauncherActivity getLauncher(Context context) { if (context instanceof LauncherActivity) { return (LauncherActivity) context; @@ -252,6 +260,13 @@ public class LauncherActivity extends AppCompatActivity implements super.onCreate(savedInstanceState); prepareBroadcastReceivers(); + WallpaperManagerCompat.Companion.getInstance(this).addOnChangeListener(this); + int themeRes = ThemesKt.getActivityThemeRes(this); + if (themeRes != mThemeRes) { + mThemeRes = themeRes; + setTheme(themeRes); + } + oldConfig = new Configuration(getResources().getConfiguration()); mDeviceProfile = BlissLauncher.getApplication(this).getDeviceProfile(); @@ -305,6 +320,23 @@ public class LauncherActivity extends AppCompatActivity implements createOrUpdateIconGrid(); addDefaultWidgets(); + + if (Utilities.ATLEAST_R) { + mDepthManager = new DepthManager(this); + } + + if (ThemesKt.isWorkspaceDarkText(this)) { + int flags = mLauncherView.getSystemUiVisibility(); + flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + flags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; + mLauncherView.setSystemUiVisibility(flags); + } + final ContextThemeWrapper lightContext = new ContextThemeWrapper(this, R.style.HomeScreenTheme); + mLightLayoutInflater = getLayoutInflater().cloneInContext(lightContext); + } + + public View getRootView() { + return mLauncherView; } private void setupViews() { @@ -383,14 +415,14 @@ public class LauncherActivity extends AppCompatActivity implements private void addDefaultWidgets() { if (!Preferences.getAddedEcloudWidget(this)) { - ComponentName provider = new ComponentName("foundation.e.drive", "foundation.e.drive.widgets.EDriveWidget"); + ComponentName provider = DefaultWidgets.INSTANCE.getEcloudWidget(); if (allocateAndBindWidget(provider)) { Preferences.setAddedEcloudWidget(this); } } if (!Preferences.getAddedPrivacyWidget(this)) { - ComponentName provider = new ComponentName("foundation.e.privacycentralapp.e", "foundation.e.privacycentralapp.Widget"); + ComponentName provider = DefaultWidgets.INSTANCE.getPrivacyWidget(); if (allocateAndBindWidget(provider)) { Preferences.setAddedPrivacyWidget(this); } @@ -452,6 +484,10 @@ public class LauncherActivity extends AppCompatActivity implements protected void onResume() { super.onResume(); + if (mDepthManager != null) { + mDepthManager.updateDepth(); + } + if (widgetsPage != null) { refreshSuggestedApps(widgetsPage, forceRefreshSuggestedApps); } @@ -528,6 +564,8 @@ public class LauncherActivity extends AppCompatActivity implements // Clear AppProvider BlissLauncher.getApplication(this).getAppProvider().clear(); + WallpaperManagerCompat.Companion.getInstance(this).removeOnChangeListener(this); + // Handover to android system. super.onDestroy(); } @@ -1164,6 +1202,14 @@ public class LauncherActivity extends AppCompatActivity implements @Override public void onScroll(int scrollX) { + float progress = (float) scrollX / mDeviceProfile.availableWidthPx; + if (progress >= 0.999) progress = 1; + if (progress <= 0.001) progress = 0; + int dockHeight = mDock.getHeight() + mIndicator.getHeight(); + float dockTranslationY = (1 - progress) * dockHeight; + mDock.setTranslationY(dockTranslationY); + mIndicator.setTranslationY(dockTranslationY); + if (scrollX >= 0 && scrollX < mDeviceProfile.availableWidthPx) { float fraction = (float) (mDeviceProfile.availableWidthPx - scrollX) / mDeviceProfile.availableWidthPx; @@ -1183,15 +1229,7 @@ public class LauncherActivity extends AppCompatActivity implements if (currentPageNumber != page) { currentPageNumber = page; - // Remove mIndicator and mDock from widgets page, and make them - // reappear when user swipes to the first apps page if (currentPageNumber == 0) { - mDock.animate().translationYBy( - Utilities.pxFromDp(105, LauncherActivity.this)).setDuration( - 100).withEndAction(() -> mDock.setVisibility(GONE)); - - mIndicator.animate().alpha(0).setDuration(100).withEndAction( - () -> mIndicator.setVisibility(GONE)); refreshSuggestedApps(widgetsPage, forceRefreshSuggestedApps); if (Preferences.weatherRefreshIntervalInMs(LauncherActivity.this) == 0) { Intent intent = new Intent(LauncherActivity.this, @@ -1199,11 +1237,6 @@ public class LauncherActivity extends AppCompatActivity implements intent.setAction(WeatherUpdateService.ACTION_FORCE_UPDATE); startService(intent); } - } else { - mIndicator.setVisibility(View.VISIBLE); - mDock.setVisibility(View.VISIBLE); - mIndicator.animate().alpha(1).setDuration(100); - mDock.animate().translationY(0).setDuration(100); } dragDropEnabled = true; @@ -1319,7 +1352,7 @@ public class LauncherActivity extends AppCompatActivity implements 0, 0);*/ mHorizontalPager.addView(widgetsPage, 0); widgetsPage.setOnDragListener(null); - InsettableScrollLayout scrollView = widgetsPage.findViewById(R.id.widgets_scroll_container); + ScrollView scrollView = widgetsPage.findViewById(R.id.widgets_scroll_container); scrollView.setOnTouchListener((v, event) -> { if (widgetsPage.findViewById(R.id.widget_resizer_container).getVisibility() == VISIBLE) { @@ -1379,9 +1412,6 @@ public class LauncherActivity extends AppCompatActivity implements suggestionRecyclerView.setLayoutManager( new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); suggestionRecyclerView.setAdapter(suggestionAdapter); - DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, - DividerItemDecoration.VERTICAL); - suggestionRecyclerView.addItemDecoration(dividerItemDecoration); getCompositeDisposable().add(RxTextView.textChanges(mSearchInput) .debounce(300, TimeUnit.MILLISECONDS) .map(CharSequence::toString) @@ -2990,7 +3020,7 @@ public class LauncherActivity extends AppCompatActivity implements mDock.setAlpha(1f); mIndicator.setVisibility(VISIBLE); mIndicator.setAlpha(1f); - mHorizontalPager.setCurrentPage(1); + mHorizontalPager.snapToPage(1); } } @@ -3100,11 +3130,6 @@ public class LauncherActivity extends AppCompatActivity implements suggestionRecyclerView.setAdapter(networkSuggestionAdapter); suggestionRecyclerView.setLayoutManager( new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); - DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, - DividerItemDecoration.VERTICAL); - if (suggestionRecyclerView.getItemDecorationCount() == 0) { - suggestionRecyclerView.addItemDecoration(dividerItemDecoration); - } searchEditText.setOnFocusChangeListener((v, hasFocus) -> { if (!hasFocus) { @@ -3363,6 +3388,17 @@ public class LauncherActivity extends AppCompatActivity implements BlissLauncher.getApplication(this).getAppProvider().getAppsRepository().updateAppsRelay(Collections.emptyList()); } + @Override + public void onColorsChanged() { + updateTheme(); + } + + private void updateTheme() { + if (mThemeRes != ThemesKt.getActivityThemeRes(this)) { + recreate(); + } + } + /** * Adapter for folder apps. */ diff --git a/app/src/main/java/foundation/e/blisslauncher/features/suggestions/AutoCompleteAdapter.java b/app/src/main/java/foundation/e/blisslauncher/features/suggestions/AutoCompleteAdapter.java index 69d80421091f4052d532d2d576a4cade5e5f3050..3c39bc08637f2a2fdf9774b7f391b8a8baf54a70 100755 --- a/app/src/main/java/foundation/e/blisslauncher/features/suggestions/AutoCompleteAdapter.java +++ b/app/src/main/java/foundation/e/blisslauncher/features/suggestions/AutoCompleteAdapter.java @@ -1,11 +1,9 @@ package foundation.e.blisslauncher.features.suggestions; import android.content.Context; -import android.graphics.Color; import android.graphics.Typeface; import android.text.SpannableStringBuilder; import android.text.Spanned; -import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.view.LayoutInflater; import android.view.View; @@ -59,9 +57,6 @@ public class AutoCompleteAdapter extends spannable.setSpan(new StyleSpan(Typeface.BOLD), queryTextPos, queryTextPos + mQueryText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - spannable.setSpan(new ForegroundColorSpan(Color.WHITE), queryTextPos, - queryTextPos + mQueryText.length(), - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); queryTextPos = lcSuggestion.indexOf(mQueryText, queryTextPos + mQueryText.length()); } holder.mSuggestionTextView.setText(spannable); diff --git a/app/src/main/java/foundation/e/blisslauncher/features/weather/WeatherWidgetHostView.java b/app/src/main/java/foundation/e/blisslauncher/features/weather/WeatherWidgetHostView.java index 75987443bf313d00ed5fe0e9a80aaef78e94e9b3..4dcbdd6721fb9005e47652abeb17c22618428d30 100644 --- a/app/src/main/java/foundation/e/blisslauncher/features/weather/WeatherWidgetHostView.java +++ b/app/src/main/java/foundation/e/blisslauncher/features/weather/WeatherWidgetHostView.java @@ -10,7 +10,7 @@ import foundation.e.blisslauncher.core.customviews.RoundedWidgetView; public class WeatherWidgetHostView extends RoundedWidgetView { public WeatherWidgetHostView(Context context) { - super(context); + super(context, true); LayoutInflater.from(context).inflate(R.layout.layout_weather_info, this); } diff --git a/app/src/main/java/foundation/e/blisslauncher/features/widgets/DefaultWidgets.kt b/app/src/main/java/foundation/e/blisslauncher/features/widgets/DefaultWidgets.kt new file mode 100644 index 0000000000000000000000000000000000000000..7360ef23889a747c65115a8fc36b4c342f0281df --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/features/widgets/DefaultWidgets.kt @@ -0,0 +1,10 @@ +package foundation.e.blisslauncher.features.widgets + +import android.content.ComponentName + +object DefaultWidgets { + val ecloudWidget = ComponentName("foundation.e.drive", "foundation.e.drive.widgets.EDriveWidget") + val privacyWidget = ComponentName("foundation.e.privacycentralapp.e", "foundation.e.privacycentralapp.Widget") + + val widgets = setOf(ecloudWidget, privacyWidget) +} diff --git a/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetViewBuilder.java b/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetViewBuilder.java index 90bb5ace997b6d9b6171b2a87da17ad12cdd88b5..d1128cc1a543129217b495acc5b62f79ebecb97d 100644 --- a/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetViewBuilder.java +++ b/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetViewBuilder.java @@ -10,12 +10,15 @@ import androidx.annotation.NonNull; import foundation.e.blisslauncher.BlissLauncher; import foundation.e.blisslauncher.R; import foundation.e.blisslauncher.core.customviews.RoundedWidgetView; +import foundation.e.blisslauncher.core.utils.ThemesKt; import foundation.e.blisslauncher.features.launcher.LauncherActivity; public class WidgetViewBuilder { private static final String TAG = "WidgetViewBuilder"; + public static final String WIDGET_OPTION_DARK_TEXT = "foundation.e.blisslauncher.WIDGET_OPTION_DARK_TEXT"; + public static RoundedWidgetView create(LauncherActivity launcherActivity, @NonNull RoundedWidgetView roundedWidgetView) { if (BlissLauncher.getApplication(launcherActivity).getAppWidgetHost() == null) return null; @@ -54,6 +57,7 @@ public class WidgetViewBuilder { newOps.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, info.minHeight); newOps.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, BlissLauncher.getApplication( context).getDeviceProfile().getMaxWidgetHeight()); + newOps.putBoolean(WIDGET_OPTION_DARK_TEXT, ThemesKt.isWorkspaceDarkText(context)); roundedWidgetView.updateAppWidgetOptions(newOps); } } diff --git a/app/src/main/res/color/search_hint_color.xml b/app/src/main/res/color/search_hint_color.xml new file mode 100644 index 0000000000000000000000000000000000000000..de00e097db01eeb8fab94ec716b07f43063856fa --- /dev/null +++ b/app/src/main/res/color/search_hint_color.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/btn_rounded_corner.xml b/app/src/main/res/drawable/btn_rounded_corner.xml index b1873d95688ff0d7ceb88dd6a3aaedbbb6a79bbe..f7fcbf4ff752d87766c6129b7f5da102f4f8d5ac 100644 --- a/app/src/main/res/drawable/btn_rounded_corner.xml +++ b/app/src/main/res/drawable/btn_rounded_corner.xml @@ -1,10 +1,10 @@ - + - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_off.xml b/app/src/main/res/drawable/dot_off.xml index 8bf6d8dcad49342c9f909445b6da871ac3983c13..442bf74197330bb5bff44f41184e7afbe761ef14 100755 --- a/app/src/main/res/drawable/dot_off.xml +++ b/app/src/main/res/drawable/dot_off.xml @@ -3,5 +3,5 @@ android:shape="oval" android:innerRadius="0dp" android:thickness="6dp"> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_on.xml b/app/src/main/res/drawable/dot_on.xml index aaa4f30930e4407f6c3ef4267ca0145f3792be02..b82015e30e48e3ee5e2abd667657728b05ceaee7 100755 --- a/app/src/main/res/drawable/dot_on.xml +++ b/app/src/main/res/drawable/dot_on.xml @@ -3,5 +3,5 @@ android:shape="oval" android:innerRadius="0dp" android:thickness="6dp"> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/folder_window.xml b/app/src/main/res/drawable/folder_window.xml index ca9e4d75f53c6134780eec773437ea934b07642c..a6e5b64f1a502bd92ef50382a886cbbee53e6a99 100755 --- a/app/src/main/res/drawable/folder_window.xml +++ b/app/src/main/res/drawable/folder_window.xml @@ -3,7 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_cancel_white_24dp.xml b/app/src/main/res/drawable/ic_cancel_white_24dp.xml index d1787e73323f5ec7a5ed312677395e7c69f5697f..e5edeabe17068031158baec7ffe04e59c2f524d6 100755 --- a/app/src/main/res/drawable/ic_cancel_white_24dp.xml +++ b/app/src/main/res/drawable/ic_cancel_white_24dp.xml @@ -1,4 +1,4 @@ - diff --git a/app/src/main/res/drawable/ic_search_white_24dp.xml b/app/src/main/res/drawable/ic_search_black_24dp.xml similarity index 89% rename from app/src/main/res/drawable/ic_search_white_24dp.xml rename to app/src/main/res/drawable/ic_search_black_24dp.xml index c927d3d226214bab4c9d3c29eb406b16abd7fddb..2c5425454be1ad84202ad29637509cc866f00998 100755 --- a/app/src/main/res/drawable/ic_search_white_24dp.xml +++ b/app/src/main/res/drawable/ic_search_black_24dp.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/app/src/main/res/drawable/ic_search_white_alpha_24dp.xml b/app/src/main/res/drawable/ic_search_white_alpha_24dp.xml index 6151c59852e5e1f2acf6f46e71edb6fd04e4b163..54099555cd8a6399e9849b916053dea3f3bd14e0 100755 --- a/app/src/main/res/drawable/ic_search_white_alpha_24dp.xml +++ b/app/src/main/res/drawable/ic_search_white_alpha_24dp.xml @@ -2,8 +2,9 @@ android:width="18dp" android:height="18dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?widgetPrimaryTextColor"> diff --git a/app/src/main/res/drawable/ic_settings_white_24dp.xml b/app/src/main/res/drawable/ic_settings_white_24dp.xml index 11a6de592405917709551d9f09696395e52cb394..4da791002a83867011f1a9bdb2c257b2b24d50f7 100644 --- a/app/src/main/res/drawable/ic_settings_white_24dp.xml +++ b/app/src/main/res/drawable/ic_settings_white_24dp.xml @@ -1,4 +1,4 @@ - - + diff --git a/app/src/main/res/drawable/search_widget.xml b/app/src/main/res/drawable/search_widget.xml index a5fcf4ada97c466ecbb6714da07fbedcdcfb7880..48c355e3e23ae22ca206e73690d78952dcabbdfb 100755 --- a/app/src/main/res/drawable/search_widget.xml +++ b/app/src/main/res/drawable/search_widget.xml @@ -3,8 +3,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - + - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index e7533658f869cc3f6f3f0521686e79f7a6cfc3cd..b9be6efbbd0ee2925ebb95c2fbc221e03122ebc5 100755 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,6 +1,7 @@ + android:rowCount="1" + app:blurOverlayColor="@color/dock_background_color" /> + android:paddingBottom="4dp" + app:ci_drawable="@drawable/dot_on" + app:ci_drawable_unselected="@drawable/dot_off" /> - - + diff --git a/app/src/main/res/layout/item_suggestion.xml b/app/src/main/res/layout/item_suggestion.xml index b63d812463c9e751b4f4a6eabb9881e0bc463657..ea71689eceba6f3ccbd728d2b6ec0e83c7132298 100755 --- a/app/src/main/res/layout/item_suggestion.xml +++ b/app/src/main/res/layout/item_suggestion.xml @@ -1,16 +1,27 @@ - \ No newline at end of file + android:orientation="vertical"> + + + + + diff --git a/app/src/main/res/layout/item_weather_forecast.xml b/app/src/main/res/layout/item_weather_forecast.xml index 0366cd234a9c6aa4325c005a73f8de83d47cab8a..d9649759ff33fce01aa01078fc18fb0b07b05790 100644 --- a/app/src/main/res/layout/item_weather_forecast.xml +++ b/app/src/main/res/layout/item_weather_forecast.xml @@ -15,7 +15,7 @@ android:drawableBottom="@android:drawable/divider_horizontal_dark" android:gravity="center_horizontal|fill_horizontal" android:textAppearance="?android:attr/textAppearanceSmallInverse" - android:textColor="@color/transparent_white" /> + android:textColor="?widgetSecondaryTextColor" /> + android:textColor="?widgetPrimaryTextColor" /> \ No newline at end of file diff --git a/app/src/main/res/layout/layout_search_suggestion.xml b/app/src/main/res/layout/layout_search_suggestion.xml index f6c721338589a1a0a7894bceafb6b6b6c035933c..16ae0f691884f9efda0d4bf18ab4db86be8679dd 100644 --- a/app/src/main/res/layout/layout_search_suggestion.xml +++ b/app/src/main/res/layout/layout_search_suggestion.xml @@ -2,50 +2,70 @@ - + app:blurCornerRadius="100dp"> - - - - - - - - + + + + + + + + + android:layout_marginTop="12dp" + android:layout_marginBottom="4dp" + app:blurCornerRadius="12dp"> + + + - \ No newline at end of file + + + + diff --git a/app/src/main/res/layout/layout_used_apps.xml b/app/src/main/res/layout/layout_used_apps.xml index 5b26e9678dc074c98d41ff41d296aeec96eddea2..0f215c84ef26d5efb2fdc043e31d23abfb6d10a8 100755 --- a/app/src/main/res/layout/layout_used_apps.xml +++ b/app/src/main/res/layout/layout_used_apps.xml @@ -2,24 +2,19 @@ + style="@style/WidgetTitle" /> \ No newline at end of file diff --git a/app/src/main/res/layout/layout_weather_info.xml b/app/src/main/res/layout/layout_weather_info.xml index 030c2ecc776ac693f9acef8418a9dba5af0b4e67..5b95800fda2428d8dc59b4b0ec10515c309f1c4c 100644 --- a/app/src/main/res/layout/layout_weather_info.xml +++ b/app/src/main/res/layout/layout_weather_info.xml @@ -18,9 +18,7 @@ android:layout_toStartOf="@+id/weather_setting_imageview" android:padding="8dp" android:text="@string/weather" - android:textAllCaps="true" - android:textColor="#88FFFFFF" - android:textSize="16sp" /> + style="@style/WidgetTitle" /> @@ -90,7 +89,7 @@ android:ellipsize="end" android:fontFamily="sans-serif-medium" android:maxLines="2" - android:textColor="@color/white" + android:textColor="?widgetPrimaryTextColor" android:textSize="18sp" /> @@ -125,7 +124,7 @@ android:layout_gravity="end" android:fontFamily="sans-serif-light" android:gravity="end" - android:textColor="@color/white" + android:textColor="?widgetPrimaryTextColor" android:textSize="32sp" /> + android:textColor="?widgetPrimaryTextColor" /> diff --git a/app/src/main/res/layout/widgets_page.xml b/app/src/main/res/layout/widgets_page.xml index c1c6b7ad24b4f5306fe064441f33b69ddb659961..2b75512e5e7b0fd425513de1872bc110a5c11f04 100755 --- a/app/src/main/res/layout/widgets_page.xml +++ b/app/src/main/res/layout/widgets_page.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" android:animateLayoutChanges="true"> - -