From f2c697342c10b754df662a89b6c58367ed736d3a Mon Sep 17 00:00:00 2001 From: septs Date: Wed, 5 Mar 2025 13:20:19 +0800 Subject: [PATCH] refactor: sim toolkit --- .../ui/UnprivilegedEuiccManagementFragment.kt | 46 +++--- .../im/angry/openeuicc/util/SIMToolkit.kt | 132 +++++++++--------- app-unpriv/src/main/res/values/strings.xml | 2 +- 3 files changed, 83 insertions(+), 97 deletions(-) diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/ui/UnprivilegedEuiccManagementFragment.kt b/app-unpriv/src/main/java/im/angry/openeuicc/ui/UnprivilegedEuiccManagementFragment.kt index 85be2ac..1ceeba3 100644 --- a/app-unpriv/src/main/java/im/angry/openeuicc/ui/UnprivilegedEuiccManagementFragment.kt +++ b/app-unpriv/src/main/java/im/angry/openeuicc/ui/UnprivilegedEuiccManagementFragment.kt @@ -29,36 +29,22 @@ class UnprivilegedEuiccManagementFragment : EuiccManagementFragment() { super.onCreateOptionsMenu(menu, inflater) inflater.inflate(R.menu.fragment_sim_toolkit, menu) menu.findItem(R.id.open_sim_toolkit).apply { - isVisible = stk.isAvailable(slotId) - setOnMenuItemClickListener { launchSIMToolkit() } + val slot = stk[slotId] ?: return@apply + isVisible = slot.intent != null + setOnMenuItemClickListener { + val intent = slot.intent ?: return@setOnMenuItemClickListener false + if (intent.action == Settings.ACTION_APPLICATION_DETAILS_SETTINGS) { + val packageName = intent.data!!.schemeSpecificPart + val label = requireContext().packageManager.getApplicationLabel(packageName) + val message = requireContext().getString(R.string.toast_prompt_to_enable_sim_toolkit, label) + Toast.makeText(context, message, Toast.LENGTH_LONG).show() + } + startActivity(intent) + true + } } } +} - private fun launchSIMToolkit(): Boolean { - val intent = stk.intent(slotId) - val disabledPackageName = stk.getDisabledPackageName(slotId) - if (disabledPackageName == null && intent != null) { - startActivity(intent) - return true - } else if (disabledPackageName != null) { - val context = requireContext() - val appInfo = context.packageManager - .getApplicationInfo(disabledPackageName, PackageManager.GET_ACTIVITIES) - val toast = Toast.makeText( - context, - getString( - R.string.toast_hint_enable_sim_toolkit, - context.packageManager.getApplicationLabel(appInfo) - ), - Toast.LENGTH_LONG, - ) - startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { - data = Uri.fromParts("package", disabledPackageName, null) - }) - toast.show() - return true - } else { - return false - } - } -} \ No newline at end of file +private fun PackageManager.getApplicationLabel(packageName: String): CharSequence = + getApplicationLabel(getApplicationInfo(packageName, 0)) diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/util/SIMToolkit.kt b/app-unpriv/src/main/java/im/angry/openeuicc/util/SIMToolkit.kt index 56e011e..418b1aa 100644 --- a/app-unpriv/src/main/java/im/angry/openeuicc/util/SIMToolkit.kt +++ b/app-unpriv/src/main/java/im/angry/openeuicc/util/SIMToolkit.kt @@ -1,92 +1,92 @@ package im.angry.openeuicc.util -import android.app.Activity import android.content.ComponentName import android.content.Context import android.content.Intent +import android.content.pm.ActivityInfo import android.content.pm.PackageManager +import android.net.Uri +import android.provider.Settings +import android.widget.Toast import androidx.annotation.ArrayRes import im.angry.easyeuicc.R import im.angry.openeuicc.core.EuiccChannelManager class SIMToolkit(private val context: Context) { - private val pm: PackageManager - get() = context.packageManager - - private val slotSelection = getComponentNames(R.array.sim_toolkit_slot_selection) - private val slots = buildMap { + fun getComponentNames(@ArrayRes id: Int) = context.resources + .getStringArray(id).mapNotNull(ComponentName::unflattenFromString) + put(-1, getComponentNames(R.array.sim_toolkit_slot_selection)) put(0, getComponentNames(R.array.sim_toolkit_slot_1)) put(1, getComponentNames(R.array.sim_toolkit_slot_2)) } - private val packageNames = buildSet { - addAll(slotSelection.map { it.packageName }) - addAll(slots.values.flatten().map { it.packageName }) + operator fun get(slotId: Int): Slot? = when (slotId) { + -1, EuiccChannelManager.USB_CHANNEL_ID -> null + else -> Slot(context, buildSet { + addAll(slots.getOrDefault(slotId, emptySet())) + addAll(slots.getOrDefault(-1, emptySet())) + }) } - private val activities: Iterable - get() = packageNames.flatMap(::getActivities).toSet() + data class Slot(private val context: Context, private val components: Set) { + private val packageManager: PackageManager + get() = context.packageManager - private val launchIntent: Intent? - get() = packageNames.firstNotNullOfOrNull(::getLaunchIntent) + private val packageNames: Iterable + get() = components.map(ComponentName::getPackageName).toSet() - private fun getLaunchIntent(packageName: String) = try { - pm.getLaunchIntentForPackage(packageName) - } catch (_: PackageManager.NameNotFoundException) { - null - } + private val launchIntent: Intent? + get() = packageNames.firstNotNullOfOrNull(packageManager::getLaunchIntent) - private fun getActivities(packageName: String) = buildList { - val activities = try { - pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES).activities ?: emptyArray() - } catch (_: PackageManager.NameNotFoundException) { - emptyArray() - } - for (activity in activities) { - if (!activity.exported) continue - add(ComponentName(packageName, activity.name)) - } - } + private val activities: Iterable + get() = packageNames.flatMap(packageManager::getActivities) + .filter(ActivityInfo::exported).map { ComponentName(it.packageName, it.name) } - private fun getComponentNames(@ArrayRes id: Int) = - context.resources.getStringArray(id).mapNotNull(ComponentName::unflattenFromString) - - fun isAvailable(slotId: Int) = when (slotId) { - -1 -> false - EuiccChannelManager.USB_CHANNEL_ID -> false - else -> intent(slotId) != null || getDisabledPackageName(slotId) != null - } - - fun intent(slotId: Int): Intent? { - val components = slots.getOrDefault(slotId, emptySet()) + slotSelection - val intent = Intent(Intent.ACTION_MAIN, null).apply { - flags = Intent.FLAG_ACTIVITY_NEW_TASK - component = components.find(activities::contains) - addCategory(Intent.CATEGORY_LAUNCHER) - } - return when (pm.getComponentEnabledSetting(intent.component ?: return launchIntent)) { - PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> intent - else -> null - } - } - - fun getDisabledPackageName(slotId: Int): String? { - val packageNames = buildSet { - addAll(slots.getOrDefault(slotId, emptySet()).map { it.packageName }) - addAll(slotSelection.map { it.packageName }) - } - return packageNames.find { - val enabledState = try { - pm.getApplicationEnabledSetting(it) - } catch (e: IllegalArgumentException) { - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - } - when (enabledState) { - PackageManager.COMPONENT_ENABLED_STATE_DISABLED -> true - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER -> true - else -> false + private fun getActivityIntent(): Intent? { + for (activity in activities) { + if (!components.contains(activity)) continue + if (isDisabledState(packageManager.getComponentEnabledSetting(activity))) continue + return Intent.makeMainActivity(activity) } + return launchIntent } + + private fun getDisabledPackageIntent(): Intent? { + val disabledPackageName = packageNames.find { + try { + isDisabledState(packageManager.getApplicationEnabledSetting(it)) + } catch (_: IllegalArgumentException) { + false + } + } + if (disabledPackageName == null) return null + return Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", disabledPackageName, null) + ) + } + + val intent: Intent? + get() = getActivityIntent() ?: getDisabledPackageIntent() } } + +private fun isDisabledState(state: Int) = when (state) { + PackageManager.COMPONENT_ENABLED_STATE_DISABLED -> true + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER -> true + else -> false +} + +private fun PackageManager.getLaunchIntent(packageName: String) = try { + getLaunchIntentForPackage(packageName) +} catch (_: PackageManager.NameNotFoundException) { + null +} + +private fun PackageManager.getActivities(packageName: String) = try { + getPackageInfo(packageName, PackageManager.GET_ACTIVITIES) + .activities?.toList() ?: emptyList() +} catch (_: PackageManager.NameNotFoundException) { + emptyList() +} diff --git a/app-unpriv/src/main/res/values/strings.xml b/app-unpriv/src/main/res/values/strings.xml index 54c1843..43bf44f 100644 --- a/app-unpriv/src/main/res/values/strings.xml +++ b/app-unpriv/src/main/res/values/strings.xml @@ -9,7 +9,7 @@ ARA-M SHA-1 copied to clipboard - Please ENABLE your "%s" application + Please ENABLE your \"%s\" application System Features