refactor: open sim toolkit logical #58
4 changed files with 95 additions and 44 deletions
|
@ -29,5 +29,7 @@
|
|||
|
||||
<queries>
|
||||
<package android:name="com.android.stk" />
|
||||
<package android:name="com.android.stk1" />
|
||||
<package android:name="com.android.stk2" />
|
||||
</queries>
|
||||
</manifest>
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
32
app-unpriv/src/main/res/values/sim_toolkit.xml
Normal file
32
app-unpriv/src/main/res/values/sim_toolkit.xml
Normal 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>
|
Loading…
Add table
Reference in a new issue