diff --git a/lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt b/lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt index 0955fa0c5c..3e242e5a79 100644 --- a/lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt +++ b/lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt @@ -8,10 +8,10 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import app.lawnchair.data.folder.model.FolderOrderUtils import app.lawnchair.data.folder.model.FolderViewModel -import app.lawnchair.flowerpot.Flowerpot import app.lawnchair.launcher import app.lawnchair.preferences.PreferenceManager import app.lawnchair.preferences2.PreferenceManager2 +import app.lawnchair.util.categorizeAppsWithSystemAndGoogle import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener import com.android.launcher3.allapps.AllAppsStore import com.android.launcher3.allapps.AlphabeticalAppsList @@ -44,7 +44,6 @@ class LawnchairAlphabeticalAppsList( private val filteredList = mutableListOf() private val folderOrder = FolderOrderUtils.stringToIntList(prefs.drawerListOrder.get()) - private val potsManager = Flowerpot.Manager.getInstance(context) init { context.launcher.deviceProfile.inv.addOnChangeListener(this) @@ -87,8 +86,10 @@ class LawnchairAlphabeticalAppsList( if (isWorkOrPrivateSpace(appList)) return super.addAppsWithSections(appList, position) if (!drawerListDefault) { - val categorizedApps = potsManager.categorizeApps(appList) - categorizedApps.forEach { (category, apps) -> + val validApps = appList.mapNotNull { it } + val finalCategorizedApps = categorizeAppsWithSystemAndGoogle(validApps, context) + + finalCategorizedApps.forEach { (category, apps) -> if (apps.size == 1) { mAdapterItems.add(AdapterItem.asApp(apps.first())) } else { diff --git a/lawnchair/src/app/lawnchair/deck/LawndeckManager.kt b/lawnchair/src/app/lawnchair/deck/LawndeckManager.kt index d7a7c74c3f..c0cd9f3cf7 100644 --- a/lawnchair/src/app/lawnchair/deck/LawndeckManager.kt +++ b/lawnchair/src/app/lawnchair/deck/LawndeckManager.kt @@ -6,6 +6,7 @@ import app.lawnchair.LawnchairLauncher import app.lawnchair.flowerpot.Flowerpot import app.lawnchair.launcher import app.lawnchair.launcherNullable +import app.lawnchair.util.categorizeAppsWithSystemAndGoogle import app.lawnchair.util.restartLauncher import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherAppState @@ -17,6 +18,7 @@ import com.android.launcher3.model.data.FolderInfo import com.android.launcher3.model.data.WorkspaceItemInfo import com.android.launcher3.provider.RestoreDbTask import com.android.launcher3.util.ComponentKey +import com.android.launcher3.util.PackageManagerHelper import java.io.File import java.util.Locale import kotlinx.coroutines.CompletableDeferred @@ -101,9 +103,8 @@ class LawndeckManager(private val context: Context) { onProgress?.invoke("Categorizing apps...") - // Use flowerpot to categorize apps - val potsManager = Flowerpot.Manager.getInstance(context) - val categorizedApps = potsManager.categorizeApps(apps.map { it as? AppInfo }) + val validApps = apps.mapNotNull { it as? AppInfo } + val finalCategorizedApps = categorizeAppsWithSystemAndGoogle(validApps, context) onProgress?.invoke("Adding apps to workspace...") @@ -115,7 +116,7 @@ class LawndeckManager(private val context: Context) { var singleAppCount = 0 // Process each category - categorizedApps.forEach { (category, categoryApps) -> + finalCategorizedApps.forEach { (category, categoryApps) -> if (categoryApps.isEmpty()) return@forEach if (categoryApps.size == 1) { @@ -188,22 +189,32 @@ class LawndeckManager(private val context: Context) { val activityInfo = activities[0] val appInfo = AppInfo(context, activityInfo, user) - // Use flowerpot to categorize the app - val potsManager = Flowerpot.Manager.getInstance(context) - val categorizedApps = potsManager.categorizeApps(listOf(appInfo)) + val intent = appInfo.intent - if (categorizedApps.isEmpty()) { - // No category found, add directly to workspace - ItemInstallQueue.INSTANCE.get(context).queueItem(packageName, user) - return - } + // Determine category: Google Apps > System Apps > Flowerpot categories + val category = when { + packageName.startsWith("com.google.") -> "Google Apps" - // Get the category for this app (categorizedApps is a Map>) - val categoryEntry = categorizedApps.entries.firstOrNull() ?: run { - ItemInstallQueue.INSTANCE.get(context).queueItem(packageName, user) - return + intent != null && PackageManagerHelper.isSystemApp(context, intent) -> "System Apps" + + else -> { + // Use flowerpot to categorize the app + val potsManager = Flowerpot.Manager.getInstance(context) + val categorizedApps = potsManager.categorizeApps(listOf(appInfo)) + + if (categorizedApps.isEmpty()) { + // No category found, add directly to workspace + ItemInstallQueue.INSTANCE.get(context).queueItem(packageName, user) + return + } + + // Get the category from flowerpot + categorizedApps.entries.firstOrNull()?.key ?: run { + ItemInstallQueue.INSTANCE.get(context).queueItem(packageName, user) + return + } + } } - val category = categoryEntry.key // Check if there's already a folder for this category on workspace val existingFolder = findFolderByCategory(category, dataModel) diff --git a/lawnchair/src/app/lawnchair/qsb/providers/Google.kt b/lawnchair/src/app/lawnchair/qsb/providers/Google.kt index c30bfe540f..6f5654a856 100644 --- a/lawnchair/src/app/lawnchair/qsb/providers/Google.kt +++ b/lawnchair/src/app/lawnchair/qsb/providers/Google.kt @@ -46,7 +46,7 @@ data object Google : QsbSearchProvider( Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK, Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK, 0, - options.toBundle() + options.toBundle(), ) return } diff --git a/lawnchair/src/app/lawnchair/util/AppCategorizationUtils.kt b/lawnchair/src/app/lawnchair/util/AppCategorizationUtils.kt new file mode 100644 index 0000000000..db1c7d0cc3 --- /dev/null +++ b/lawnchair/src/app/lawnchair/util/AppCategorizationUtils.kt @@ -0,0 +1,54 @@ +package app.lawnchair.util + +import android.content.Context +import app.lawnchair.flowerpot.Flowerpot +import com.android.launcher3.model.data.AppInfo +import com.android.launcher3.util.PackageManagerHelper + +/** + * Categorizes apps into System Apps, Google Apps, and Flowerpot categories. + * + * @param apps List of apps to categorize + * @param context Context for checking system apps and accessing Flowerpot + * @return Map of category names to lists of apps in that category + */ +fun categorizeAppsWithSystemAndGoogle( + apps: List, + context: Context, +): Map> { + val systemApps = mutableListOf() + val googleApps = mutableListOf() + val otherApps = mutableListOf() + + apps.forEach { app -> + val packageName = app.targetPackage ?: return@forEach + val intent = app.intent + + // Check if it's a Google app first (Google apps can also be system apps) + when { + packageName.startsWith("com.google.") -> googleApps.add(app) + intent != null && PackageManagerHelper.isSystemApp(context, intent) -> systemApps.add(app) + else -> otherApps.add(app) + } + } + + // Use flowerpot to categorize other apps (non-system, non-Google) + val potsManager = Flowerpot.Manager.getInstance(context) + val categorizedApps = potsManager.categorizeApps(otherApps) + + // Build final categorized apps map + val finalCategorizedApps = mutableMapOf>() + + if (systemApps.isNotEmpty()) { + finalCategorizedApps["System Apps"] = systemApps + } + + if (googleApps.isNotEmpty()) { + finalCategorizedApps["Google Apps"] = googleApps + } + + // Add flowerpot categorized apps + finalCategorizedApps.putAll(categorizedApps) + + return finalCategorizedApps +}