Compare commits
No commits in common. "100d2e2866ebf2fbc7a2360fad4785a5550703ec" and "ed585edf49cb57d131e43c4a61297ce3b4180609" have entirely different histories.
100d2e2866
...
ed585edf49
3 changed files with 26 additions and 118 deletions
|
@ -121,20 +121,6 @@ open class EuiccChannelManager(protected val context: Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findEuiccChannelByPhysicalSlotBlocking(physicalSlotId: Int): EuiccChannel? = runBlocking {
|
|
||||||
if (!checkPrivileges()) return@runBlocking null
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
for (card in tm.uiccCardsInfoCompat) {
|
|
||||||
if (card.physicalSlotIndex != physicalSlotId) continue
|
|
||||||
for (port in card.ports) {
|
|
||||||
tryOpenEuiccChannel(port)?.let { return@withContext it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findEuiccChannelByPortBlocking(physicalSlotId: Int, portId: Int): EuiccChannel? = runBlocking {
|
fun findEuiccChannelByPortBlocking(physicalSlotId: Int, portId: Int): EuiccChannel? = runBlocking {
|
||||||
if (!checkPrivileges()) return@runBlocking null
|
if (!checkPrivileges()) return@runBlocking null
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
|
|
|
@ -1,31 +1,20 @@
|
||||||
package im.angry.openeuicc.service
|
package im.angry.openeuicc.service
|
||||||
|
|
||||||
import android.service.euicc.*
|
import android.service.euicc.*
|
||||||
import android.telephony.UiccSlotMapping
|
|
||||||
import android.telephony.euicc.DownloadableSubscription
|
import android.telephony.euicc.DownloadableSubscription
|
||||||
import android.telephony.euicc.EuiccInfo
|
import android.telephony.euicc.EuiccInfo
|
||||||
import android.util.Log
|
|
||||||
import net.typeblog.lpac_jni.LocalProfileInfo
|
import net.typeblog.lpac_jni.LocalProfileInfo
|
||||||
import im.angry.openeuicc.OpenEuiccApplication
|
import im.angry.openeuicc.OpenEuiccApplication
|
||||||
import im.angry.openeuicc.core.EuiccChannel
|
import im.angry.openeuicc.core.EuiccChannel
|
||||||
import im.angry.openeuicc.util.*
|
import im.angry.openeuicc.util.*
|
||||||
import java.lang.IllegalStateException
|
|
||||||
|
|
||||||
class OpenEuiccService : EuiccService() {
|
class OpenEuiccService : EuiccService() {
|
||||||
companion object {
|
|
||||||
const val TAG = "OpenEuiccService"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val openEuiccApplication
|
private val openEuiccApplication
|
||||||
get() = application as OpenEuiccApplication
|
get() = application as OpenEuiccApplication
|
||||||
|
|
||||||
private fun findChannel(physicalSlotId: Int): EuiccChannel? =
|
private fun findChannel(slotId: Int): EuiccChannel? =
|
||||||
openEuiccApplication.euiccChannelManager
|
openEuiccApplication.euiccChannelManager
|
||||||
.findEuiccChannelByPhysicalSlotBlocking(physicalSlotId)
|
.findEuiccChannelBySlotBlocking(slotId)
|
||||||
|
|
||||||
private fun findChannel(slotId: Int, portId: Int): EuiccChannel? =
|
|
||||||
openEuiccApplication.euiccChannelManager
|
|
||||||
.findEuiccChannelByPortBlocking(slotId, portId)
|
|
||||||
|
|
||||||
override fun onGetEid(slotId: Int): String? =
|
override fun onGetEid(slotId: Int): String? =
|
||||||
findChannel(slotId)?.lpa?.eID
|
findChannel(slotId)?.lpa?.eID
|
||||||
|
@ -36,47 +25,6 @@ class OpenEuiccService : EuiccService() {
|
||||||
private fun EuiccChannel.profileExists(iccid: String?) =
|
private fun EuiccChannel.profileExists(iccid: String?) =
|
||||||
lpa.profiles.any { it.iccid == iccid }
|
lpa.profiles.any { it.iccid == iccid }
|
||||||
|
|
||||||
private fun ensurePortIsMapped(slotId: Int, portId: Int) {
|
|
||||||
val mappings = openEuiccApplication.telephonyManager.simSlotMapping.toMutableList()
|
|
||||||
|
|
||||||
mappings.firstOrNull { it.physicalSlotIndex == slotId && it.portIndex == portId }?.let {
|
|
||||||
throw IllegalStateException("Slot $slotId port $portId has already been mapped")
|
|
||||||
}
|
|
||||||
|
|
||||||
val idx = mappings.indexOfFirst { it.physicalSlotIndex != slotId || it.portIndex != portId }
|
|
||||||
if (idx >= 0) {
|
|
||||||
mappings[idx] = UiccSlotMapping(portId, slotId, mappings[idx].logicalSlotIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
mappings.firstOrNull { it.physicalSlotIndex == slotId && it.portIndex == portId } ?: run {
|
|
||||||
throw IllegalStateException("Cannot map slot $slotId port $portId")
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
openEuiccApplication.telephonyManager.simSlotMapping = mappings
|
|
||||||
return
|
|
||||||
} catch (_: Exception) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sometimes hardware supports one ordering but not the reverse
|
|
||||||
openEuiccApplication.telephonyManager.simSlotMapping = mappings.reversed()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T> retryWithTimeout(timeoutMillis: Int, backoff: Int = 1000, f: () -> T?): T? {
|
|
||||||
val startTimeMillis = System.currentTimeMillis()
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
f()?.let { return@retryWithTimeout it }
|
|
||||||
} catch (_: Exception) {
|
|
||||||
// Ignore
|
|
||||||
} finally {
|
|
||||||
Thread.sleep(backoff.toLong())
|
|
||||||
}
|
|
||||||
} while (System.currentTimeMillis() - startTimeMillis < timeoutMillis)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetOtaStatus(slotId: Int): Int {
|
override fun onGetOtaStatus(slotId: Int): Int {
|
||||||
// Not implemented
|
// Not implemented
|
||||||
return 5 // EUICC_OTA_STATUS_UNAVAILABLE
|
return 5 // EUICC_OTA_STATUS_UNAVAILABLE
|
||||||
|
@ -108,7 +56,6 @@ class OpenEuiccService : EuiccService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetEuiccProfileInfoList(slotId: Int): GetEuiccProfileInfoListResult? {
|
override fun onGetEuiccProfileInfoList(slotId: Int): GetEuiccProfileInfoListResult? {
|
||||||
Log.i(TAG, "onGetEuiccProfileInfoList slotId=$slotId")
|
|
||||||
val channel = findChannel(slotId) ?: return null
|
val channel = findChannel(slotId) ?: return null
|
||||||
val profiles = channel.lpa.profiles.operational.map {
|
val profiles = channel.lpa.profiles.operational.map {
|
||||||
EuiccProfileInfo.Builder(it.iccid).apply {
|
EuiccProfileInfo.Builder(it.iccid).apply {
|
||||||
|
@ -139,7 +86,6 @@ class OpenEuiccService : EuiccService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDeleteSubscription(slotId: Int, iccid: String): Int {
|
override fun onDeleteSubscription(slotId: Int, iccid: String): Int {
|
||||||
Log.i(TAG, "onDeleteSubscription slotId=$slotId iccid=$iccid")
|
|
||||||
try {
|
try {
|
||||||
val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
|
val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
|
||||||
|
|
||||||
|
@ -153,7 +99,6 @@ class OpenEuiccService : EuiccService() {
|
||||||
|
|
||||||
if (profile.state == LocalProfileInfo.State.Enabled) {
|
if (profile.state == LocalProfileInfo.State.Enabled) {
|
||||||
// Must disable the profile first
|
// Must disable the profile first
|
||||||
// TODO: Need to check "other port" as well for MEP
|
|
||||||
return RESULT_FIRST_USER
|
return RESULT_FIRST_USER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,63 +112,40 @@ class OpenEuiccService : EuiccService() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: on some devices we need to update the mapping (and potentially disable a pSIM)
|
||||||
|
// for eSIM to be usable, in which case we will have to respect forceDeactivateSim.
|
||||||
|
// This is the same for our custom LUI. Both have to take this into consideration.
|
||||||
@Deprecated("Deprecated in Java")
|
@Deprecated("Deprecated in Java")
|
||||||
override fun onSwitchToSubscription(
|
override fun onSwitchToSubscription(
|
||||||
slotId: Int,
|
slotId: Int,
|
||||||
iccid: String?,
|
iccid: String?,
|
||||||
forceDeactivateSim: Boolean
|
forceDeactivateSim: Boolean
|
||||||
): Int =
|
|
||||||
// -1 = any port
|
|
||||||
onSwitchToSubscriptionWithPort(slotId, -1, iccid, forceDeactivateSim)
|
|
||||||
|
|
||||||
override fun onSwitchToSubscriptionWithPort(
|
|
||||||
slotId: Int,
|
|
||||||
portIndex: Int,
|
|
||||||
iccid: String?,
|
|
||||||
forceDeactivateSim: Boolean
|
|
||||||
): Int {
|
): Int {
|
||||||
Log.i(TAG,"onSwitchToSubscriptionWithPort slotId=$slotId portIndex=$portIndex iccid=$iccid forceDeactivateSim=$forceDeactivateSim")
|
|
||||||
try {
|
try {
|
||||||
// retryWithTimeout is needed here because this function may be called just after
|
val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
|
||||||
// AOSP has switched slot mappings, in which case the slots may not be ready yet.
|
|
||||||
val channel = if (portIndex == -1) {
|
|
||||||
retryWithTimeout(5000) { findChannel(slotId) }
|
|
||||||
} else {
|
|
||||||
retryWithTimeout(5000) { findChannel(slotId, portIndex) }
|
|
||||||
} ?: run {
|
|
||||||
if (!forceDeactivateSim) {
|
|
||||||
// The user must select which SIM to deactivate
|
|
||||||
return@onSwitchToSubscriptionWithPort RESULT_MUST_DEACTIVATE_SIM
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
// If we are allowed to deactivate any SIM we like, try mapping the indicated port first
|
|
||||||
ensurePortIsMapped(slotId, portIndex)
|
|
||||||
retryWithTimeout(5000) { findChannel(slotId, portIndex) }
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// We cannot map the port (or it is already mapped)
|
|
||||||
// but we can also use any port available on the card
|
|
||||||
retryWithTimeout(5000) { findChannel(slotId) }
|
|
||||||
} ?: return@onSwitchToSubscriptionWithPort RESULT_FIRST_USER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iccid != null && !channel.profileExists(iccid)) {
|
if (!channel.profileExists(iccid)) {
|
||||||
Log.i(TAG, "onSwitchToSubscriptionWithPort iccid=$iccid not found")
|
|
||||||
return RESULT_FIRST_USER
|
return RESULT_FIRST_USER
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable any active profile first if present
|
if (iccid == null) {
|
||||||
channel.lpa.profiles.find {
|
// Disable active profile
|
||||||
it.state == LocalProfileInfo.State.Enabled
|
val activeProfile = channel.lpa.profiles.find {
|
||||||
}?.let { if (!channel.lpa.disableProfile(it.iccid)) return RESULT_FIRST_USER }
|
it.state == LocalProfileInfo.State.Enabled
|
||||||
|
} ?: return RESULT_OK
|
||||||
|
|
||||||
if (iccid != null) {
|
return if (channel.lpa.disableProfile(activeProfile.iccid)) {
|
||||||
if (!channel.lpa.enableProfile(iccid)) {
|
RESULT_OK
|
||||||
return RESULT_FIRST_USER
|
} else {
|
||||||
|
RESULT_FIRST_USER
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return if (channel.lpa.enableProfile(iccid)) {
|
||||||
|
RESULT_OK
|
||||||
|
} else {
|
||||||
|
RESULT_FIRST_USER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_OK
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return RESULT_FIRST_USER
|
return RESULT_FIRST_USER
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -232,7 +154,6 @@ class OpenEuiccService : EuiccService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUpdateSubscriptionNickname(slotId: Int, iccid: String, nickname: String?): Int {
|
override fun onUpdateSubscriptionNickname(slotId: Int, iccid: String, nickname: String?): Int {
|
||||||
Log.i(TAG, "onUpdateSubscriptionNickname slotId=$slotId iccid=$iccid nickname=$nickname")
|
|
||||||
val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
|
val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
|
||||||
if (!channel.profileExists(iccid)) {
|
if (!channel.profileExists(iccid)) {
|
||||||
return RESULT_FIRST_USER
|
return RESULT_FIRST_USER
|
||||||
|
|
|
@ -20,10 +20,11 @@ class LocalProfileAssistantImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override val profiles: List<LocalProfileInfo>
|
override val profiles: List<LocalProfileInfo>
|
||||||
get() = LpacJni.es10cGetProfilesInfo(contextHandle)!!.asList()
|
get() = LpacJni.es10cGetProfilesInfo(contextHandle)!!.asList() // TODO: Maybe we need better error handling
|
||||||
|
|
||||||
override val eID: String
|
override val eID: String by lazy {
|
||||||
get() = LpacJni.es10cGetEid(contextHandle)!!
|
LpacJni.es10cGetEid(contextHandle)!!
|
||||||
|
}
|
||||||
|
|
||||||
override val euiccInfo2: EuiccInfo2?
|
override val euiccInfo2: EuiccInfo2?
|
||||||
get() = LpacJni.es10cexGetEuiccInfo2(contextHandle)
|
get() = LpacJni.es10cexGetEuiccInfo2(contextHandle)
|
||||||
|
|
Loading…
Add table
Reference in a new issue