Compare commits

...

7 commits

Author SHA1 Message Date
40d97f0291
refactor: sim toolkit 2025-03-05 14:56:35 +08:00
d9cbef886e
fix: strings 2025-03-05 14:34:30 +08:00
cc5f798d3d
fix: strings 2025-03-05 14:32:23 +08:00
e24523f3e2
refactor: sim toolkit 2025-03-05 14:20:55 +08:00
e47eca289b
refactor: sim toolkit 2025-03-05 13:59:29 +08:00
698021c7f4
refactor: sim toolkit 2025-03-05 13:42:44 +08:00
9873634de7
chore: rename strings name 2025-03-05 13:20:19 +08:00
3 changed files with 73 additions and 92 deletions

View file

@ -1,12 +1,7 @@
package im.angry.openeuicc.ui package im.angry.openeuicc.ui
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.provider.Settings
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.widget.Toast
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.newInstanceEuicc import im.angry.openeuicc.util.newInstanceEuicc
@ -30,35 +25,7 @@ class UnprivilegedEuiccManagementFragment : EuiccManagementFragment() {
inflater.inflate(R.menu.fragment_sim_toolkit, menu) inflater.inflate(R.menu.fragment_sim_toolkit, menu)
menu.findItem(R.id.open_sim_toolkit).apply { menu.findItem(R.id.open_sim_toolkit).apply {
isVisible = stk.isAvailable(slotId) isVisible = stk.isAvailable(slotId)
setOnMenuItemClickListener { launchSIMToolkit() } setOnMenuItemClickListener { stk.launch(slotId) }
}
}
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
} }
} }
} }

View file

@ -1,92 +1,106 @@
package im.angry.openeuicc.util package im.angry.openeuicc.util
import android.app.Activity
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.ActivityInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.Uri
import android.provider.Settings
import android.widget.Toast
import androidx.annotation.ArrayRes import androidx.annotation.ArrayRes
import im.angry.easyeuicc.R import im.angry.easyeuicc.R
import im.angry.openeuicc.core.EuiccChannelManager import im.angry.openeuicc.core.EuiccChannelManager
class SIMToolkit(private val context: Context) { 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 { 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(0, getComponentNames(R.array.sim_toolkit_slot_1))
put(1, getComponentNames(R.array.sim_toolkit_slot_2)) put(1, getComponentNames(R.array.sim_toolkit_slot_2))
} }
private val packageNames = buildSet { private val packageNames: Iterable<String>
addAll(slotSelection.map { it.packageName }) get() = slots.values.flatten().map { it.packageName }.toSet()
addAll(slots.values.flatten().map { it.packageName })
}
private val activities: Iterable<ComponentName> private val activities: Iterable<ComponentName>
get() = packageNames.flatMap(::getActivities).toSet() get() = packageNames.flatMap(context.packageManager::getActivities)
.filter { it.exported }
.map { ComponentName(it.packageName, it.name) }
private val launchIntent: Intent? private val launchIntent: Intent?
get() = packageNames.firstNotNullOfOrNull(::getLaunchIntent) get() = packageNames.firstNotNullOfOrNull(context.packageManager::getLaunchIntent)
private fun getLaunchIntent(packageName: String) = try { private fun getComponentsBySlotId(slotId: Int) = buildSet {
pm.getLaunchIntentForPackage(packageName) addAll(slots.getOrDefault(slotId, emptySet()))
} catch (_: PackageManager.NameNotFoundException) { addAll(slots.getOrDefault(-1, emptySet()))
null
} }
private fun getActivities(packageName: String) = buildList { private fun intentActivity(slotId: Int): Intent? {
val activities = try { val component = getComponentsBySlotId(slotId).find(activities::contains)
pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES).activities ?: emptyArray() ?: return launchIntent
} catch (_: PackageManager.NameNotFoundException) { val disabled = try {
emptyArray() isDisabledState(context.packageManager.getComponentEnabledSetting(component))
} } catch (e: IllegalArgumentException) {
for (activity in activities) { true
if (!activity.exported) continue
add(ComponentName(packageName, activity.name))
} }
if (disabled) return null
return Intent.makeMainActivity(component)
} }
private fun getComponentNames(@ArrayRes id: Int) = private fun getDisabledPackageName(slotId: Int) =
context.resources.getStringArray(id).mapNotNull(ComponentName::unflattenFromString) getComponentsBySlotId(slotId).map { it.packageName }.toSet().find {
try {
isDisabledState(context.packageManager.getApplicationEnabledSetting(it))
} catch (e: IllegalArgumentException) {
false
}
}
fun isAvailable(slotId: Int) = when (slotId) { fun isAvailable(slotId: Int) = when (slotId) {
-1 -> false -1 -> false
EuiccChannelManager.USB_CHANNEL_ID -> false EuiccChannelManager.USB_CHANNEL_ID -> false
else -> intent(slotId) != null || getDisabledPackageName(slotId) != null else -> intentActivity(slotId) != null || getDisabledPackageName(slotId) != null
} }
fun intent(slotId: Int): Intent? { fun launch(slotId: Int): Boolean {
val components = slots.getOrDefault(slotId, emptySet()) + slotSelection var intent = intentActivity(slotId)
val intent = Intent(Intent.ACTION_MAIN, null).apply { if (intent == null) {
flags = Intent.FLAG_ACTIVITY_NEW_TASK val pkgName = getDisabledPackageName(slotId) ?: return false
component = components.find(activities::contains) val message = context.getString(
addCategory(Intent.CATEGORY_LAUNCHER) R.string.toast_prompt_to_enable_sim_toolkit,
context.packageManager.getApplicationLabel(pkgName)
)
intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", pkgName, null)
)
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
} }
return when (pm.getComponentEnabledSetting(intent.component ?: return launchIntent)) { context.startActivity(intent)
PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> intent return true
else -> null
} }
} }
fun getDisabledPackageName(slotId: Int): String? { private fun isDisabledState(state: Int) = when (state) {
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 -> true
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER -> true PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER -> true
else -> false else -> false
} }
private fun PackageManager.getApplicationLabel(packageName: String): CharSequence =
getApplicationLabel(getApplicationInfo(packageName, 0))
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<ActivityInfo>()
} }

View file

@ -9,7 +9,7 @@
<!-- Toast --> <!-- Toast -->
<string name="toast_ara_m_copied">ARA-M SHA-1 copied to clipboard</string> <string name="toast_ara_m_copied">ARA-M SHA-1 copied to clipboard</string>
<string name="toast_hint_enable_sim_toolkit">Please ENABLE your "%s" application</string> <string name="toast_prompt_to_enable_sim_toolkit">Please ENABLE your \&quot;%s\&quot; application</string>
<!-- Compatibility Check Descriptions --> <!-- Compatibility Check Descriptions -->
<string name="compatibility_check_system_features">System Features</string> <string name="compatibility_check_system_features">System Features</string>