From 993b7f39fcadc63206968eb1d1c3fac844fd6602 Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Wed, 15 Feb 2023 19:13:55 +0100 Subject: [PATCH] Add support for native themed Google clock icon --- .../de/mm20/launcher2/icons/IconRepository.kt | 2 +- .../compat/AdaptiveIconDrawableCompat.kt | 83 +++++++++++++++++- .../providers/GoogleClockIconProvider.kt | 87 +++++++++---------- 3 files changed, 123 insertions(+), 49 deletions(-) diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/IconRepository.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/IconRepository.kt index 5d31914d..43f8bd03 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/IconRepository.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/IconRepository.kt @@ -109,7 +109,7 @@ class IconRepository( if (settings.themedIcons) { providers.add(ThemedIconProvider(iconPackManager)) } - providers.add(GoogleClockIconProvider(context)) + providers.add(GoogleClockIconProvider(context, settings.themedIcons)) providers.add(CalendarIconProvider(context, settings.themedIcons)) if (!isAtLeastApiLevel(33)) { providers.add(CompatIconProvider(context, settings.themedIcons)) diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/compat/AdaptiveIconDrawableCompat.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/compat/AdaptiveIconDrawableCompat.kt index b26630b9..6fa1fcb1 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/compat/AdaptiveIconDrawableCompat.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/compat/AdaptiveIconDrawableCompat.kt @@ -4,15 +4,21 @@ import android.content.res.Resources import android.content.res.XmlResourceParser import android.graphics.drawable.AdaptiveIconDrawable import android.graphics.drawable.Drawable +import android.graphics.drawable.LayerDrawable +import android.graphics.drawable.RotateDrawable import android.util.AttributeSet import android.util.Log import android.util.Xml import android.view.InflateException import androidx.core.content.res.ResourcesCompat import de.mm20.launcher2.crashreporter.CrashReporter +import de.mm20.launcher2.icons.ClockLayer +import de.mm20.launcher2.icons.ClockSublayer +import de.mm20.launcher2.icons.ClockSublayerRole import de.mm20.launcher2.icons.ColorLayer import de.mm20.launcher2.icons.StaticIconLayer import de.mm20.launcher2.icons.StaticLauncherIcon +import de.mm20.launcher2.icons.TintedClockLayer import de.mm20.launcher2.icons.TintedIconLayer import de.mm20.launcher2.ktx.isAtLeastApiLevel import de.mm20.launcher2.ktx.skipToNextTag @@ -36,6 +42,19 @@ data class AdaptiveIconDrawableCompat( } fun from(resources: Resources, resId: Int): AdaptiveIconDrawableCompat? { + if (isAtLeastApiLevel(33)) { + return try { + val drawable = ResourcesCompat.getDrawable(resources, resId, null) + if (drawable is AdaptiveIconDrawable) { + from(drawable) + } else { + null + } + } catch (e: Resources.NotFoundException) { + null + } + } + var xmlParser: XmlResourceParser? = null try { @@ -126,7 +145,60 @@ data class AdaptiveIconDrawableCompat( fun AdaptiveIconDrawableCompat.toLauncherIcon( themed: Boolean = false, + clock: ClockIconConfig? = null, ): StaticLauncherIcon { + val clockForeground = (if (themed) monochrome else foreground) as? LayerDrawable + if (clock != null && clockForeground != null) { + val clockLayers = (0 until clockForeground.numberOfLayers).map { + val drw = clockForeground.getDrawable(it) + if (drw is RotateDrawable) { + drw.level = when (it) { + clock.hourLayer -> { + (12 - clock.defaultHour) * 60 + } + + clock.minuteLayer -> { + (60 - clock.defaultMinute) + } + + clock.secondLayer -> { + (60 - clock.defaultSecond) * 10 + } + + else -> 0 + } + } + ClockSublayer( + drawable = drw, + role = when (it) { + clock.hourLayer -> ClockSublayerRole.Hour + clock.minuteLayer -> ClockSublayerRole.Minute + clock.secondLayer -> ClockSublayerRole.Second + else -> ClockSublayerRole.Static + } + ) + } + if (themed) { + return StaticLauncherIcon( + foregroundLayer = TintedClockLayer( + sublayers = clockLayers, + scale = 1f, + ), + backgroundLayer = ColorLayer(), + ) + } + return StaticLauncherIcon( + foregroundLayer = ClockLayer( + sublayers = clockLayers, + scale = 1.5f, + ), + backgroundLayer = StaticIconLayer( + icon = this.background, + scale = 1.5f, + ) + ) + } + if (themed && this.monochrome != null) { return StaticLauncherIcon( foregroundLayer = TintedIconLayer( @@ -147,4 +219,13 @@ fun AdaptiveIconDrawableCompat.toLauncherIcon( ) ) } -} \ No newline at end of file +} + +data class ClockIconConfig( + val hourLayer: Int, + val minuteLayer: Int, + val secondLayer: Int, + val defaultHour: Int, + val defaultMinute: Int, + val defaultSecond: Int, +) \ No newline at end of file diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/providers/GoogleClockIconProvider.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/providers/GoogleClockIconProvider.kt index 5debdae2..c8782a44 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/providers/GoogleClockIconProvider.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/providers/GoogleClockIconProvider.kt @@ -8,10 +8,13 @@ import android.graphics.drawable.LayerDrawable import android.graphics.drawable.RotateDrawable import androidx.core.content.res.ResourcesCompat import de.mm20.launcher2.icons.* +import de.mm20.launcher2.icons.compat.AdaptiveIconDrawableCompat +import de.mm20.launcher2.icons.compat.ClockIconConfig +import de.mm20.launcher2.icons.compat.toLauncherIcon import de.mm20.launcher2.search.SavableSearchable import de.mm20.launcher2.search.data.LauncherApp -class GoogleClockIconProvider(val context: Context) : IconProvider { +class GoogleClockIconProvider(val context: Context, private val themed: Boolean) : IconProvider { override suspend fun getIcon(searchable: SavableSearchable, size: Int): LauncherIcon? { if (searchable !is LauncherApp) return null if (searchable.`package` != "com.google.android.deskclock") return null @@ -24,22 +27,15 @@ class GoogleClockIconProvider(val context: Context) : IconProvider { } catch (e: PackageManager.NameNotFoundException) { return null } - val drawable = + val drawableId = appInfo.metaData.getInt("com.android.launcher3.LEVEL_PER_TICK_ICON_ROUND") - val resources = pm.getResourcesForApplication(appInfo) - val baseIcon = try { - ResourcesCompat.getDrawable(resources, drawable, null) as? AdaptiveIconDrawable - ?: return null - } catch (e: Resources.NotFoundException) { + val resources = try { + pm.getResourcesForApplication(appInfo) + } catch (e: PackageManager.NameNotFoundException) { return null } - val foreground = baseIcon.foreground as? LayerDrawable ?: return null - val hourLayer = - appInfo.metaData.getInt("com.android.launcher3.HOUR_LAYER_INDEX") - val minuteLayer = - appInfo.metaData.getInt("com.android.launcher3.MINUTE_LAYER_INDEX") - val secondLayer = - appInfo.metaData.getInt("com.android.launcher3.SECOND_LAYER_INDEX") + + val icon = AdaptiveIconDrawableCompat.from(resources, drawableId) ?: return null val defaultHour = appInfo.metaData.getInt("com.android.launcher3.DEFAULT_HOUR") @@ -48,40 +44,37 @@ class GoogleClockIconProvider(val context: Context) : IconProvider { val defaultSecond = appInfo.metaData.getInt("com.android.launcher3.DEFAULT_SECOND") - return StaticLauncherIcon( - foregroundLayer = ClockLayer( - sublayers = (0 until foreground.numberOfLayers).map { - val drw = foreground.getDrawable(it) - if (drw is RotateDrawable) { - drw.level = when (it) { - hourLayer -> { - (12 - defaultHour) * 60 - } - minuteLayer -> { - (60 - defaultMinute) - } - secondLayer -> { - (60 - defaultSecond) * 10 - } - else -> 0 - } - } - ClockSublayer( - drawable = drw, - role = when (it) { - hourLayer -> ClockSublayerRole.Hour - minuteLayer -> ClockSublayerRole.Minute - secondLayer -> ClockSublayerRole.Second - else -> ClockSublayerRole.Static - } - ) - }, - scale = 1.5f, - ), - backgroundLayer = StaticIconLayer( - icon = baseIcon.background, - scale = 1.5f, + // Workaround for Google Clock themed icon because it is weird and I don't understand + // how to get the correct layers from the drawable without hardcoding them here. + val clockConfig = if (themed && searchable.`package` == "com.google.android.deskclock") { + ClockIconConfig( + hourLayer = 0, + minuteLayer = 1, + secondLayer = -1, + defaultHour = defaultHour, + defaultMinute = defaultMinute, + defaultSecond = defaultSecond ) + } else { + val hourLayer = + appInfo.metaData.getInt("com.android.launcher3.HOUR_LAYER_INDEX", -1) + val minuteLayer = + appInfo.metaData.getInt("com.android.launcher3.MINUTE_LAYER_INDEX", -1) + val secondLayer = + appInfo.metaData.getInt("com.android.launcher3.SECOND_LAYER_INDEX", -1) + ClockIconConfig( + hourLayer = hourLayer, + minuteLayer = minuteLayer, + secondLayer = secondLayer, + defaultHour = defaultHour, + defaultMinute = defaultMinute, + defaultSecond = defaultSecond + ) + } + + return icon.toLauncherIcon( + themed = themed, + clock = clockConfig ) } } \ No newline at end of file