From 1477fba932e5c73fabbf3e203d7b5ec3a161dfc8 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Fri, 13 May 2022 11:00:33 +0200 Subject: [PATCH] Update: Merge AppSheet's Installed into main Installed --- .../com/looker/droidify/MainApplication.kt | 22 ++++++- .../looker/droidify/database/Converters.kt | 17 ++++++ .../com/looker/droidify/database/DatabaseX.kt | 2 +- .../droidify/database/entity/Installed.kt | 4 +- .../service/PackageChangedReceiver.kt | 5 +- .../looker/droidify/ui/fragments/AppSheetX.kt | 59 +++---------------- .../com/looker/droidify/utility/Utils.kt | 34 ++++++++++- 7 files changed, 85 insertions(+), 58 deletions(-) diff --git a/src/main/kotlin/com/looker/droidify/MainApplication.kt b/src/main/kotlin/com/looker/droidify/MainApplication.kt index a4fc226a..330044ea 100644 --- a/src/main/kotlin/com/looker/droidify/MainApplication.kt +++ b/src/main/kotlin/com/looker/droidify/MainApplication.kt @@ -68,9 +68,29 @@ class MainApplication : Application(), ImageLoaderFactory { addDataScheme("package") } ) + val launcherActivitiesMap = + packageManager + .queryIntentActivities( + Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER), + 0 + ) + .mapNotNull { resolveInfo -> resolveInfo.activityInfo } + .groupBy { it.packageName } + .mapNotNull { (packageName, activityInfos) -> + val aiNameLabels = activityInfos.mapNotNull { + val label = try { + it.loadLabel(packageManager).toString() + } catch (e: Exception) { + e.printStackTrace() + null + } + label?.let { label -> Pair(it.name, label) } + } + Pair(packageName, aiNameLabels) + }.toMap() val installedItems = packageManager .getInstalledPackages(Android.PackageManager.signaturesFlag) - .map { it.toInstalledItem() } + .map { it.toInstalledItem(launcherActivitiesMap[it.packageName].orEmpty()) } CoroutineScope(Dispatchers.Default).launch { db.installedDao.emptyTable() db.installedDao.put(*installedItems.toTypedArray()) diff --git a/src/main/kotlin/com/looker/droidify/database/Converters.kt b/src/main/kotlin/com/looker/droidify/database/Converters.kt index 21dddf3b..4f41609d 100644 --- a/src/main/kotlin/com/looker/droidify/database/Converters.kt +++ b/src/main/kotlin/com/looker/droidify/database/Converters.kt @@ -21,6 +21,23 @@ object Converters { @JvmStatic fun toByteArray(list: List): ByteArray = list.toString().toByteArray() + @TypeConverter + @JvmStatic + fun toPairStringList(byteArray: ByteArray): List> { + val string = String(byteArray) + return if (string == "") emptyList() + else string.removeSurrounding("[", "]").split(",").filter(String::isNotEmpty).map { + val pairs = it.split("|") + Pair(pairs[0], pairs[1]) + } + } + + @JvmName("pairStringListToByteArray") + @TypeConverter + @JvmStatic + fun toByteArray(list: List>): ByteArray = + list.map { it.toList().joinToString("|") }.toString().toByteArray() + @TypeConverter @JvmStatic fun toAuthor(byteArray: ByteArray) = Author.fromJson(String(byteArray)) diff --git a/src/main/kotlin/com/looker/droidify/database/DatabaseX.kt b/src/main/kotlin/com/looker/droidify/database/DatabaseX.kt index 17cc408f..ed8b7007 100644 --- a/src/main/kotlin/com/looker/droidify/database/DatabaseX.kt +++ b/src/main/kotlin/com/looker/droidify/database/DatabaseX.kt @@ -21,7 +21,7 @@ import kotlinx.coroutines.launch CategoryTemp::class, Installed::class, Ignored::class - ], version = 6 + ], version = 7 ) @TypeConverters(Converters::class) abstract class DatabaseX : RoomDatabase() { diff --git a/src/main/kotlin/com/looker/droidify/database/entity/Installed.kt b/src/main/kotlin/com/looker/droidify/database/entity/Installed.kt index 07e10a55..807e8561 100644 --- a/src/main/kotlin/com/looker/droidify/database/entity/Installed.kt +++ b/src/main/kotlin/com/looker/droidify/database/entity/Installed.kt @@ -10,5 +10,7 @@ data class Installed( var packageName: String = "", var version: String = "", var versionCode: Long = 0L, - var signature: String = "" + var signature: String = "", + var isSystem: Boolean = false, + val launcherActivities: List> = emptyList() ) \ No newline at end of file diff --git a/src/main/kotlin/com/looker/droidify/service/PackageChangedReceiver.kt b/src/main/kotlin/com/looker/droidify/service/PackageChangedReceiver.kt index 505cc75c..55c504b2 100644 --- a/src/main/kotlin/com/looker/droidify/service/PackageChangedReceiver.kt +++ b/src/main/kotlin/com/looker/droidify/service/PackageChangedReceiver.kt @@ -6,6 +6,7 @@ import android.content.Intent import com.looker.droidify.database.DatabaseX import com.looker.droidify.utility.Utils.toInstalledItem import com.looker.droidify.utility.extension.android.Android +import com.looker.droidify.utility.getLaunchActivities import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -29,8 +30,10 @@ class PackageChangedReceiver : BroadcastReceiver() { } catch (e: Exception) { null } + val launcherActivities = context.packageManager.getLaunchActivities(packageName) GlobalScope.launch(Dispatchers.IO) { - if (packageInfo != null) db.installedDao.insertReplace(packageInfo.toInstalledItem()) + if (packageInfo != null) db.installedDao + .insertReplace(packageInfo.toInstalledItem(launcherActivities)) else db.installedDao.delete(packageName) } } diff --git a/src/main/kotlin/com/looker/droidify/ui/fragments/AppSheetX.kt b/src/main/kotlin/com/looker/droidify/ui/fragments/AppSheetX.kt index bb7bd860..59ff80ee 100644 --- a/src/main/kotlin/com/looker/droidify/ui/fragments/AppSheetX.kt +++ b/src/main/kotlin/com/looker/droidify/ui/fragments/AppSheetX.kt @@ -1,9 +1,7 @@ package com.looker.droidify.ui.fragments import android.content.ActivityNotFoundException -import android.content.ComponentName import android.content.Intent -import android.content.pm.ApplicationInfo import android.net.Uri import android.os.Bundle import android.provider.Settings @@ -18,6 +16,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.looker.droidify.R import com.looker.droidify.content.ProductPreferences +import com.looker.droidify.database.entity.Installed import com.looker.droidify.database.entity.Product import com.looker.droidify.database.entity.Release import com.looker.droidify.database.entity.Repository @@ -108,46 +107,7 @@ class AppSheetX() : FullscreenBottomSheetDialogFragment(), AppDetailAdapter.Call override fun setupLayout() { // TODO simplify observing and updating viewModel.installedItem.observe(viewLifecycleOwner) { - installed = it?.let { - val isSystem = try { - ((requireContext().packageManager.getApplicationInfo(packageName, 0).flags) - and ApplicationInfo.FLAG_SYSTEM) != 0 - } catch (e: Exception) { - false - } - val launcherActivities = - if (packageName != context?.packageName && context != null) { - val packageManager = requireContext().packageManager - packageManager - .queryIntentActivities( - Intent(Intent.ACTION_MAIN).addCategory( - Intent.CATEGORY_LAUNCHER - ), 0 - ) - .asSequence() - .mapNotNull { resolveInfo -> resolveInfo.activityInfo } - .filter { activityInfo -> activityInfo.packageName == packageName } - .mapNotNull { activityInfo -> - val label = try { - activityInfo.loadLabel(packageManager).toString() - } catch (e: Exception) { - e.printStackTrace() - null - } - label?.let { labelName -> - Pair( - activityInfo.name, - labelName - ) - } - } - .toList() - } else { - // Don't allow to launch self - emptyList() - } - Installed(it, isSystem, launcherActivities) - } + installed = it updateSheet() } @@ -175,7 +135,7 @@ class AppSheetX() : FullscreenBottomSheetDialogFragment(), AppDetailAdapter.Call binding.recyclerView.context, packageName, this, - installed?.data + installed ) lifecycleScope.launch { updateButtons() @@ -205,12 +165,12 @@ class AppSheetX() : FullscreenBottomSheetDialogFragment(), AppDetailAdapter.Call private suspend fun updateButtons(preference: ProductPreference) = withContext(Dispatchers.Default) { val installed = installed - val product = findSuggestedProduct(productRepos, installed?.data) { it.first }?.first + val product = findSuggestedProduct(productRepos, installed) { it.first }?.first val compatible = product != null && product.selectedReleases.firstOrNull() .let { it != null && it.incompatibilities.isEmpty() } val canInstall = product != null && installed == null && compatible val canUpdate = - product != null && compatible && product.canUpdate(installed?.data) && + product != null && compatible && product.canUpdate(installed) && !preference.shouldIgnoreUpdate(product.versionCode) val canUninstall = product != null && installed != null && !installed.isSystem val canLaunch = @@ -303,7 +263,7 @@ class AppSheetX() : FullscreenBottomSheetDialogFragment(), AppDetailAdapter.Call AppDetailAdapter.Action.INSTALL, AppDetailAdapter.Action.UPDATE, -> { - val installedItem = installed?.data + val installedItem = installed lifecycleScope.launch { startUpdate( packageName, @@ -408,7 +368,7 @@ class AppSheetX() : FullscreenBottomSheetDialogFragment(), AppDetailAdapter.Call } override fun onReleaseClick(release: Release) { - val installedItem = installed?.data + val installedItem = installed when { release.incompatibilities.isNotEmpty() -> { MessageDialog( @@ -494,9 +454,4 @@ class AppSheetX() : FullscreenBottomSheetDialogFragment(), AppDetailAdapter.Call UNINSTALL(5, AppDetailAdapter.Action.UNINSTALL), SHARE(6, AppDetailAdapter.Action.SHARE) } - - private class Installed( - val data: com.looker.droidify.database.entity.Installed, val isSystem: Boolean, - val launcherActivities: List>, - ) } diff --git a/src/main/kotlin/com/looker/droidify/utility/Utils.kt b/src/main/kotlin/com/looker/droidify/utility/Utils.kt index cab6e0fd..14f9a041 100644 --- a/src/main/kotlin/com/looker/droidify/utility/Utils.kt +++ b/src/main/kotlin/com/looker/droidify/utility/Utils.kt @@ -7,7 +7,9 @@ import android.content.ActivityNotFoundException import android.content.Context import android.content.DialogInterface import android.content.Intent +import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo +import android.content.pm.PackageManager import android.content.pm.Signature import android.content.res.Configuration import android.graphics.drawable.Drawable @@ -37,9 +39,16 @@ import java.security.cert.CertificateEncodingException import java.util.* object Utils { - fun PackageInfo.toInstalledItem(): Installed { + fun PackageInfo.toInstalledItem(launcherActivities: List> = emptyList()): Installed { val signatureString = singleSignature?.let(Utils::calculateHash).orEmpty() - return Installed(packageName, versionName.orEmpty(), versionCodeCompat, signatureString) + return Installed( + packageName, + versionName.orEmpty(), + versionCodeCompat, + signatureString, + applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == ApplicationInfo.FLAG_SYSTEM, + launcherActivities + ) } fun getDefaultApplicationIcon(context: Context): Drawable = @@ -224,4 +233,25 @@ fun Context.showBatteryOptimizationDialog() { Preferences[Preferences.Key.IgnoreIgnoreBatteryOptimization] = true } .show() +} + +fun PackageManager.getLaunchActivities(packageName: String): List> = + queryIntentActivities(Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER), 0) + .mapNotNull { resolveInfo -> resolveInfo.activityInfo } + .filter { activityInfo -> activityInfo.packageName == packageName } + .mapNotNull { activityInfo -> + val label = try { + activityInfo.loadLabel(this).toString() + } catch (e: Exception) { + e.printStackTrace() + null + } + label?.let { labelName -> + Pair( + activityInfo.name, + labelName + ) + } + } + .toList() } \ No newline at end of file