refactor: impl LegacyInstallComponent as sealed class & new option always_choose

This commit is contained in:
maniacata 2025-05-23 01:54:40 +08:00
parent 815aebe28c
commit d9d22809a9
5 changed files with 111 additions and 32 deletions

View File

@ -87,13 +87,28 @@ class PreferenceSettingsRepository(
INSTALLER_TYPE.update(installerType.name)
override suspend fun setLegacyInstallerComponent(component: LegacyInstallerComponent?) {
if (component == null) {
LEGACY_INSTALLER_COMPONENT_CLASS.update("")
LEGACY_INSTALLER_COMPONENT_ACTIVITY.update("")
return
when (component) {
null -> {
LEGACY_INSTALLER_COMPONENT_TYPE.update("")
LEGACY_INSTALLER_COMPONENT_CLASS.update("")
LEGACY_INSTALLER_COMPONENT_ACTIVITY.update("")
}
is LegacyInstallerComponent.Component -> {
LEGACY_INSTALLER_COMPONENT_TYPE.update("component")
LEGACY_INSTALLER_COMPONENT_CLASS.update(component.clazz)
LEGACY_INSTALLER_COMPONENT_ACTIVITY.update(component.activity)
}
LegacyInstallerComponent.Unspecified -> {
LEGACY_INSTALLER_COMPONENT_TYPE.update("unspecified")
LEGACY_INSTALLER_COMPONENT_CLASS.update("")
LEGACY_INSTALLER_COMPONENT_ACTIVITY.update("")
}
LegacyInstallerComponent.AlwaysChoose -> {
LEGACY_INSTALLER_COMPONENT_TYPE.update("always_choose")
LEGACY_INSTALLER_COMPONENT_CLASS.update("")
LEGACY_INSTALLER_COMPONENT_ACTIVITY.update("")
}
}
LEGACY_INSTALLER_COMPONENT_CLASS.update(component.clazz)
LEGACY_INSTALLER_COMPONENT_ACTIVITY.update(component.activity)
}
override suspend fun setAutoUpdate(allow: Boolean) =
@ -136,12 +151,18 @@ class PreferenceSettingsRepository(
private fun mapSettings(preferences: Preferences): Settings {
val installerType =
InstallerType.valueOf(preferences[INSTALLER_TYPE] ?: InstallerType.Default.name)
val legacyInstallerComponent =
preferences[LEGACY_INSTALLER_COMPONENT_CLASS]?.takeIf { it.isNotBlank() }?.let { cls ->
preferences[LEGACY_INSTALLER_COMPONENT_ACTIVITY]?.takeIf { it.isNotBlank() }?.let { act ->
LegacyInstallerComponent(cls, act)
val legacyInstallerComponent = when (preferences[LEGACY_INSTALLER_COMPONENT_TYPE]) {
"component" -> {
preferences[LEGACY_INSTALLER_COMPONENT_CLASS]?.takeIf { it.isNotBlank() }?.let { cls ->
preferences[LEGACY_INSTALLER_COMPONENT_ACTIVITY]?.takeIf { it.isNotBlank() }?.let { act ->
LegacyInstallerComponent.Component(cls, act)
}
}
}
"unspecified" -> LegacyInstallerComponent.Unspecified
"always_choose" -> LegacyInstallerComponent.AlwaysChoose
else -> null
}
val language = preferences[LANGUAGE] ?: "system"
val incompatibleVersions = preferences[INCOMPATIBLE_VERSIONS] ?: false
@ -205,6 +226,7 @@ class PreferenceSettingsRepository(
val HOME_SCREEN_SWIPING = booleanPreferencesKey("key_home_swiping")
val LEGACY_INSTALLER_COMPONENT_CLASS = stringPreferencesKey("key_legacy_installer_component_class")
val LEGACY_INSTALLER_COMPONENT_ACTIVITY = stringPreferencesKey("key_legacy_installer_component_activity")
val LEGACY_INSTALLER_COMPONENT_TYPE = stringPreferencesKey("key_legacy_installer_component_type")
// Enums
val THEME = stringPreferencesKey("key_theme")
@ -220,8 +242,28 @@ class PreferenceSettingsRepository(
set(UNSTABLE_UPDATES, settings.unstableUpdate)
set(THEME, settings.theme.name)
set(DYNAMIC_THEME, settings.dynamicTheme)
settings.legacyInstallerComponent?.let { set(LEGACY_INSTALLER_COMPONENT_CLASS, it.clazz) }
settings.legacyInstallerComponent?.let { set(LEGACY_INSTALLER_COMPONENT_ACTIVITY, it.activity) }
when (settings.legacyInstallerComponent) {
is LegacyInstallerComponent.Component -> {
set(LEGACY_INSTALLER_COMPONENT_TYPE, "component")
set(LEGACY_INSTALLER_COMPONENT_CLASS, settings.legacyInstallerComponent.clazz)
set(LEGACY_INSTALLER_COMPONENT_ACTIVITY, settings.legacyInstallerComponent.activity)
}
LegacyInstallerComponent.Unspecified -> {
set(LEGACY_INSTALLER_COMPONENT_TYPE, "unspecified")
set(LEGACY_INSTALLER_COMPONENT_CLASS, "")
set(LEGACY_INSTALLER_COMPONENT_ACTIVITY, "")
}
LegacyInstallerComponent.AlwaysChoose -> {
set(LEGACY_INSTALLER_COMPONENT_TYPE, "always_choose")
set(LEGACY_INSTALLER_COMPONENT_CLASS, "")
set(LEGACY_INSTALLER_COMPONENT_ACTIVITY, "")
}
null -> {
set(LEGACY_INSTALLER_COMPONENT_TYPE, "")
set(LEGACY_INSTALLER_COMPONENT_CLASS, "")
set(LEGACY_INSTALLER_COMPONENT_ACTIVITY, "")
}
}
set(INSTALLER_TYPE, settings.installerType.name)
set(AUTO_UPDATE, settings.autoUpdate)
set(AUTO_SYNC, settings.autoSync.name)

View File

@ -3,15 +3,24 @@ package com.looker.droidify.datastore.model
import kotlinx.serialization.Serializable
@Serializable
data class LegacyInstallerComponent(
val clazz: String,
val activity: String,
) {
fun update(
newClazz: String? = null,
newActivity: String? = null,
): LegacyInstallerComponent = copy(
clazz = newClazz ?: clazz,
activity = newActivity ?: activity
)
sealed class LegacyInstallerComponent {
@Serializable
object Unspecified : LegacyInstallerComponent()
@Serializable
object AlwaysChoose : LegacyInstallerComponent()
@Serializable
data class Component(
val clazz: String,
val activity: String,
) : LegacyInstallerComponent() {
fun update(
newClazz: String? = null,
newActivity: String? = null,
): Component = copy(
clazz = newClazz ?: clazz,
activity = newActivity ?: activity
)
}
}

View File

@ -5,8 +5,10 @@ import android.content.Context
import android.content.Intent
import android.util.AndroidRuntimeException
import androidx.core.net.toUri
import com.looker.droidify.R
import com.looker.droidify.datastore.SettingsRepository
import com.looker.droidify.datastore.get
import com.looker.droidify.datastore.model.LegacyInstallerComponent
import com.looker.droidify.domain.model.PackageName
import com.looker.droidify.installer.model.InstallItem
import com.looker.droidify.installer.model.InstallState
@ -18,8 +20,10 @@ import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
@Suppress("DEPRECATION")
class LegacyInstaller(private val context: Context,
private val settingsRepository: SettingsRepository) : Installer {
class LegacyInstaller(
private val context: Context,
private val settingsRepository: SettingsRepository
) : Installer {
companion object {
private const val APK_MIME = "application/vnd.android.package-archive"
@ -38,10 +42,23 @@ class LegacyInstaller(private val context: Context,
val comp = settingsRepository.get { legacyInstallerComponent }.firstOrNull()
return suspendCancellableCoroutine { cont ->
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE).apply {
val intent = Intent(Intent.ACTION_INSTALL_PACKAGE).apply {
setDataAndType(fileUri, APK_MIME)
flags = installFlag
component = comp?.let { ComponentName(it.clazz, it.activity) }
when (comp) {
is LegacyInstallerComponent.Component -> {
component = ComponentName(comp.clazz, comp.activity)
}
else -> {
// For Unspecified and AlwaysChoose, don't set component
}
}
}
val installIntent = when (comp) {
LegacyInstallerComponent.AlwaysChoose -> Intent.createChooser(intent, context.getString(
R.string.select_installer))
else -> intent
}
try {

View File

@ -238,13 +238,19 @@ class SettingsFragment : Fragment() {
titleText = getString(R.string.legacyInstallerComponent),
setting = viewModel.getSetting { legacyInstallerComponent },
map = {
it?.let { component ->
when (it) {
is LegacyInstallerComponent.Component -> {
val component = it
val appLabel = runCatching {
val info = pm.getApplicationInfo(component.clazz, 0)
pm.getApplicationLabel(info).toString()
}.getOrElse { component.clazz }
"$appLabel (${component.activity})"
} ?: getString(R.string.unspecified)
}
LegacyInstallerComponent.Unspecified -> getString(R.string.unspecified)
LegacyInstallerComponent.AlwaysChoose -> getString(R.string.always_choose)
null -> getString(R.string.unspecified)
}
},
) { component, valueToString ->
val installerOptions = run {
@ -253,15 +259,18 @@ class SettingsFragment : Fragment() {
setDataAndType(contentProtocol.toUri(), "application/vnd.android.package-archive")
}
val activities = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
listOf<LegacyInstallerComponent?>(null) + activities.map {
LegacyInstallerComponent(
listOf(
LegacyInstallerComponent.Unspecified,
LegacyInstallerComponent.AlwaysChoose
) + activities.map {
LegacyInstallerComponent.Component(
clazz = it.activityInfo.packageName,
activity = it.activityInfo.name,
)
}
}
addSingleCorrectDialog(
initialValue = component,
initialValue = component ?: LegacyInstallerComponent.Unspecified,
values = installerOptions,
title = R.string.legacyInstallerComponent,
iconRes = R.drawable.ic_apk_install,

View File

@ -241,4 +241,6 @@
<string name="label_open_video">Video</string>
<string name="label_targets_sdk">Targets: Android %s</string>
<string name="label_unknown_sdk">Unknown (%d)</string>
<string name="always_choose">Always Choose</string>
<string name="select_installer">Select installer</string>
</resources>