diff --git a/core/database/src/main/java/de/mm20/launcher2/database/IconDao.kt b/core/database/src/main/java/de/mm20/launcher2/database/IconDao.kt index 3be1ab66..7920edb2 100644 --- a/core/database/src/main/java/de/mm20/launcher2/database/IconDao.kt +++ b/core/database/src/main/java/de/mm20/launcher2/database/IconDao.kt @@ -51,6 +51,9 @@ interface IconDao { @Query("SELECT * FROM IconPack") suspend fun getInstalledIconPacks(): List + @Query("SELECT * FROM IconPack WHERE packageName = :packageName LIMIT 1") + suspend fun getIconPack(packageName: String): IconPackEntity? + @Query("SELECT * FROM IconPack") fun getInstalledIconPacksLiveData(): LiveData> diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/DynamicCalendarIcon.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/DynamicCalendarIcon.kt index a4fd9dc5..3f9db1f4 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/DynamicCalendarIcon.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/DynamicCalendarIcon.kt @@ -4,6 +4,7 @@ import android.content.res.Resources import android.graphics.drawable.AdaptiveIconDrawable import androidx.core.content.res.ResourcesCompat import de.mm20.launcher2.icons.transformations.LauncherIconTransformation +import de.mm20.launcher2.ktx.isAtLeastApiLevel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.time.Instant @@ -33,36 +34,59 @@ internal class DynamicCalendarIcon( backgroundLayer = ColorLayer() ) - var icon = if (isThemed) { - StaticLauncherIcon( - foregroundLayer = TintedIconLayer( + var icon = when { + isThemed && drawable is AdaptiveIconDrawable -> { + if (isAtLeastApiLevel(33) && drawable.monochrome != null) { + return@withContext StaticLauncherIcon( + foregroundLayer = TintedIconLayer( + icon = drawable.monochrome!!, + scale = 1f, + ), + backgroundLayer = ColorLayer() + ) + } else { + return@withContext StaticLauncherIcon( + foregroundLayer = TintedIconLayer( + icon = drawable.foreground!!, + scale = 1.5f, + ), + backgroundLayer = ColorLayer() + ) + } + } + isThemed -> { + StaticLauncherIcon( + foregroundLayer = TintedIconLayer( + icon = drawable, + scale = 0.5f, + ), + backgroundLayer = ColorLayer() + ) + } + drawable is AdaptiveIconDrawable -> { + return@withContext StaticLauncherIcon( + foregroundLayer = drawable.foreground?.let { + StaticIconLayer( + icon = it, + scale = 1.5f, + ) + } ?: TransparentLayer, + backgroundLayer = drawable.background?.let { + StaticIconLayer( + icon = it, + scale = 1.5f, + ) + } ?: TransparentLayer, + ) + } + else -> StaticLauncherIcon( + foregroundLayer = StaticIconLayer( icon = drawable, - scale = 0.5f, + scale = 1f, ), - backgroundLayer = ColorLayer() + backgroundLayer = TransparentLayer ) - } else if (drawable is AdaptiveIconDrawable) { - return@withContext StaticLauncherIcon( - foregroundLayer = drawable.foreground?.let { - StaticIconLayer( - icon = it, - scale = 1.5f, - ) - } ?: TransparentLayer, - backgroundLayer = drawable.background?.let { - StaticIconLayer( - icon = it, - scale = 1.5f, - ) - } ?: TransparentLayer, - ) - } else StaticLauncherIcon( - foregroundLayer = StaticIconLayer( - icon = drawable, - scale = 1f, - ), - backgroundLayer = TransparentLayer - ) + } for (transformation in transformations) { icon = transformation.transform(icon) diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/IconPack.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/IconPack.kt index 8ab53ec3..db0110f0 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/IconPack.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/IconPack.kt @@ -1,5 +1,7 @@ package de.mm20.launcher2.icons +import android.content.Context +import android.content.pm.ResolveInfo import de.mm20.launcher2.database.entities.IconPackEntity data class IconPack( @@ -8,7 +10,7 @@ data class IconPack( val version: String, var scale: Float = 1f, val themed: Boolean = false, - ) { +) { constructor(entity: IconPackEntity) : this( name = entity.name, packageName = entity.packageName, @@ -17,6 +19,17 @@ data class IconPack( themed = entity.themed, ) + internal constructor( + context: Context, + resolveInfo: ResolveInfo, + themed: Boolean = false + ): this( + name = resolveInfo.loadLabel(context.packageManager).toString(), + packageName = resolveInfo.activityInfo.packageName, + version = context.packageManager.getPackageInfo(resolveInfo.activityInfo.packageName, 0).versionName, + themed = themed, + ) + fun toDatabaseEntity(): IconPackEntity { return IconPackEntity( name = name, diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/IconPackManager.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/IconPackManager.kt index ac9e3114..7b18f29f 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/IconPackManager.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/IconPackManager.kt @@ -14,6 +14,7 @@ import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.toBitmap import de.mm20.launcher2.crashreporter.CrashReporter import de.mm20.launcher2.database.AppDatabase +import de.mm20.launcher2.ktx.isAtLeastApiLevel import de.mm20.launcher2.ktx.obtainTypedArrayOrNull import de.mm20.launcher2.ktx.randomElementOrNull import kotlinx.coroutines.Dispatchers @@ -46,13 +47,21 @@ class IconPackManager( } } + suspend fun getIconPack(packageName: String): IconPack? { + return withContext(Dispatchers.IO) { + appDatabase.iconDao().getIconPack(packageName)?.let { + IconPack(it) + } + } + } + suspend fun updateIconPacks() { withContext(Dispatchers.IO) { UpdateIconPacksWorker(context).doWork() } } - suspend fun getIcon(iconPack: String, componentName: ComponentName): LauncherIcon? { + suspend fun getIcon(iconPack: String, componentName: ComponentName, themed: Boolean = false): LauncherIcon? { val res = try { context.packageManager.getResourcesForApplication(iconPack) } catch (e: PackageManager.NameNotFoundException) { @@ -66,7 +75,7 @@ class IconPackManager( val drawableName = icon.drawable ?: return null if (icon.type == "calendar") { - return getIconPackCalendarIcon(context, iconPack, drawableName) + return getIconPackCalendarIcon(context, iconPack, drawableName, themed) } val resId = res.getIdentifier(drawableName, "drawable", iconPack).takeIf { it != 0 } ?: return null @@ -75,8 +84,27 @@ class IconPackManager( } catch (e: Resources.NotFoundException) { return null } - return when (drawable) { - is AdaptiveIconDrawable -> { + return when { + themed && drawable is AdaptiveIconDrawable -> { + if (isAtLeastApiLevel(33) && drawable.monochrome != null) { + return StaticLauncherIcon( + foregroundLayer = StaticIconLayer( + icon = drawable.monochrome!!, + scale = 1f, + ), + backgroundLayer = ColorLayer(), + ) + } else { + return StaticLauncherIcon( + foregroundLayer = TintedIconLayer( + icon = drawable.foreground, + scale = 1.5f, + ), + backgroundLayer = ColorLayer(), + ) + } + } + drawable is AdaptiveIconDrawable -> { return StaticLauncherIcon( foregroundLayer = drawable.foreground?.let { StaticIconLayer( @@ -237,7 +265,8 @@ class IconPackManager( private fun getIconPackCalendarIcon( context: Context, iconPack: String, - baseIconName: String + baseIconName: String, + themed: Boolean, ): DynamicCalendarIcon? { val resources = try { context.packageManager.getResourcesForApplication(iconPack) @@ -252,7 +281,8 @@ class IconPackManager( }.toIntArray() return DynamicCalendarIcon( resources = resources, - resourceIds = drawableIds + resourceIds = drawableIds, + isThemed = themed, ) } @@ -417,23 +447,16 @@ class IconPackManager( class UpdateIconPacksWorker(val context: Context) { fun doWork() { - val packs = loadInstalledPacks(context).map { it.activityInfo.packageName } + val packs = loadInstalledPacks(context) val grayscaleProviders = loadInstalledGreyscaleProviders(context) val iconDao = AppDatabase.getInstance(context).iconDao() iconDao.uninstallIconPacksExcept( - packs.union(grayscaleProviders).toList() + packs.map { it.packageName }.union(grayscaleProviders).toList() ) for (pack in packs) { try { - val packInfo = context.packageManager.getPackageInfo(pack, 0) - val iconPack = IconPack( - name = packInfo.applicationInfo.loadLabel(context.packageManager).toString(), - packageName = pack, - version = packInfo.versionName - ) - //if (iconDao.isInstalled(iconPack)) continue - installIconPack(iconPack) + installIconPack(pack) } catch (e: PackageManager.NameNotFoundException) { continue } @@ -455,21 +478,19 @@ class UpdateIconPacksWorker(val context: Context) { } } - private fun loadInstalledPacks(context: Context): List { - val packs = mutableListOf() + private fun loadInstalledPacks(context: Context): List { + val packs = mutableListOf() val pm = context.packageManager - var intent = Intent("org.adw.ActivityStarter.THEMES") + var intent = Intent("app.lawnchair.icons.THEMED_ICON") + val themedPacks = pm.queryIntentActivities(intent, 0) + packs.addAll(themedPacks.map { IconPack(context, it, true) }) + intent = Intent("org.adw.ActivityStarter.THEMES") val adwPacks = pm.queryIntentActivities(intent, 0) - packs.addAll(adwPacks) + packs.addAll(adwPacks.map { IconPack(context, it, false) }) intent = Intent("com.novalauncher.THEME") val novaPacks = pm.queryIntentActivities(intent, 0) - novaPacks.forEach { - if (packs.none { p -> p.activityInfo.packageName == it.activityInfo.packageName }) packs.add( - it - ) - } - packs.sortWith(ResolveInfo.DisplayNameComparator(pm)) - return packs + packs.addAll(novaPacks.map { IconPack(context, it, false) }) + return packs.distinctBy { it.packageName } } private fun installIconPack(iconPack: IconPack) { 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 b751e0ce..83fd0c33 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 @@ -5,6 +5,7 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.graphics.Color +import android.util.Log import android.util.LruCache import de.mm20.launcher2.data.customattrs.AdaptifiedLegacyIcon import de.mm20.launcher2.data.customattrs.CustomAttributesRepository @@ -94,13 +95,18 @@ class IconRepository( } if (settings.iconPack.isNotBlank()) { - providers.add( - IconPackIconProvider( - context, - settings.iconPack, - iconPackManager + val pack = iconPackManager.getIconPack(settings.iconPack) + if (pack != null) { + providers.add( + IconPackIconProvider( + context, + pack, + iconPackManager + ) ) - ) + } else { + Log.w("MM20", "Icon pack ${settings.iconPack} not found") + } } providers.add(GoogleClockIconProvider(context)) providers.add(CalendarIconProvider(context)) diff --git a/services/icons/src/main/java/de/mm20/launcher2/icons/providers/IconPackIconProvider.kt b/services/icons/src/main/java/de/mm20/launcher2/icons/providers/IconPackIconProvider.kt index 9215204b..857dee02 100644 --- a/services/icons/src/main/java/de/mm20/launcher2/icons/providers/IconPackIconProvider.kt +++ b/services/icons/src/main/java/de/mm20/launcher2/icons/providers/IconPackIconProvider.kt @@ -10,17 +10,17 @@ import kotlinx.coroutines.withContext class IconPackIconProvider( private val context: Context, - private val iconPack: String, + private val iconPack: IconPack, private val iconPackManager: IconPackManager, ): IconProvider { override suspend fun getIcon(searchable: SavableSearchable, size: Int): LauncherIcon? { if (searchable !is LauncherApp) return null val component = ComponentName(searchable.`package`, searchable.activity) - return iconPackManager.getIcon(iconPack, component) + return iconPackManager.getIcon(iconPack.packageName, component, iconPack.themed) ?: iconPackManager.generateIcon( context, - iconPack, + iconPack.packageName, baseIcon = withContext(Dispatchers.IO) { searchable.launcherActivityInfo.getIcon(context.resources.displayMetrics.densityDpi) },