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