refactor: open sim toolkit logical #58

Merged
PeterCxy merged 3 commits from septs/OpenEUICC:stk into master 2024-11-09 01:10:58 +01:00
4 changed files with 95 additions and 44 deletions

View file

@ -29,5 +29,7 @@
<queries> <queries>
<package android:name="com.android.stk" /> <package android:name="com.android.stk" />
<package android:name="com.android.stk1" />
<package android:name="com.android.stk2" />
</queries> </queries>
</manifest> </manifest>

View file

@ -1,12 +1,9 @@
package im.angry.openeuicc.ui package im.angry.openeuicc.ui
import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem
import im.angry.easyeuicc.R import im.angry.easyeuicc.R
import im.angry.openeuicc.util.SIMToolkit import im.angry.openeuicc.util.SIMToolkit
import im.angry.openeuicc.util.isUsb
import im.angry.openeuicc.util.newInstanceEuicc import im.angry.openeuicc.util.newInstanceEuicc
import im.angry.openeuicc.util.slotId import im.angry.openeuicc.util.slotId
@ -19,22 +16,16 @@ class UnprivilegedEuiccManagementFragment : EuiccManagementFragment() {
newInstanceEuicc(UnprivilegedEuiccManagementFragment::class.java, slotId, portId) newInstanceEuicc(UnprivilegedEuiccManagementFragment::class.java, slotId, portId)
} }
private val stk by lazy {
SIMToolkit(requireContext())
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater) super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.fragment_sim_toolkit, menu) inflater.inflate(R.menu.fragment_sim_toolkit, menu)
menu.findItem(R.id.open_sim_toolkit).isVisible = menu.findItem(R.id.open_sim_toolkit).apply {
SIMToolkit.getComponentName(requireContext(), slotId) != null isVisible = stk.isAvailable(slotId)
intent = stk.intent(slotId)
} }
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)
} }
} }

View file

@ -3,36 +3,62 @@ package im.angry.openeuicc.util
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent 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 { class SIMToolkit(private val context: Context) {
private val slot1activities = arrayOf( private val slotSelection = getComponentNames(R.array.sim_toolkit_slot_selection)
ComponentName("com.android.stk", "com.android.stk.StkMain1"),
)
private val slot2activities = arrayOf( private val slots = buildMap {
ComponentName("com.android.stk", "com.android.stk.StkMain2"), put(0, getComponentNames(R.array.sim_toolkit_slot_1))
) put(1, getComponentNames(R.array.sim_toolkit_slot_2))
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
}
}
} }
fun intent(context: Context, slotId: Int) = Intent(Intent.ACTION_MAIN, null).apply { 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 flags = Intent.FLAG_ACTIVITY_NEW_TASK
component = getComponentName(context, slotId) component = components.find(activities::contains)
addCategory(Intent.CATEGORY_LAUNCHER) addCategory(Intent.CATEGORY_LAUNCHER)
} }
return if (intent.component != null) intent else launchIntent
}
} }

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="Typos">
<string-array name="sim_toolkit_slot_selection">
<item>com.android.stk/.StkMain</item>
<item>com.android.stk/.StkMainHide</item>
<item>com.android.stk/.StkListActivity</item>
<item>com.android.stk/.StkLauncherListActivity</item>
</string-array>
<string-array name="sim_toolkit_slot_1">
<item>com.android.stk/.StkMain1</item>
<item>com.android.stk/.PrimaryStkMain</item>
<item>com.android.stk/.StkLauncherActivity</item>
<item>com.android.stk/.StkLauncherActivity_Chn</item>
<item>com.android.stk/.StkLauncherActivityI</item>
<item>com.android.stk/.OppoStkLauncherActivity1</item>
<item>com.android.stk/.OplusStkLauncherActivity1</item>
<item>com.android.stk/.mtk.StkLauncherActivityI</item>
</string-array>
<string-array name="sim_toolkit_slot_2">
<item>com.android.stk/.StkMain2</item>
<item>com.android.stk/.SecondaryStkMain</item>
<item>com.android.stk/.StkLauncherActivity2</item>
<item>com.android.stk/.StkLauncherActivityII</item>
<item>com.android.stk/.OppoStkLauncherActivity2</item>
<item>com.android.stk/.OplusStkLauncherActivity2</item>
<item>com.android.stk/.mtk.StkLauncherActivityII</item>
<item>com.android.stk1/.StkLauncherActivity</item>
<item>com.android.stk2/.StkLauncherActivity</item>
<item>com.android.stk2/.StkLauncherActivity_Chn</item>
<item>com.android.stk2/.StkLauncherActivity2</item>
</string-array>
</resources>