diff --git a/app-unpriv/src/main/AndroidManifest.xml b/app-unpriv/src/main/AndroidManifest.xml
index cb1ef5f..8760fb9 100644
--- a/app-unpriv/src/main/AndroidManifest.xml
+++ b/app-unpriv/src/main/AndroidManifest.xml
@@ -29,5 +29,7 @@
+
+
\ No newline at end of file
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 91c4804..fad03fd 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
@@ -1,12 +1,9 @@
package im.angry.openeuicc.ui
-import android.util.Log
import android.view.Menu
import android.view.MenuInflater
-import android.view.MenuItem
import im.angry.easyeuicc.R
import im.angry.openeuicc.util.SIMToolkit
-import im.angry.openeuicc.util.isUsb
import im.angry.openeuicc.util.newInstanceEuicc
import im.angry.openeuicc.util.slotId
@@ -19,22 +16,16 @@ class UnprivilegedEuiccManagementFragment : EuiccManagementFragment() {
newInstanceEuicc(UnprivilegedEuiccManagementFragment::class.java, slotId, portId)
}
+ private val stk by lazy {
+ SIMToolkit(requireContext())
+ }
+
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.fragment_sim_toolkit, menu)
- menu.findItem(R.id.open_sim_toolkit).isVisible =
- SIMToolkit.getComponentName(requireContext(), slotId) != null
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean =
- when (item.itemId) {
- R.id.open_sim_toolkit -> {
- val intent = SIMToolkit.intent(requireContext(), slotId)
- Log.d(TAG, "Opening SIM Toolkit for $slotId slot, intent: $intent")
- startActivity(intent)
- true
- }
-
- else -> super.onOptionsItemSelected(item)
+ menu.findItem(R.id.open_sim_toolkit).apply {
+ isVisible = stk.isAvailable(slotId)
+ intent = stk.intent(slotId)
}
+ }
}
\ No newline at end of file
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 b6aed0f..148e932 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
@@ -3,36 +3,62 @@ package im.angry.openeuicc.util
import android.content.ComponentName
import android.content.Context
import android.content.Intent
-import android.content.pm.PackageManager.NameNotFoundException
+import android.content.pm.PackageManager
+import androidx.annotation.ArrayRes
+import im.angry.easyeuicc.R
+import im.angry.openeuicc.core.EuiccChannelManager
-object SIMToolkit {
- private val slot1activities = arrayOf(
- ComponentName("com.android.stk", "com.android.stk.StkMain1"),
- )
+class SIMToolkit(private val context: Context) {
+ private val slotSelection = getComponentNames(R.array.sim_toolkit_slot_selection)
- private val slot2activities = arrayOf(
- ComponentName("com.android.stk", "com.android.stk.StkMain2"),
- )
-
- fun getComponentName(context: Context, slotId: Int): ComponentName? {
- val components = when (slotId) {
- 0 -> slot1activities
- 1 -> slot2activities
- else -> return null
- }
- return components.find {
- try {
- context.packageManager.getActivityIcon(it)
- true
- } catch (_: NameNotFoundException) {
- false
- }
- }
+ private val slots = buildMap {
+ put(0, getComponentNames(R.array.sim_toolkit_slot_1))
+ put(1, getComponentNames(R.array.sim_toolkit_slot_2))
}
- fun intent(context: Context, slotId: Int) = Intent(Intent.ACTION_MAIN, null).apply {
- flags = Intent.FLAG_ACTIVITY_NEW_TASK
- component = getComponentName(context, slotId)
- addCategory(Intent.CATEGORY_LAUNCHER)
+ private val packageNames = buildSet {
+ addAll(slotSelection.map { it.packageName })
+ addAll(slots.values.flatten().map { it.packageName })
+ }
+
+ private val activities = packageNames.flatMap(::getActivities).toSet()
+
+ private val launchIntent by lazy {
+ packageNames.firstNotNullOfOrNull(::getLaunchIntent)
+ }
+
+ private fun getLaunchIntent(packageName: String) = try {
+ val pm = context.packageManager
+ pm.getLaunchIntentForPackage(packageName)
+ } catch (_: PackageManager.NameNotFoundException) {
+ null
+ }
+
+ private fun getActivities(packageName: String) = try {
+ val pm = context.packageManager
+ val packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES)
+ packageInfo.activities!!.filter { it.exported }
+ .map { ComponentName(it.packageName, it.name) }
+ } catch (_: PackageManager.NameNotFoundException) {
+ emptyList()
+ }
+
+ 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
+ }
+
+ 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 if (intent.component != null) intent else launchIntent
}
}
diff --git a/app-unpriv/src/main/res/values/sim_toolkit.xml b/app-unpriv/src/main/res/values/sim_toolkit.xml
new file mode 100644
index 0000000..1f16271
--- /dev/null
+++ b/app-unpriv/src/main/res/values/sim_toolkit.xml
@@ -0,0 +1,32 @@
+
+
+
+ - com.android.stk/.StkMain
+ - com.android.stk/.StkMainHide
+ - com.android.stk/.StkListActivity
+ - com.android.stk/.StkLauncherListActivity
+
+
+ - com.android.stk/.StkMain1
+ - com.android.stk/.PrimaryStkMain
+ - com.android.stk/.StkLauncherActivity
+ - com.android.stk/.StkLauncherActivity_Chn
+ - com.android.stk/.StkLauncherActivityI
+ - com.android.stk/.OppoStkLauncherActivity1
+ - com.android.stk/.OplusStkLauncherActivity1
+ - com.android.stk/.mtk.StkLauncherActivityI
+
+
+ - com.android.stk/.StkMain2
+ - com.android.stk/.SecondaryStkMain
+ - com.android.stk/.StkLauncherActivity2
+ - com.android.stk/.StkLauncherActivityII
+ - com.android.stk/.OppoStkLauncherActivity2
+ - com.android.stk/.OplusStkLauncherActivity2
+ - com.android.stk/.mtk.StkLauncherActivityII
+ - com.android.stk1/.StkLauncherActivity
+ - com.android.stk2/.StkLauncherActivity
+ - com.android.stk2/.StkLauncherActivity_Chn
+ - com.android.stk2/.StkLauncherActivity2
+
+
\ No newline at end of file