Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
5dd9e40c25 | |||
6bb05d910b |
11 changed files with 85 additions and 65 deletions
|
@ -1,7 +1,7 @@
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- '*'
|
- 'master'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-debug:
|
build-debug:
|
||||||
|
|
|
@ -20,7 +20,8 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
|
||||||
|
|
||||||
override suspend fun tryOpenEuiccChannel(
|
override suspend fun tryOpenEuiccChannel(
|
||||||
port: UiccPortInfoCompat,
|
port: UiccPortInfoCompat,
|
||||||
isdrAid: ByteArray
|
isdrAid: ByteArray,
|
||||||
|
seId: Int,
|
||||||
): EuiccChannel? {
|
): EuiccChannel? {
|
||||||
if (port.portIndex != 0) {
|
if (port.portIndex != 0) {
|
||||||
Log.w(
|
Log.w(
|
||||||
|
@ -46,6 +47,7 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
|
||||||
context.preferenceRepository.verboseLoggingFlow
|
context.preferenceRepository.verboseLoggingFlow
|
||||||
),
|
),
|
||||||
isdrAid,
|
isdrAid,
|
||||||
|
seId,
|
||||||
context.preferenceRepository.verboseLoggingFlow,
|
context.preferenceRepository.verboseLoggingFlow,
|
||||||
context.preferenceRepository.ignoreTLSCertificateFlow,
|
context.preferenceRepository.ignoreTLSCertificateFlow,
|
||||||
).also {
|
).also {
|
||||||
|
@ -65,7 +67,8 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
|
||||||
|
|
||||||
override fun tryOpenUsbEuiccChannel(
|
override fun tryOpenUsbEuiccChannel(
|
||||||
ccidCtx: UsbCcidContext,
|
ccidCtx: UsbCcidContext,
|
||||||
isdrAid: ByteArray
|
isdrAid: ByteArray,
|
||||||
|
seId: Int
|
||||||
): EuiccChannel? {
|
): EuiccChannel? {
|
||||||
try {
|
try {
|
||||||
return EuiccChannelImpl(
|
return EuiccChannelImpl(
|
||||||
|
@ -76,6 +79,7 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
|
||||||
ccidCtx
|
ccidCtx
|
||||||
),
|
),
|
||||||
isdrAid,
|
isdrAid,
|
||||||
|
seId,
|
||||||
context.preferenceRepository.verboseLoggingFlow,
|
context.preferenceRepository.verboseLoggingFlow,
|
||||||
context.preferenceRepository.ignoreTLSCertificateFlow,
|
context.preferenceRepository.ignoreTLSCertificateFlow,
|
||||||
)
|
)
|
||||||
|
|
|
@ -32,7 +32,7 @@ open class DefaultEuiccChannelManager(
|
||||||
|
|
||||||
private val channelCache = mutableListOf<EuiccChannel>()
|
private val channelCache = mutableListOf<EuiccChannel>()
|
||||||
|
|
||||||
private var usbChannel: EuiccChannel? = null
|
private var usbChannels = mutableListOf<EuiccChannel>()
|
||||||
|
|
||||||
private val lock = Mutex()
|
private val lock = Mutex()
|
||||||
|
|
||||||
|
@ -51,15 +51,17 @@ open class DefaultEuiccChannelManager(
|
||||||
protected open val uiccCards: Collection<UiccCardInfoCompat>
|
protected open val uiccCards: Collection<UiccCardInfoCompat>
|
||||||
get() = (0..<tm.activeModemCountCompat).map { FakeUiccCardInfoCompat(it) }
|
get() = (0..<tm.activeModemCountCompat).map { FakeUiccCardInfoCompat(it) }
|
||||||
|
|
||||||
private suspend inline fun tryOpenChannelFirstValidAid(openFn: (ByteArray) -> EuiccChannel?): EuiccChannel? {
|
private suspend inline fun tryOpenChannelWithKnownAids(openFn: (ByteArray, Int) -> EuiccChannel?): List<EuiccChannel> {
|
||||||
val isdrAidList =
|
val isdrAidList =
|
||||||
parseIsdrAidList(appContainer.preferenceRepository.isdrAidListFlow.first())
|
parseIsdrAidList(appContainer.preferenceRepository.isdrAidListFlow.first())
|
||||||
|
var seId = 0
|
||||||
|
|
||||||
return isdrAidList.firstNotNullOfOrNull {
|
return isdrAidList.mapNotNull {
|
||||||
Log.i(TAG, "Opening channel, trying ISDR AID ${it.encodeHex()}")
|
Log.i(TAG, "Opening channel, trying ISDR AID ${it.encodeHex()}, this will be seId ${seId}")
|
||||||
|
|
||||||
openFn(it)?.let { channel ->
|
openFn(it, seId)?.let { channel ->
|
||||||
if (channel.valid) {
|
if (channel.valid) {
|
||||||
|
seId += 1
|
||||||
channel
|
channel
|
||||||
} else {
|
} else {
|
||||||
channel.close()
|
channel.close()
|
||||||
|
@ -69,19 +71,15 @@ open class DefaultEuiccChannelManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat): EuiccChannel? {
|
private suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat, seId: Int = 0): EuiccChannel? {
|
||||||
lock.withLock {
|
lock.withLock {
|
||||||
if (port.card.physicalSlotIndex == EuiccChannelManager.USB_CHANNEL_ID) {
|
if (port.card.physicalSlotIndex == EuiccChannelManager.USB_CHANNEL_ID) {
|
||||||
return if (usbChannel != null && usbChannel!!.valid) {
|
// We only compare seId because we assume we can only open 1 card from USB
|
||||||
usbChannel
|
return usbChannels.find { it.seId == seId }
|
||||||
} else {
|
|
||||||
usbChannel = null
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val existing =
|
val existing =
|
||||||
channelCache.find { it.slotId == port.card.physicalSlotIndex && it.portId == port.portIndex }
|
channelCache.find { it.slotId == port.card.physicalSlotIndex && it.portId == port.portIndex && it.seId == seId }
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
if (existing.valid && port.logicalSlotIndex == existing.logicalSlotId) {
|
if (existing.valid && port.logicalSlotIndex == existing.logicalSlotId) {
|
||||||
return existing
|
return existing
|
||||||
|
@ -96,12 +94,12 @@ open class DefaultEuiccChannelManager(
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val channel =
|
val channels =
|
||||||
tryOpenChannelFirstValidAid { euiccChannelFactory.tryOpenEuiccChannel(port, it) }
|
tryOpenChannelWithKnownAids { isdrAid, seId -> euiccChannelFactory.tryOpenEuiccChannel(port, isdrAid, seId) }
|
||||||
|
|
||||||
if (channel != null) {
|
if (channels.isNotEmpty()) {
|
||||||
channelCache.add(channel)
|
channelCache.addAll(channels)
|
||||||
return channel
|
return channels.find { it.seId == seId }
|
||||||
} else {
|
} else {
|
||||||
Log.i(
|
Log.i(
|
||||||
TAG,
|
TAG,
|
||||||
|
@ -112,10 +110,10 @@ open class DefaultEuiccChannelManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected suspend fun findEuiccChannelByLogicalSlot(logicalSlotId: Int): EuiccChannel? =
|
protected suspend fun findEuiccChannelByLogicalSlot(logicalSlotId: Int, seId: Int = 0): EuiccChannel? =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
if (logicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
|
if (logicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
|
||||||
return@withContext usbChannel
|
return@withContext usbChannels.find { it.seId == seId }
|
||||||
}
|
}
|
||||||
|
|
||||||
for (card in uiccCards) {
|
for (card in uiccCards) {
|
||||||
|
@ -131,7 +129,7 @@ open class DefaultEuiccChannelManager(
|
||||||
|
|
||||||
private suspend fun findAllEuiccChannelsByPhysicalSlot(physicalSlotId: Int): List<EuiccChannel>? {
|
private suspend fun findAllEuiccChannelsByPhysicalSlot(physicalSlotId: Int): List<EuiccChannel>? {
|
||||||
if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
|
if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
|
||||||
return usbChannel?.let { listOf(it) }
|
return usbChannels.ifEmpty { null }
|
||||||
}
|
}
|
||||||
|
|
||||||
for (card in uiccCards) {
|
for (card in uiccCards) {
|
||||||
|
@ -142,14 +140,14 @@ open class DefaultEuiccChannelManager(
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun findEuiccChannelByPort(physicalSlotId: Int, portId: Int): EuiccChannel? =
|
private suspend fun findEuiccChannelByPort(physicalSlotId: Int, portId: Int, seId: Int = 0): EuiccChannel? =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
|
if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
|
||||||
return@withContext usbChannel
|
return@withContext usbChannels.find { it.seId == seId }
|
||||||
}
|
}
|
||||||
|
|
||||||
uiccCards.find { it.physicalSlotIndex == physicalSlotId }?.let { card ->
|
uiccCards.find { it.physicalSlotIndex == physicalSlotId }?.let { card ->
|
||||||
card.ports.find { it.portIndex == portId }?.let { tryOpenEuiccChannel(it) }
|
card.ports.find { it.portIndex == portId }?.let { tryOpenEuiccChannel(it, seId) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,15 +166,16 @@ open class DefaultEuiccChannelManager(
|
||||||
return@withContext listOf(0)
|
return@withContext listOf(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
findAllEuiccChannelsByPhysicalSlot(physicalSlotId)?.map { it.portId } ?: listOf()
|
findAllEuiccChannelsByPhysicalSlot(physicalSlotId)?.map { it.portId }?.toSet()?.toList() ?: listOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun <R> withEuiccChannel(
|
override suspend fun <R> withEuiccChannel(
|
||||||
physicalSlotId: Int,
|
physicalSlotId: Int,
|
||||||
portId: Int,
|
portId: Int,
|
||||||
|
seId: Int,
|
||||||
fn: suspend (EuiccChannel) -> R
|
fn: suspend (EuiccChannel) -> R
|
||||||
): R {
|
): R {
|
||||||
val channel = findEuiccChannelByPort(physicalSlotId, portId)
|
val channel = findEuiccChannelByPort(physicalSlotId, portId, seId)
|
||||||
?: throw EuiccChannelManager.EuiccChannelNotFoundException()
|
?: throw EuiccChannelManager.EuiccChannelNotFoundException()
|
||||||
val wrapper = EuiccChannelWrapper(channel)
|
val wrapper = EuiccChannelWrapper(channel)
|
||||||
try {
|
try {
|
||||||
|
@ -190,9 +189,10 @@ open class DefaultEuiccChannelManager(
|
||||||
|
|
||||||
override suspend fun <R> withEuiccChannel(
|
override suspend fun <R> withEuiccChannel(
|
||||||
logicalSlotId: Int,
|
logicalSlotId: Int,
|
||||||
|
seId: Int,
|
||||||
fn: suspend (EuiccChannel) -> R
|
fn: suspend (EuiccChannel) -> R
|
||||||
): R {
|
): R {
|
||||||
val channel = findEuiccChannelByLogicalSlot(logicalSlotId)
|
val channel = findEuiccChannelByLogicalSlot(logicalSlotId, seId)
|
||||||
?: throw EuiccChannelManager.EuiccChannelNotFoundException()
|
?: throw EuiccChannelManager.EuiccChannelNotFoundException()
|
||||||
val wrapper = EuiccChannelWrapper(channel)
|
val wrapper = EuiccChannelWrapper(channel)
|
||||||
try {
|
try {
|
||||||
|
@ -206,8 +206,8 @@ open class DefaultEuiccChannelManager(
|
||||||
|
|
||||||
override suspend fun waitForReconnect(physicalSlotId: Int, portId: Int, timeoutMillis: Long) {
|
override suspend fun waitForReconnect(physicalSlotId: Int, portId: Int, timeoutMillis: Long) {
|
||||||
if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
|
if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
|
||||||
usbChannel?.close()
|
usbChannels.forEach { it.close() }
|
||||||
usbChannel = null
|
usbChannels.clear()
|
||||||
} else {
|
} else {
|
||||||
// If there is already a valid channel, we close it proactively
|
// If there is already a valid channel, we close it proactively
|
||||||
// Sometimes the current channel can linger on for a bit even after it should have become invalid
|
// Sometimes the current channel can linger on for a bit even after it should have become invalid
|
||||||
|
@ -223,7 +223,7 @@ open class DefaultEuiccChannelManager(
|
||||||
// tryOpenUsbEuiccChannel() will always try to reopen the channel, even if
|
// tryOpenUsbEuiccChannel() will always try to reopen the channel, even if
|
||||||
// a USB channel already exists
|
// a USB channel already exists
|
||||||
tryOpenUsbEuiccChannel()
|
tryOpenUsbEuiccChannel()
|
||||||
usbChannel!!
|
usbChannels.getOrNull(0)!!
|
||||||
} else {
|
} else {
|
||||||
// tryOpenEuiccChannel() will automatically dispose of invalid channels
|
// tryOpenEuiccChannel() will automatically dispose of invalid channels
|
||||||
// and recreate when needed
|
// and recreate when needed
|
||||||
|
@ -280,12 +280,13 @@ open class DefaultEuiccChannelManager(
|
||||||
val ccidCtx = UsbCcidContext.createFromUsbDevice(context, device, iface) ?: return@forEach
|
val ccidCtx = UsbCcidContext.createFromUsbDevice(context, device, iface) ?: return@forEach
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val channel = tryOpenChannelFirstValidAid {
|
val channels = tryOpenChannelWithKnownAids { isdrAid, seId ->
|
||||||
euiccChannelFactory.tryOpenUsbEuiccChannel(ccidCtx, it)
|
euiccChannelFactory.tryOpenUsbEuiccChannel(ccidCtx, isdrAid, seId)
|
||||||
}
|
}
|
||||||
if (channel != null && channel.lpa.valid) {
|
if (channels.isNotEmpty() && channels[0].valid) {
|
||||||
ccidCtx.allowDisconnect = true
|
ccidCtx.allowDisconnect = true
|
||||||
usbChannel = channel
|
usbChannels.clear()
|
||||||
|
usbChannels.addAll(channels)
|
||||||
return@withContext Pair(device, true)
|
return@withContext Pair(device, true)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -309,8 +310,8 @@ open class DefaultEuiccChannelManager(
|
||||||
channel.close()
|
channel.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
usbChannel?.close()
|
usbChannels.forEach { it.close() }
|
||||||
usbChannel = null
|
usbChannels.clear()
|
||||||
channelCache.clear()
|
channelCache.clear()
|
||||||
euiccChannelFactory.cleanup()
|
euiccChannelFactory.cleanup()
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,16 @@ interface EuiccChannel {
|
||||||
val logicalSlotId: Int
|
val logicalSlotId: Int
|
||||||
val portId: Int
|
val portId: Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some chips support multiple SEs on one chip. The seId here is intended
|
||||||
|
* to distinguish channels opened from these different SEs.
|
||||||
|
*
|
||||||
|
* Note that this ID is arbitrary and heavily depends on the order in which
|
||||||
|
* we attempt to open the ISD-R AIDs. As such, it shall not be treated with
|
||||||
|
* any significance other than as a transient ID.
|
||||||
|
*/
|
||||||
|
val seId: Int
|
||||||
|
|
||||||
val lpa: LocalProfileAssistant
|
val lpa: LocalProfileAssistant
|
||||||
|
|
||||||
val valid: Boolean
|
val valid: Boolean
|
||||||
|
|
|
@ -6,11 +6,12 @@ import im.angry.openeuicc.util.*
|
||||||
// This class is here instead of inside DI because it contains a bit more logic than just
|
// This class is here instead of inside DI because it contains a bit more logic than just
|
||||||
// "dumb" dependency injection.
|
// "dumb" dependency injection.
|
||||||
interface EuiccChannelFactory {
|
interface EuiccChannelFactory {
|
||||||
suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat, isdrAid: ByteArray): EuiccChannel?
|
suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat, isdrAid: ByteArray, seInt: Int): EuiccChannel?
|
||||||
|
|
||||||
fun tryOpenUsbEuiccChannel(
|
fun tryOpenUsbEuiccChannel(
|
||||||
ccidCtx: UsbCcidContext,
|
ccidCtx: UsbCcidContext,
|
||||||
isdrAid: ByteArray
|
isdrAid: ByteArray,
|
||||||
|
seInt: Int
|
||||||
): EuiccChannel?
|
): EuiccChannel?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,6 +14,7 @@ class EuiccChannelImpl(
|
||||||
override val intrinsicChannelName: String?,
|
override val intrinsicChannelName: String?,
|
||||||
override val apduInterface: ApduInterface,
|
override val apduInterface: ApduInterface,
|
||||||
override val isdrAid: ByteArray,
|
override val isdrAid: ByteArray,
|
||||||
|
override val seId: Int,
|
||||||
verboseLoggingFlow: Flow<Boolean>,
|
verboseLoggingFlow: Flow<Boolean>,
|
||||||
ignoreTLSCertificateFlow: Flow<Boolean>
|
ignoreTLSCertificateFlow: Flow<Boolean>
|
||||||
) : EuiccChannel {
|
) : EuiccChannel {
|
||||||
|
|
|
@ -81,6 +81,7 @@ interface EuiccChannelManager {
|
||||||
suspend fun <R> withEuiccChannel(
|
suspend fun <R> withEuiccChannel(
|
||||||
physicalSlotId: Int,
|
physicalSlotId: Int,
|
||||||
portId: Int,
|
portId: Int,
|
||||||
|
seId: Int = 0,
|
||||||
fn: suspend (EuiccChannel) -> R
|
fn: suspend (EuiccChannel) -> R
|
||||||
): R
|
): R
|
||||||
|
|
||||||
|
@ -89,6 +90,7 @@ interface EuiccChannelManager {
|
||||||
*/
|
*/
|
||||||
suspend fun <R> withEuiccChannel(
|
suspend fun <R> withEuiccChannel(
|
||||||
logicalSlotId: Int,
|
logicalSlotId: Int,
|
||||||
|
seId: Int = 0,
|
||||||
fn: suspend (EuiccChannel) -> R
|
fn: suspend (EuiccChannel) -> R
|
||||||
): R
|
): R
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ class EuiccChannelWrapper(orig: EuiccChannel) : EuiccChannel {
|
||||||
get() = channel.logicalSlotId
|
get() = channel.logicalSlotId
|
||||||
override val portId: Int
|
override val portId: Int
|
||||||
get() = channel.portId
|
get() = channel.portId
|
||||||
|
override val seId: Int
|
||||||
|
get() = channel.seId
|
||||||
private val lpaDelegate = lazy {
|
private val lpaDelegate = lazy {
|
||||||
LocalProfileAssistantWrapper(channel.lpa)
|
LocalProfileAssistantWrapper(channel.lpa)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,6 @@ import kotlinx.coroutines.launch
|
||||||
import net.typeblog.lpac_jni.impl.PKID_GSMA_LIVE_CI
|
import net.typeblog.lpac_jni.impl.PKID_GSMA_LIVE_CI
|
||||||
import net.typeblog.lpac_jni.impl.PKID_GSMA_TEST_CI
|
import net.typeblog.lpac_jni.impl.PKID_GSMA_TEST_CI
|
||||||
|
|
||||||
// https://euicc-manual.osmocom.org/docs/pki/eum/accredited.json
|
|
||||||
// ref: <https://regex101.com/r/5FFz8u>
|
|
||||||
private val RE_SAS = Regex(
|
|
||||||
"""^[A-Z]{2}-[A-Z]{2}(?:-UP)?-\d{4}T?(?:-\d+)?T?$""",
|
|
||||||
setOf(RegexOption.IGNORE_CASE),
|
|
||||||
)
|
|
||||||
|
|
||||||
class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
|
class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
|
||||||
companion object {
|
companion object {
|
||||||
private val YES_NO = Pair(R.string.yes, R.string.no)
|
private val YES_NO = Pair(R.string.yes, R.string.no)
|
||||||
|
@ -99,7 +92,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
(infoList.adapter!! as EuiccInfoAdapter).euiccInfoItems =
|
(infoList.adapter!! as EuiccInfoAdapter).euiccInfoItems =
|
||||||
euiccChannelManager.withEuiccChannel(logicalSlotId, ::buildEuiccInfoItems)
|
euiccChannelManager.withEuiccChannel(logicalSlotId, fn = ::buildEuiccInfoItems)
|
||||||
|
|
||||||
swipeRefresh.isRefreshing = false
|
swipeRefresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
|
@ -116,14 +109,13 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
|
||||||
vendorInfo.firmwareVersion?.let { add(Item(R.string.euicc_info_fw_ver, it)) }
|
vendorInfo.firmwareVersion?.let { add(Item(R.string.euicc_info_fw_ver, it)) }
|
||||||
vendorInfo.bootloaderVersion?.let { add(Item(R.string.euicc_info_bl_ver, it)) }
|
vendorInfo.bootloaderVersion?.let { add(Item(R.string.euicc_info_bl_ver, it)) }
|
||||||
}
|
}
|
||||||
channel.lpa.euiccInfo2?.let { info ->
|
channel.lpa.euiccInfo2.let { info ->
|
||||||
add(Item(R.string.euicc_info_sgp22_version, info.sgp22Version.toString()))
|
add(Item(R.string.euicc_info_sgp22_version, info?.sgp22Version.toString()))
|
||||||
add(Item(R.string.euicc_info_firmware_version, info.euiccFirmwareVersion.toString()))
|
add(Item(R.string.euicc_info_firmware_version, info?.euiccFirmwareVersion.toString()))
|
||||||
add(Item(R.string.euicc_info_globalplatform_version, info.globalPlatformVersion.toString()))
|
add(Item(R.string.euicc_info_globalplatform_version, info?.globalPlatformVersion.toString()))
|
||||||
add(Item(R.string.euicc_info_pp_version, info.ppVersion.toString()))
|
add(Item(R.string.euicc_info_pp_version, info?.ppVersion.toString()))
|
||||||
info.sasAccreditationNumber.trim().takeIf(RE_SAS::matches)
|
add(Item(R.string.euicc_info_sas_accreditation_number, info?.sasAccreditationNumber))
|
||||||
?.let { add(Item(R.string.euicc_info_sas_accreditation_number, it.uppercase())) }
|
add(Item(R.string.euicc_info_free_nvram, info?.freeNvram?.let(::formatFreeSpace)))
|
||||||
add(Item(R.string.euicc_info_free_nvram, info.freeNvram.let(::formatFreeSpace)))
|
|
||||||
}
|
}
|
||||||
channel.lpa.euiccInfo2?.euiccCiPKIdListForSigning.orEmpty().let { signers ->
|
channel.lpa.euiccInfo2?.euiccCiPKIdListForSigning.orEmpty().let { signers ->
|
||||||
// SGP.28 v1.0, eSIM CI Registration Criteria (Page 5 of 9, 2019-10-24)
|
// SGP.28 v1.0, eSIM CI Registration Criteria (Page 5 of 9, 2019-10-24)
|
||||||
|
@ -142,9 +134,14 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
|
||||||
add(Item(R.string.euicc_info_atr, atr, copiedToastResId = R.string.toast_atr_copied))
|
add(Item(R.string.euicc_info_atr, atr, copiedToastResId = R.string.toast_atr_copied))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("SameParameterValue")
|
|
||||||
private fun formatByBoolean(b: Boolean, res: Pair<Int, Int>): String =
|
private fun formatByBoolean(b: Boolean, res: Pair<Int, Int>): String =
|
||||||
getString(if (b) res.first else res.second)
|
getString(
|
||||||
|
if (b) {
|
||||||
|
res.first
|
||||||
|
} else {
|
||||||
|
res.second
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
inner class EuiccInfoViewHolder(root: View) : ViewHolder(root) {
|
inner class EuiccInfoViewHolder(root: View) : ViewHolder(root) {
|
||||||
private val title: TextView = root.requireViewById(R.id.euicc_info_title)
|
private val title: TextView = root.requireViewById(R.id.euicc_info_title)
|
||||||
|
|
|
@ -16,13 +16,14 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
override suspend fun tryOpenEuiccChannel(
|
override suspend fun tryOpenEuiccChannel(
|
||||||
port: UiccPortInfoCompat,
|
port: UiccPortInfoCompat,
|
||||||
isdrAid: ByteArray
|
isdrAid: ByteArray,
|
||||||
|
seId: Int,
|
||||||
): EuiccChannel? {
|
): EuiccChannel? {
|
||||||
val port = port as RealUiccPortInfoCompat
|
val port = port as RealUiccPortInfoCompat
|
||||||
if (port.card.isRemovable) {
|
if (port.card.isRemovable) {
|
||||||
// Attempt unprivileged (OMAPI) before TelephonyManager
|
// Attempt unprivileged (OMAPI) before TelephonyManager
|
||||||
// but still try TelephonyManager in case OMAPI is broken
|
// but still try TelephonyManager in case OMAPI is broken
|
||||||
super.tryOpenEuiccChannel(port, isdrAid)?.let { return it }
|
super.tryOpenEuiccChannel(port, isdrAid, seId)?.let { return it }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port.card.isEuicc || preferenceRepository.removableTelephonyManagerFlow.first()) {
|
if (port.card.isEuicc || preferenceRepository.removableTelephonyManagerFlow.first()) {
|
||||||
|
@ -41,6 +42,7 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto
|
||||||
context.preferenceRepository.verboseLoggingFlow
|
context.preferenceRepository.verboseLoggingFlow
|
||||||
),
|
),
|
||||||
isdrAid,
|
isdrAid,
|
||||||
|
seId,
|
||||||
context.preferenceRepository.verboseLoggingFlow,
|
context.preferenceRepository.verboseLoggingFlow,
|
||||||
context.preferenceRepository.ignoreTLSCertificateFlow,
|
context.preferenceRepository.ignoreTLSCertificateFlow,
|
||||||
)
|
)
|
||||||
|
@ -53,6 +55,6 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.tryOpenEuiccChannel(port, isdrAid)
|
return super.tryOpenEuiccChannel(port, isdrAid, seId)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -80,7 +80,7 @@ apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t *rx_len, c
|
||||||
LPAC_JNI_EXCEPTION_RETURN;
|
LPAC_JNI_EXCEPTION_RETURN;
|
||||||
*rx_len = (*env)->GetArrayLength(env, ret);
|
*rx_len = (*env)->GetArrayLength(env, ret);
|
||||||
*rx = calloc(*rx_len, sizeof(uint8_t));
|
*rx = calloc(*rx_len, sizeof(uint8_t));
|
||||||
(*env)->GetByteArrayRegion(env, ret, 0, *rx_len, (jbyte *) *rx);
|
(*env)->GetByteArrayRegion(env, ret, 0, *rx_len, *rx);
|
||||||
(*env)->DeleteLocalRef(env, txArr);
|
(*env)->DeleteLocalRef(env, txArr);
|
||||||
(*env)->DeleteLocalRef(env, ret);
|
(*env)->DeleteLocalRef(env, ret);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -113,7 +113,7 @@ http_interface_transmit(struct euicc_ctx *ctx, const char *url, uint32_t *rcode,
|
||||||
jbyteArray rxArr = (jbyteArray) (*env)->GetObjectField(env, ret, field_resp_data);
|
jbyteArray rxArr = (jbyteArray) (*env)->GetObjectField(env, ret, field_resp_data);
|
||||||
*rx_len = (*env)->GetArrayLength(env, rxArr);
|
*rx_len = (*env)->GetArrayLength(env, rxArr);
|
||||||
*rx = calloc(*rx_len, sizeof(uint8_t));
|
*rx = calloc(*rx_len, sizeof(uint8_t));
|
||||||
(*env)->GetByteArrayRegion(env, rxArr, 0, *rx_len, (jbyte *) *rx);
|
(*env)->GetByteArrayRegion(env, rxArr, 0, *rx_len, *rx);
|
||||||
(*env)->DeleteLocalRef(env, txArr);
|
(*env)->DeleteLocalRef(env, txArr);
|
||||||
(*env)->DeleteLocalRef(env, rxArr);
|
(*env)->DeleteLocalRef(env, rxArr);
|
||||||
(*env)->DeleteLocalRef(env, headersArr);
|
(*env)->DeleteLocalRef(env, headersArr);
|
||||||
|
|
Loading…
Add table
Reference in a new issue