Add support for native themed Google clock icon

This commit is contained in:
MM20 2023-02-15 19:13:55 +01:00
parent 23252726b0
commit 993b7f39fc
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
3 changed files with 123 additions and 49 deletions

View File

@ -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))

View File

@ -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(
)
)
}
}
}
data class ClockIconConfig(
val hourLayer: Int,
val minuteLayer: Int,
val secondLayer: Int,
val defaultHour: Int,
val defaultMinute: Int,
val defaultSecond: Int,
)

View File

@ -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
)
}
}