Update: Merge AppSheet's Installed into main Installed

This commit is contained in:
machiav3lli 2022-05-13 11:00:33 +02:00
parent 099b1bdf28
commit 1477fba932
7 changed files with 85 additions and 58 deletions

View File

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

View File

@ -21,6 +21,23 @@ object Converters {
@JvmStatic
fun toByteArray(list: List<String>): ByteArray = list.toString().toByteArray()
@TypeConverter
@JvmStatic
fun toPairStringList(byteArray: ByteArray): List<Pair<String, String>> {
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<Pair<String, String>>): ByteArray =
list.map { it.toList().joinToString("|") }.toString().toByteArray()
@TypeConverter
@JvmStatic
fun toAuthor(byteArray: ByteArray) = Author.fromJson(String(byteArray))

View File

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

View File

@ -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<Pair<String, String>> = emptyList()
)

View File

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

View File

@ -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<Pair<String, String>>,
)
}

View File

@ -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<Pair<String, String>> = 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<Pair<String, String>> =
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()
}