Compare commits
1 commit
9673de4d07
...
b59a85e120
Author | SHA1 | Date | |
---|---|---|---|
b59a85e120 |
3 changed files with 82 additions and 100 deletions
|
@ -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
|
||||||
|
@ -29,36 +24,9 @@ class UnprivilegedEuiccManagementFragment : EuiccManagementFragment() {
|
||||||
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).apply {
|
menu.findItem(R.id.open_sim_toolkit).apply {
|
||||||
isVisible = stk.isAvailable(slotId)
|
val slot = stk[slotId] ?: return@apply
|
||||||
setOnMenuItemClickListener { launchSIMToolkit() }
|
isVisible = slot.available
|
||||||
}
|
setOnMenuItemClickListener { slot.launch() }
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 {
|
operator fun get(slotId: Int): Slot? = when (slotId) {
|
||||||
addAll(slotSelection.map { it.packageName })
|
-1, EuiccChannelManager.USB_CHANNEL_ID -> null
|
||||||
addAll(slots.values.flatten().map { it.packageName })
|
else -> Slot(context, buildSet {
|
||||||
|
addAll(slots.getOrDefault(slotId, emptySet()))
|
||||||
|
addAll(slots.getOrDefault(-1, emptySet()))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private val activities: Iterable<ComponentName>
|
data class Slot(private val context: Context, private val components: Set<ComponentName>) {
|
||||||
get() = packageNames.flatMap(::getActivities).toSet()
|
private val packageManager: PackageManager
|
||||||
|
get() = context.packageManager
|
||||||
|
|
||||||
|
private val packageNames: Iterable<String>
|
||||||
|
get() = components.map(ComponentName::getPackageName).toSet()
|
||||||
|
|
||||||
private val launchIntent: Intent?
|
private val launchIntent: Intent?
|
||||||
get() = packageNames.firstNotNullOfOrNull(::getLaunchIntent)
|
get() = packageNames.firstNotNullOfOrNull(packageManager::getLaunchIntent)
|
||||||
|
|
||||||
private fun getLaunchIntent(packageName: String) = try {
|
private val activities: Iterable<ComponentName>
|
||||||
pm.getLaunchIntentForPackage(packageName)
|
get() = packageNames.flatMap(packageManager::getActivities)
|
||||||
} catch (_: PackageManager.NameNotFoundException) {
|
.filter(ActivityInfo::exported).map { ComponentName(it.packageName, it.name) }
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getActivities(packageName: String) = buildList {
|
val available: Boolean
|
||||||
val activities = try {
|
get() = getIntent() != null || getDisabledPackageName() != null
|
||||||
pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES).activities ?: emptyArray()
|
|
||||||
} catch (_: PackageManager.NameNotFoundException) {
|
private fun getIntent(): Intent? {
|
||||||
emptyArray()
|
|
||||||
}
|
|
||||||
for (activity in activities) {
|
for (activity in activities) {
|
||||||
if (!activity.exported) continue
|
if (!components.contains(activity)) continue
|
||||||
add(ComponentName(packageName, activity.name))
|
if (isDisabledState(packageManager.getComponentEnabledSetting(activity))) continue
|
||||||
|
return Intent.makeMainActivity(activity)
|
||||||
|
}
|
||||||
|
return launchIntent
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDisabledPackageName() = packageNames.find {
|
||||||
|
try {
|
||||||
|
isDisabledState(packageManager.getApplicationEnabledSetting(it))
|
||||||
|
} catch (_: IllegalArgumentException) {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getComponentNames(@ArrayRes id: Int) =
|
fun launch(): Boolean {
|
||||||
context.resources.getStringArray(id).mapNotNull(ComponentName::unflattenFromString)
|
var intent = getIntent()
|
||||||
|
if (intent == null) {
|
||||||
fun isAvailable(slotId: Int) = when (slotId) {
|
val pkgName = getDisabledPackageName() ?: return false
|
||||||
-1 -> false
|
val message = context.getString(
|
||||||
EuiccChannelManager.USB_CHANNEL_ID -> false
|
R.string.toast_prompt_to_enable_sim_toolkit,
|
||||||
else -> intent(slotId) != null || getDisabledPackageName(slotId) != null
|
packageManager.getApplicationLabel(pkgName)
|
||||||
|
)
|
||||||
|
intent = Intent(
|
||||||
|
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||||
|
Uri.fromParts("package", pkgName, null)
|
||||||
|
)
|
||||||
|
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
context.startActivity(intent)
|
||||||
fun intent(slotId: Int): Intent? {
|
return true
|
||||||
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 when (pm.getComponentEnabledSetting(intent.component ?: return launchIntent)) {
|
|
||||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> intent
|
|
||||||
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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 \"%s\" 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>
|
||||||
|
|
Loading…
Add table
Reference in a new issue