diff --git a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt index 93b002e..78a8c3f 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt @@ -20,8 +20,7 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha override suspend fun tryOpenEuiccChannel( port: UiccPortInfoCompat, - isdrAid: ByteArray, - seId: EuiccChannel.SecureElementId, + isdrAid: ByteArray ): EuiccChannel? = try { if (port.portIndex != 0) { Log.w( @@ -46,7 +45,6 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha context.preferenceRepository.verboseLoggingFlow ), isdrAid, - seId, context.preferenceRepository.verboseLoggingFlow, context.preferenceRepository.ignoreTLSCertificateFlow, context.preferenceRepository.es10xMssFlow, @@ -62,8 +60,7 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha override fun tryOpenUsbEuiccChannel( ccidCtx: UsbCcidContext, - isdrAid: ByteArray, - seId: EuiccChannel.SecureElementId + isdrAid: ByteArray ): EuiccChannel? = try { EuiccChannelImpl( context.getString(R.string.channel_type_usb), @@ -73,7 +70,6 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha ccidCtx ), isdrAid, - seId, context.preferenceRepository.verboseLoggingFlow, context.preferenceRepository.ignoreTLSCertificateFlow, context.preferenceRepository.es10xMssFlow, diff --git a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt index 2d0493b..6b336cd 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt @@ -32,7 +32,7 @@ open class DefaultEuiccChannelManager( private val channelCache = mutableListOf() - private var usbChannels = mutableListOf() + private var usbChannel: EuiccChannel? = null private val lock = Mutex() @@ -51,20 +51,15 @@ open class DefaultEuiccChannelManager( protected open val uiccCards: Collection get() = (0.. EuiccChannel?): List { + private suspend inline fun tryOpenChannelFirstValidAid(openFn: (ByteArray) -> EuiccChannel?): EuiccChannel? { val isdrAidList = parseIsdrAidList(appContainer.preferenceRepository.isdrAidListFlow.first()) - var seId = 0 - return isdrAidList.mapNotNull { - Log.i( - TAG, - "Opening channel, trying ISDR AID ${it.encodeHex()}, this will be seId $seId" - ) + return isdrAidList.firstNotNullOfOrNull { + Log.i(TAG, "Opening channel, trying ISDR AID ${it.encodeHex()}") - openFn(it, EuiccChannel.SecureElementId.createFromInt(seId))?.let { channel -> + openFn(it)?.let { channel -> if (channel.valid) { - seId += 1 channel } else { channel.close() @@ -74,18 +69,19 @@ open class DefaultEuiccChannelManager( } } - private suspend fun tryOpenEuiccChannel( - port: UiccPortInfoCompat, - seId: EuiccChannel.SecureElementId = EuiccChannel.SecureElementId.DEFAULT - ): EuiccChannel? { + private suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat): EuiccChannel? { lock.withLock { if (port.card.physicalSlotIndex == EuiccChannelManager.USB_CHANNEL_ID) { - // We only compare seId because we assume we can only open 1 card from USB - return usbChannels.find { it.seId == seId } + return if (usbChannel != null && usbChannel!!.valid) { + usbChannel + } else { + usbChannel = null + null + } } val existing = - channelCache.find { it.slotId == port.card.physicalSlotIndex && it.portId == port.portIndex && it.seId == seId } + channelCache.find { it.slotId == port.card.physicalSlotIndex && it.portId == port.portIndex } if (existing != null) { if (existing.valid && port.logicalSlotIndex == existing.logicalSlotId) { return existing @@ -100,18 +96,12 @@ open class DefaultEuiccChannelManager( return null } - val channels = - tryOpenChannelWithKnownAids { isdrAid, seId -> - euiccChannelFactory.tryOpenEuiccChannel( - port, - isdrAid, - seId - ) - } + val channel = + tryOpenChannelFirstValidAid { euiccChannelFactory.tryOpenEuiccChannel(port, it) } - if (channels.isNotEmpty()) { - channelCache.addAll(channels) - return channels.find { it.seId == seId } + if (channel != null) { + channelCache.add(channel) + return channel } else { Log.i( TAG, @@ -122,13 +112,10 @@ open class DefaultEuiccChannelManager( } } - protected suspend fun findEuiccChannelByLogicalSlot( - logicalSlotId: Int, - seId: EuiccChannel.SecureElementId = EuiccChannel.SecureElementId.DEFAULT - ): EuiccChannel? = + protected suspend fun findEuiccChannelByLogicalSlot(logicalSlotId: Int): EuiccChannel? = withContext(Dispatchers.IO) { if (logicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { - return@withContext usbChannels.find { it.seId == seId } + return@withContext usbChannel } for (card in uiccCards) { @@ -144,7 +131,7 @@ open class DefaultEuiccChannelManager( private suspend fun findAllEuiccChannelsByPhysicalSlot(physicalSlotId: Int): List? { if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { - return usbChannels.ifEmpty { null } + return usbChannel?.let { listOf(it) } } for (card in uiccCards) { @@ -155,18 +142,14 @@ open class DefaultEuiccChannelManager( return null } - private suspend fun findEuiccChannelByPort( - physicalSlotId: Int, - portId: Int, - seId: EuiccChannel.SecureElementId = EuiccChannel.SecureElementId.DEFAULT - ): EuiccChannel? = + private suspend fun findEuiccChannelByPort(physicalSlotId: Int, portId: Int): EuiccChannel? = withContext(Dispatchers.IO) { if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { - return@withContext usbChannels.find { it.seId == seId } + return@withContext usbChannel } uiccCards.find { it.physicalSlotIndex == physicalSlotId }?.let { card -> - card.ports.find { it.portIndex == portId }?.let { tryOpenEuiccChannel(it, seId) } + card.ports.find { it.portIndex == portId }?.let { tryOpenEuiccChannel(it) } } } @@ -185,17 +168,15 @@ open class DefaultEuiccChannelManager( return@withContext listOf(0) } - findAllEuiccChannelsByPhysicalSlot(physicalSlotId)?.map { it.portId }?.toSet()?.toList() - ?: listOf() + findAllEuiccChannelsByPhysicalSlot(physicalSlotId)?.map { it.portId } ?: listOf() } override suspend fun withEuiccChannel( physicalSlotId: Int, portId: Int, - seId: EuiccChannel.SecureElementId, fn: suspend (EuiccChannel) -> R ): R { - val channel = findEuiccChannelByPort(physicalSlotId, portId, seId) + val channel = findEuiccChannelByPort(physicalSlotId, portId) ?: throw EuiccChannelManager.EuiccChannelNotFoundException() val wrapper = EuiccChannelWrapper(channel) try { @@ -209,10 +190,9 @@ open class DefaultEuiccChannelManager( override suspend fun withEuiccChannel( logicalSlotId: Int, - seId: EuiccChannel.SecureElementId, fn: suspend (EuiccChannel) -> R ): R { - val channel = findEuiccChannelByLogicalSlot(logicalSlotId, seId) + val channel = findEuiccChannelByLogicalSlot(logicalSlotId) ?: throw EuiccChannelManager.EuiccChannelNotFoundException() val wrapper = EuiccChannelWrapper(channel) try { @@ -226,8 +206,8 @@ open class DefaultEuiccChannelManager( override suspend fun waitForReconnect(physicalSlotId: Int, portId: Int, timeoutMillis: Long) { if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { - usbChannels.forEach { it.close() } - usbChannels.clear() + usbChannel?.close() + usbChannel = null } else { // 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 @@ -243,7 +223,7 @@ open class DefaultEuiccChannelManager( // tryOpenUsbEuiccChannel() will always try to reopen the channel, even if // a USB channel already exists tryOpenUsbEuiccChannel() - usbChannels.getOrNull(0)!! + usbChannel!! } else { // tryOpenEuiccChannel() will automatically dispose of invalid channels // and recreate when needed @@ -284,20 +264,6 @@ open class DefaultEuiccChannelManager( } }) - override fun flowEuiccSecureElements( - slotId: Int, - portId: Int - ): Flow = flow { - // Emit the "default" channel first - // TODO: This function below should really return a list, not just one SE - findEuiccChannelByPort(slotId, portId, seId = EuiccChannel.SecureElementId.DEFAULT)?.let { - emit(EuiccChannel.SecureElementId.DEFAULT) - - channelCache.filter { it.slotId == slotId && it.portId == portId && it.seId != EuiccChannel.SecureElementId.DEFAULT } - .forEach { emit(it.seId) } - } - } - override suspend fun tryOpenUsbEuiccChannel(): Pair = withContext(Dispatchers.IO) { usbManager.deviceList.values.forEach { device -> @@ -311,17 +277,15 @@ open class DefaultEuiccChannelManager( "Found CCID interface on ${device.deviceId}:${device.vendorId}, and has permission; trying to open channel" ) - val ccidCtx = - UsbCcidContext.createFromUsbDevice(context, device, iface) ?: return@forEach + val ccidCtx = UsbCcidContext.createFromUsbDevice(context, device, iface) ?: return@forEach try { - val channels = tryOpenChannelWithKnownAids { isdrAid, seId -> - euiccChannelFactory.tryOpenUsbEuiccChannel(ccidCtx, isdrAid, seId) + val channel = tryOpenChannelFirstValidAid { + euiccChannelFactory.tryOpenUsbEuiccChannel(ccidCtx, it) } - if (channels.isNotEmpty() && channels[0].valid) { + if (channel != null && channel.lpa.valid) { ccidCtx.allowDisconnect = true - usbChannels.clear() - usbChannels.addAll(channels) + usbChannel = channel return@withContext Pair(device, true) } } catch (e: Exception) { @@ -345,8 +309,8 @@ open class DefaultEuiccChannelManager( channel.close() } - usbChannels.forEach { it.close() } - usbChannels.clear() + usbChannel?.close() + usbChannel = null channelCache.clear() euiccChannelFactory.cleanup() } diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt index 4306855..b20932f 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt @@ -1,7 +1,5 @@ package im.angry.openeuicc.core -import android.os.Parcel -import android.os.Parcelable import im.angry.openeuicc.util.* import net.typeblog.lpac_jni.ApduInterface import net.typeblog.lpac_jni.LocalProfileAssistant @@ -15,59 +13,6 @@ interface EuiccChannel { val logicalSlotId: Int val portId: Int - /** - * A semi-obscure wrapper over the integer ID of a secure element on a card. - * - * Because the ID is arbitrary, this is intended to discourage the use of the - * integer value directly. Additionally, it prevents accidentally calling the - * wrong function in EuiccChannelManager with a ton of integer parameters. - */ - class SecureElementId private constructor(val id: Int) : Parcelable { - companion object { - val DEFAULT = SecureElementId(0) - - /** - * Create a SecureElementId from an integer ID. You should not call this directly - * unless you know what you're doing. - * - * This is currently only ever used in the download flow. - */ - fun createFromInt(id: Int): SecureElementId = - SecureElementId(id) - - @Suppress("unused") - @JvmField - val CREATOR = object : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): SecureElementId = - createFromInt(parcel.readInt()) - - override fun newArray(size: Int): Array = arrayOfNulls(size) - } - } - - override fun hashCode(): Int = - id.hashCode() - - override fun equals(other: Any?): Boolean = - if (other is SecureElementId) { - this.id == other.id - } else { - super.equals(other) - } - - override fun describeContents(): Int = id - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeInt(id) - } - } - - /** - * Some chips support multiple SEs on one chip. The seId here is intended - * to distinguish channels opened from these different SEs. - */ - val seId: SecureElementId - val lpa: LocalProfileAssistant val valid: Boolean diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelFactory.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelFactory.kt index a8051af..ba587a6 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelFactory.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelFactory.kt @@ -6,12 +6,11 @@ import im.angry.openeuicc.util.* // This class is here instead of inside DI because it contains a bit more logic than just // "dumb" dependency injection. interface EuiccChannelFactory { - suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat, isdrAid: ByteArray, seId: EuiccChannel.SecureElementId): EuiccChannel? + suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat, isdrAid: ByteArray): EuiccChannel? fun tryOpenUsbEuiccChannel( ccidCtx: UsbCcidContext, - isdrAid: ByteArray, - seId: EuiccChannel.SecureElementId + isdrAid: ByteArray ): EuiccChannel? /** diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt index 18751c9..eaec522 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt @@ -15,7 +15,6 @@ class EuiccChannelImpl( override val intrinsicChannelName: String?, override val apduInterface: ApduInterface, override val isdrAid: ByteArray, - override val seId: EuiccChannel.SecureElementId, verboseLoggingFlow: Flow, ignoreTLSCertificateFlow: Flow, es10xMssFlow: Flow, diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelManager.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelManager.kt index eb8e87c..17f3130 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelManager.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelManager.kt @@ -37,14 +37,6 @@ interface EuiccChannelManager { */ fun flowAllOpenEuiccPorts(): Flow> - /** - * Iterate over all the Secure Elements available on one eUICC. - * - * This is going to almost always return only 1 result, except in the case where - * a card has multiple SEs. - */ - fun flowEuiccSecureElements(slotId: Int, portId: Int): Flow - /** * Scan all possible USB devices for CCID readers that may contain eUICC cards. * If found, try to open it for access, and add it to the internal EuiccChannel cache @@ -89,16 +81,14 @@ interface EuiccChannelManager { suspend fun withEuiccChannel( physicalSlotId: Int, portId: Int, - seId: EuiccChannel.SecureElementId = EuiccChannel.SecureElementId.DEFAULT, fn: suspend (EuiccChannel) -> R ): R /** - * Same as withEuiccChannel(Int, Int, SecureElementId, (EuiccChannel) -> R) but instead uses logical slot ID + * Same as withEuiccChannel(Int, Int, (EuiccChannel) -> R) but instead uses logical slot ID */ suspend fun withEuiccChannel( logicalSlotId: Int, - seId: EuiccChannel.SecureElementId = EuiccChannel.SecureElementId.DEFAULT, fn: suspend (EuiccChannel) -> R ): R diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt index a36c1b6..361a943 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt @@ -26,8 +26,6 @@ class EuiccChannelWrapper(orig: EuiccChannel) : EuiccChannel { get() = channel.logicalSlotId override val portId: Int get() = channel.portId - override val seId: EuiccChannel.SecureElementId - get() = channel.seId private val lpaDelegate = lazy { LocalProfileAssistantWrapper(channel.lpa) } diff --git a/app-common/src/main/java/im/angry/openeuicc/di/CustomizableTextProvider.kt b/app-common/src/main/java/im/angry/openeuicc/di/CustomizableTextProvider.kt index 14d07b6..2c86273 100644 --- a/app-common/src/main/java/im/angry/openeuicc/di/CustomizableTextProvider.kt +++ b/app-common/src/main/java/im/angry/openeuicc/di/CustomizableTextProvider.kt @@ -1,7 +1,5 @@ package im.angry.openeuicc.di -import im.angry.openeuicc.core.EuiccChannel - interface CustomizableTextProvider { /** * Explanation string for when no eUICC is found on the device. @@ -15,13 +13,8 @@ interface CustomizableTextProvider { val profileSwitchingTimeoutMessage: String /** - * Format the name of a logical slot -- not for USB channels + * Format the name of a logical slot; internal only -- not intended for + * other channels such as USB. */ - fun formatNonUsbChannelName(logicalSlotId: Int): String - - /** - * Format the name of a logical slot with a SE ID, in case of multi-SE chips; currently - * this is used in the download flow to distinguish between them on the same chip. - */ - fun formatNonUsbChannelNameWithSeId(logicalSlotId: Int, seId: EuiccChannel.SecureElementId): String + fun formatInternalChannelName(logicalSlotId: Int): String } \ No newline at end of file diff --git a/app-common/src/main/java/im/angry/openeuicc/di/DefaultCustomizableTextProvider.kt b/app-common/src/main/java/im/angry/openeuicc/di/DefaultCustomizableTextProvider.kt index 516aab2..76227fd 100644 --- a/app-common/src/main/java/im/angry/openeuicc/di/DefaultCustomizableTextProvider.kt +++ b/app-common/src/main/java/im/angry/openeuicc/di/DefaultCustomizableTextProvider.kt @@ -2,22 +2,14 @@ package im.angry.openeuicc.di import android.content.Context import im.angry.openeuicc.common.R -import im.angry.openeuicc.core.EuiccChannel -open class DefaultCustomizableTextProvider(private val context: Context) : - CustomizableTextProvider { +open class DefaultCustomizableTextProvider(private val context: Context) : CustomizableTextProvider { override val noEuiccExplanation: String get() = context.getString(R.string.no_euicc) override val profileSwitchingTimeoutMessage: String get() = context.getString(R.string.profile_switch_timeout) - override fun formatNonUsbChannelName(logicalSlotId: Int): String = + override fun formatInternalChannelName(logicalSlotId: Int): String = context.getString(R.string.channel_name_format, logicalSlotId) - - override fun formatNonUsbChannelNameWithSeId( - logicalSlotId: Int, - seId: EuiccChannel.SecureElementId - ): String = - context.getString(R.string.channel_name_format_se, logicalSlotId, seId.id) } \ No newline at end of file diff --git a/app-common/src/main/java/im/angry/openeuicc/di/DefaultUiComponentFactory.kt b/app-common/src/main/java/im/angry/openeuicc/di/DefaultUiComponentFactory.kt index d268da8..52a501a 100644 --- a/app-common/src/main/java/im/angry/openeuicc/di/DefaultUiComponentFactory.kt +++ b/app-common/src/main/java/im/angry/openeuicc/di/DefaultUiComponentFactory.kt @@ -2,18 +2,13 @@ package im.angry.openeuicc.di import androidx.fragment.app.Fragment import androidx.preference.PreferenceFragmentCompat -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.ui.EuiccManagementFragment import im.angry.openeuicc.ui.NoEuiccPlaceholderFragment import im.angry.openeuicc.ui.SettingsFragment open class DefaultUiComponentFactory : UiComponentFactory { - override fun createEuiccManagementFragment( - slotId: Int, - portId: Int, - seId: EuiccChannel.SecureElementId - ): EuiccManagementFragment = - EuiccManagementFragment.newInstance(slotId, portId, seId) + override fun createEuiccManagementFragment(slotId: Int, portId: Int): EuiccManagementFragment = + EuiccManagementFragment.newInstance(slotId, portId) override fun createNoEuiccPlaceholderFragment(): Fragment = NoEuiccPlaceholderFragment() diff --git a/app-common/src/main/java/im/angry/openeuicc/di/UiComponentFactory.kt b/app-common/src/main/java/im/angry/openeuicc/di/UiComponentFactory.kt index 6a4d13f..2c3c72b 100644 --- a/app-common/src/main/java/im/angry/openeuicc/di/UiComponentFactory.kt +++ b/app-common/src/main/java/im/angry/openeuicc/di/UiComponentFactory.kt @@ -2,16 +2,10 @@ package im.angry.openeuicc.di import androidx.fragment.app.Fragment import androidx.preference.PreferenceFragmentCompat -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.ui.EuiccManagementFragment interface UiComponentFactory { - fun createEuiccManagementFragment( - slotId: Int, - portId: Int, - seId: EuiccChannel.SecureElementId - ): EuiccManagementFragment - + fun createEuiccManagementFragment(slotId: Int, portId: Int): EuiccManagementFragment fun createNoEuiccPlaceholderFragment(): Fragment fun createSettingsFragment(): Fragment } \ No newline at end of file diff --git a/app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt b/app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt index 556b346..4744321 100644 --- a/app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt +++ b/app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt @@ -12,7 +12,6 @@ import androidx.core.app.NotificationManagerCompat import androidx.lifecycle.LifecycleService import androidx.lifecycle.lifecycleScope import im.angry.openeuicc.common.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.core.EuiccChannelManager import im.angry.openeuicc.util.* import kotlinx.coroutines.Dispatchers @@ -381,7 +380,6 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { fun launchProfileDownloadTask( slotId: Int, portId: Int, - seId: EuiccChannel.SecureElementId, smdp: String, matchingId: String?, confirmationCode: String?, @@ -392,8 +390,8 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { getString(R.string.task_profile_download_failure), R.drawable.ic_task_sim_card_download ) { - euiccChannelManager.beginTrackedOperation(slotId, portId, seId) { - euiccChannelManager.withEuiccChannel(slotId, portId, seId) { channel -> + euiccChannelManager.beginTrackedOperation(slotId, portId) { + euiccChannelManager.withEuiccChannel(slotId, portId) { channel -> channel.lpa.downloadProfile( smdp, matchingId, @@ -415,7 +413,6 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { fun launchProfileRenameTask( slotId: Int, portId: Int, - seId: EuiccChannel.SecureElementId, iccid: String, name: String ): ForegroundTaskSubscriberFlow = @@ -424,7 +421,7 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { getString(R.string.task_profile_rename_failure), R.drawable.ic_task_rename ) { - euiccChannelManager.withEuiccChannel(slotId, portId, seId) { channel -> + euiccChannelManager.withEuiccChannel(slotId, portId) { channel -> channel.lpa.setNickname( iccid, name @@ -435,7 +432,6 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { fun launchProfileDeleteTask( slotId: Int, portId: Int, - seId: EuiccChannel.SecureElementId, iccid: String ): ForegroundTaskSubscriberFlow = launchForegroundTask( @@ -443,8 +439,8 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { getString(R.string.task_profile_delete_failure), R.drawable.ic_task_delete ) { - euiccChannelManager.beginTrackedOperation(slotId, portId, seId) { - euiccChannelManager.withEuiccChannel(slotId, portId, seId) { channel -> + euiccChannelManager.beginTrackedOperation(slotId, portId) { + euiccChannelManager.withEuiccChannel(slotId, portId) { channel -> channel.lpa.deleteProfile(iccid) } @@ -457,7 +453,6 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { fun launchProfileSwitchTask( slotId: Int, portId: Int, - seId: EuiccChannel.SecureElementId, iccid: String, enable: Boolean, // Enable or disable the profile indicated in iccid reconnectTimeoutMillis: Long = 0 // 0 = do not wait for reconnect @@ -467,9 +462,9 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { getString(R.string.task_profile_switch_failure), R.drawable.ic_task_switch ) { - euiccChannelManager.beginTrackedOperation(slotId, portId, seId) { + euiccChannelManager.beginTrackedOperation(slotId, portId) { val (response, refreshed) = - euiccChannelManager.withEuiccChannel(slotId, portId, seId) { channel -> + euiccChannelManager.withEuiccChannel(slotId, portId) { channel -> val refresh = preferenceRepository.refreshAfterSwitchFlow.first() val response = channel.lpa.switchProfile(iccid, enable, refresh) if (response || !refresh) { @@ -515,17 +510,13 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { } } - fun launchMemoryReset( - slotId: Int, - portId: Int, - seId: EuiccChannel.SecureElementId - ): ForegroundTaskSubscriberFlow = + fun launchMemoryReset(slotId: Int, portId: Int): ForegroundTaskSubscriberFlow = launchForegroundTask( getString(R.string.task_euicc_memory_reset), getString(R.string.task_euicc_memory_reset_failure), R.drawable.ic_euicc_memory_reset ) { - euiccChannelManager.beginTrackedOperation(slotId, portId, seId) { + euiccChannelManager.beginTrackedOperation(slotId, portId) { euiccChannelManager.withEuiccChannel(slotId, portId) { channel -> channel.lpa.euiccMemoryReset() } diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt index 930fa1e..248afaf 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt @@ -43,7 +43,6 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { private lateinit var infoList: RecyclerView private var logicalSlotId: Int = -1 - private var seId: EuiccChannel.SecureElementId = EuiccChannel.SecureElementId.DEFAULT data class Item( @StringRes @@ -68,17 +67,11 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { } logicalSlotId = intent.getIntExtra("logicalSlotId", 0) - seId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - intent.getParcelableExtra("seId", EuiccChannel.SecureElementId::class.java) - } else { - @Suppress("DEPRECATION") - intent.getParcelableExtra("seId")!! - } ?: EuiccChannel.SecureElementId.DEFAULT val channelTitle = if (logicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { getString(R.string.channel_type_usb) } else { - appContainer.customizableTextProvider.formatNonUsbChannelName(logicalSlotId) + appContainer.customizableTextProvider.formatInternalChannelName(logicalSlotId) } title = getString(R.string.euicc_info_activity_title, channelTitle) @@ -106,7 +99,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { lifecycleScope.launch { (infoList.adapter!! as EuiccInfoAdapter).euiccInfoItems = - euiccChannelManager.withEuiccChannel(logicalSlotId, fn = ::buildEuiccInfoItems) + euiccChannelManager.withEuiccChannel(logicalSlotId, ::buildEuiccInfoItems) swipeRefresh.isRefreshing = false } @@ -114,31 +107,12 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { private fun buildEuiccInfoItems(channel: EuiccChannel) = buildList { add(Item(R.string.euicc_info_access_mode, channel.type)) - add( - Item( - R.string.euicc_info_removable, - formatByBoolean(channel.port.card.isRemovable, YES_NO) - ) - ) - add( - Item( - R.string.euicc_info_eid, - channel.lpa.eID, - copiedToastResId = R.string.toast_eid_copied - ) - ) + add(Item(R.string.euicc_info_removable, formatByBoolean(channel.port.card.isRemovable, YES_NO))) + add(Item(R.string.euicc_info_eid, channel.lpa.eID, copiedToastResId = R.string.toast_eid_copied)) add(Item(R.string.euicc_info_isdr_aid, channel.isdrAid.encodeHex())) channel.tryParseEuiccVendorInfo()?.let { vendorInfo -> vendorInfo.skuName?.let { add(Item(R.string.euicc_info_sku, it)) } - vendorInfo.serialNumber?.let { - add( - Item( - R.string.euicc_info_sn, - it, - copiedToastResId = R.string.toast_sn_copied - ) - ) - } + vendorInfo.serialNumber?.let { add(Item(R.string.euicc_info_sn, it, copiedToastResId = R.string.toast_sn_copied)) } vendorInfo.firmwareVersion?.let { add(Item(R.string.euicc_info_fw_ver, it)) } vendorInfo.bootloaderVersion?.let { add(Item(R.string.euicc_info_bl_ver, it)) } } diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt index 1cb898e..016e96f 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt @@ -31,7 +31,6 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.google.android.material.floatingactionbutton.FloatingActionButton import net.typeblog.lpac_jni.LocalProfileInfo import im.angry.openeuicc.common.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.service.EuiccChannelManagerService import im.angry.openeuicc.service.EuiccChannelManagerService.Companion.waitDone import im.angry.openeuicc.ui.wizard.DownloadWizardActivity @@ -50,12 +49,8 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, companion object { const val TAG = "EuiccManagementFragment" - fun newInstance( - slotId: Int, - portId: Int, - seId: EuiccChannel.SecureElementId - ): EuiccManagementFragment = - newInstanceEuicc(EuiccManagementFragment::class.java, slotId, portId, seId) + fun newInstance(slotId: Int, portId: Int): EuiccManagementFragment = + newInstanceEuicc(EuiccManagementFragment::class.java, slotId, portId) } private lateinit var swipeRefresh: SwipeRefreshLayout @@ -153,7 +148,6 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, R.id.show_notifications -> { Intent(requireContext(), NotificationsActivity::class.java).apply { putExtra("logicalSlotId", logicalSlotId) - putExtra("seId", seId) startActivity(this) } true @@ -162,14 +156,13 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, R.id.euicc_info -> { Intent(requireContext(), EuiccInfoActivity::class.java).apply { putExtra("logicalSlotId", logicalSlotId) - putExtra("seId", seId) startActivity(this) } true } R.id.euicc_memory_reset -> { - EuiccMemoryResetFragment.newInstance(slotId, portId, seId, eid) + EuiccMemoryResetFragment.newInstance(slotId, portId, eid) .show(childFragmentManager, EuiccMemoryResetFragment.TAG) true } @@ -248,7 +241,6 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, val err = euiccChannelManagerService.launchProfileSwitchTask( slotId, portId, - seId, iccid, enable, reconnectTimeoutMillis = 30 * 1000 @@ -302,10 +294,7 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, } } - protected open fun populatePopupWithProfileActions( - popup: PopupMenu, - profile: LocalProfileInfo - ) { + protected open fun populatePopupWithProfileActions(popup: PopupMenu, profile: LocalProfileInfo) { popup.inflate(R.menu.profile_options) if (profile.isEnabled) { popup.menu.findItem(R.id.enable).isVisible = false @@ -332,7 +321,7 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, } } - inner class FooterViewHolder : ViewHolder(FrameLayout(requireContext())) { + inner class FooterViewHolder: ViewHolder(FrameLayout(requireContext())) { init { itemView.layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, @@ -434,36 +423,20 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, enableOrDisableProfile(profile.iccid, true) true } - R.id.disable -> { enableOrDisableProfile(profile.iccid, false) true } - R.id.rename -> { - ProfileRenameFragment.newInstance( - slotId, - portId, - seId, - profile.iccid, - profile.displayName - ) + ProfileRenameFragment.newInstance(slotId, portId, profile.iccid, profile.displayName) .show(childFragmentManager, ProfileRenameFragment.TAG) true } - R.id.delete -> { - ProfileDeleteFragment.newInstance( - slotId, - portId, - seId, - profile.iccid, - profile.displayName - ) + ProfileDeleteFragment.newInstance(slotId, portId, profile.iccid, profile.displayName) .show(childFragmentManager, ProfileDeleteFragment.TAG) true } - else -> false } } @@ -475,11 +448,9 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = when (ViewHolder.Type.fromInt(viewType)) { ViewHolder.Type.PROFILE -> { - val view = LayoutInflater.from(parent.context) - .inflate(R.layout.euicc_profile, parent, false) + val view = LayoutInflater.from(parent.context).inflate(R.layout.euicc_profile, parent, false) ProfileViewHolder(view) } - ViewHolder.Type.FOOTER -> { FooterViewHolder() } @@ -490,11 +461,9 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, position < profiles.size -> { ViewHolder.Type.PROFILE.value } - position >= profiles.size && position < profiles.size + footerViews.size -> { ViewHolder.Type.FOOTER.value } - else -> -1 } @@ -504,7 +473,6 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, holder.setProfile(profiles[position]) holder.setProfileSequenceNumber(position + 1) } - is FooterViewHolder -> { holder.attach(footerViews[position - profiles.size]) } diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccMemoryResetFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccMemoryResetFragment.kt index b123c2e..086a849 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccMemoryResetFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccMemoryResetFragment.kt @@ -11,7 +11,6 @@ import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import im.angry.openeuicc.common.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.service.EuiccChannelManagerService.Companion.waitDone import im.angry.openeuicc.util.EuiccChannelFragmentMarker import im.angry.openeuicc.util.EuiccProfilesChangedListener @@ -20,7 +19,6 @@ import im.angry.openeuicc.util.euiccChannelManagerService import im.angry.openeuicc.util.newInstanceEuicc import im.angry.openeuicc.util.notifyEuiccProfilesChanged import im.angry.openeuicc.util.portId -import im.angry.openeuicc.util.seId import im.angry.openeuicc.util.slotId import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch @@ -31,8 +29,8 @@ class EuiccMemoryResetFragment : DialogFragment(), EuiccChannelFragmentMarker { private const val FIELD_EID = "eid" - fun newInstance(slotId: Int, portId: Int, seId: EuiccChannel.SecureElementId, eid: String) = - newInstanceEuicc(EuiccMemoryResetFragment::class.java, slotId, portId, seId) { + fun newInstance(slotId: Int, portId: Int, eid: String) = + newInstanceEuicc(EuiccMemoryResetFragment::class.java, slotId, portId) { putString(FIELD_EID, eid) } } @@ -105,7 +103,7 @@ class EuiccMemoryResetFragment : DialogFragment(), EuiccChannelFragmentMarker { ensureEuiccChannelManager() euiccChannelManagerService.waitForForegroundTask() - euiccChannelManagerService.launchMemoryReset(slotId, portId, seId) + euiccChannelManagerService.launchMemoryReset(slotId, portId) .onStart { parentFragment?.notifyEuiccProfilesChanged() diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/MainActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/MainActivity.kt index 0d96448..b42f4cf 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/MainActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/MainActivity.kt @@ -112,12 +112,10 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { startActivity(Intent(this, SettingsActivity::class.java)) true } - R.id.reload -> { refresh() true } - else -> super.onOptionsItemSelected(item) } @@ -156,27 +154,21 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { euiccChannelManager.flowInternalEuiccPorts().onEach { (slotId, portId) -> Log.d(TAG, "slot $slotId port $portId") - euiccChannelManager.flowEuiccSecureElements(slotId, portId).onEach { seId -> - euiccChannelManager.withEuiccChannel(slotId, portId, seId) { channel -> - if (preferenceRepository.verboseLoggingFlow.first()) { - Log.d(TAG, channel.lpa.eID) - } - // Request the system to refresh the list of profiles every time we start - // Note that this is currently supposed to be no-op when unprivileged, - // but it could change in the future - euiccChannelManager.notifyEuiccProfilesChanged(channel.logicalSlotId) - - val channelName = - appContainer.customizableTextProvider.formatNonUsbChannelName(channel.logicalSlotId) - newPages.add(Page(channel.logicalSlotId, channelName) { - appContainer.uiComponentFactory.createEuiccManagementFragment( - slotId, - portId, - seId - ) - }) + euiccChannelManager.withEuiccChannel(slotId, portId) { channel -> + if (preferenceRepository.verboseLoggingFlow.first()) { + Log.d(TAG, channel.lpa.eID) } - }.collect() + // Request the system to refresh the list of profiles every time we start + // Note that this is currently supposed to be no-op when unprivileged, + // but it could change in the future + euiccChannelManager.notifyEuiccProfilesChanged(channel.logicalSlotId) + + val channelName = + appContainer.customizableTextProvider.formatInternalChannelName(channel.logicalSlotId) + newPages.add(Page(channel.logicalSlotId, channelName) { + appContainer.uiComponentFactory.createEuiccManagementFragment(slotId, portId) + }) + } }.collect() // If USB readers exist, add them at the very last diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt index bd808bb..07d5f13 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt @@ -1,7 +1,6 @@ package im.angry.openeuicc.ui import android.annotation.SuppressLint -import android.os.Build import android.os.Bundle import android.text.Html import android.view.ContextMenu @@ -21,7 +20,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import im.angry.openeuicc.common.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.core.EuiccChannelManager import im.angry.openeuicc.util.* import kotlinx.coroutines.Dispatchers @@ -29,13 +27,12 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import net.typeblog.lpac_jni.LocalProfileNotification -class NotificationsActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { +class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker { private lateinit var swipeRefresh: SwipeRefreshLayout private lateinit var notificationList: RecyclerView private val notificationAdapter = NotificationAdapter() private var logicalSlotId = -1 - private var seId = EuiccChannel.SecureElementId.DEFAULT override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() @@ -54,29 +51,18 @@ class NotificationsActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker override fun onInit() { notificationList.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) - notificationList.addItemDecoration( - DividerItemDecoration( - this, - LinearLayoutManager.VERTICAL - ) - ) + notificationList.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL)) notificationList.adapter = notificationAdapter registerForContextMenu(notificationList) logicalSlotId = intent.getIntExtra("logicalSlotId", 0) - seId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - intent.getParcelableExtra("seId", EuiccChannel.SecureElementId::class.java) - } else { - @Suppress("DEPRECATION") - intent.getParcelableExtra("seId")!! - } ?: EuiccChannel.SecureElementId.DEFAULT // This is slightly different from the MainActivity logic // due to the length (we don't want to display the full USB product name) val channelTitle = if (logicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { getString(R.string.channel_type_usb) } else { - appContainer.customizableTextProvider.formatNonUsbChannelName(logicalSlotId) + appContainer.customizableTextProvider.formatInternalChannelName(logicalSlotId) } title = getString(R.string.profile_notifications_detailed_format, channelTitle) @@ -100,7 +86,6 @@ class NotificationsActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker finish() true } - R.id.help -> { AlertDialog.Builder(this, R.style.AlertDialogTheme).apply { setMessage(R.string.profile_notifications_help) @@ -111,7 +96,6 @@ class NotificationsActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker } true } - else -> super.onOptionsItemSelected(item) } @@ -130,20 +114,20 @@ class NotificationsActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker } private fun refresh() { - launchTask { - notificationAdapter.notifications = - euiccChannelManager.withEuiccChannel(logicalSlotId) { channel -> - val nameMap = buildMap { - for (profile in channel.lpa.profiles) { - put(profile.iccid, profile.displayName) - } - } + launchTask { + notificationAdapter.notifications = + euiccChannelManager.withEuiccChannel(logicalSlotId) { channel -> + val nameMap = buildMap { + for (profile in channel.lpa.profiles) { + put(profile.iccid, profile.displayName) + } + } - channel.lpa.notifications.map { - LocalProfileNotificationWrapper(it, nameMap[it.iccid] ?: "???") - } - } - } + channel.lpa.notifications.map { + LocalProfileNotificationWrapper(it, nameMap[it.iccid] ?: "???") + } + } + } } data class LocalProfileNotificationWrapper( @@ -152,7 +136,7 @@ class NotificationsActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker ) @SuppressLint("ClickableViewAccessibility") - inner class NotificationViewHolder(private val root: View) : + inner class NotificationViewHolder(private val root: View): RecyclerView.ViewHolder(root), View.OnCreateContextMenuListener, OnMenuItemClickListener { private val address: TextView = root.requireViewById(R.id.notification_address) private val sequenceNumber: TextView = @@ -186,8 +170,7 @@ class NotificationsActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker LocalProfileNotification.Operation.Delete -> R.string.profile_notification_operation_delete LocalProfileNotification.Operation.Enable -> R.string.profile_notification_operation_enable LocalProfileNotification.Operation.Disable -> R.string.profile_notification_operation_disable - } - ) + }) fun updateNotification(value: LocalProfileNotificationWrapper) { notification = value @@ -198,13 +181,10 @@ class NotificationsActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker value.inner.seqNumber ) profileName.text = Html.fromHtml( - root.context.getString( - R.string.profile_notification_name_format, + root.context.getString(R.string.profile_notification_name_format, operationToLocalizedText(value.inner.profileManagementOperation), - value.profileName, value.inner.iccid - ), - Html.FROM_HTML_MODE_COMPACT - ) + value.profileName, value.inner.iccid), + Html.FROM_HTML_MODE_COMPACT) } override fun onCreateContextMenu( @@ -233,7 +213,6 @@ class NotificationsActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker } true } - R.id.notification_delete -> { launchTask { withContext(Dispatchers.IO) { @@ -246,12 +225,11 @@ class NotificationsActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker } true } - else -> false } } - inner class NotificationAdapter : RecyclerView.Adapter() { + inner class NotificationAdapter: RecyclerView.Adapter() { var notifications: List = listOf() @SuppressLint("NotifyDataSetChanged") set(value) { diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDeleteFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDeleteFragment.kt index 15424aa..38d1bc6 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDeleteFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDeleteFragment.kt @@ -9,7 +9,6 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import im.angry.openeuicc.common.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.service.EuiccChannelManagerService.Companion.waitDone import im.angry.openeuicc.util.* import kotlinx.coroutines.flow.onStart @@ -21,8 +20,8 @@ class ProfileDeleteFragment : DialogFragment(), EuiccChannelFragmentMarker { private const val FIELD_ICCID = "iccid" private const val FIELD_NAME = "name" - fun newInstance(slotId: Int, portId: Int, seId: EuiccChannel.SecureElementId, iccid: String, name: String) = - newInstanceEuicc(ProfileDeleteFragment::class.java, slotId, portId, seId) { + fun newInstance(slotId: Int, portId: Int, iccid: String, name: String) = + newInstanceEuicc(ProfileDeleteFragment::class.java, slotId, portId) { putString(FIELD_ICCID, iccid) putString(FIELD_NAME, name) } @@ -89,7 +88,7 @@ class ProfileDeleteFragment : DialogFragment(), EuiccChannelFragmentMarker { requireParentFragment().lifecycleScope.launch { ensureEuiccChannelManager() euiccChannelManagerService.waitForForegroundTask() - euiccChannelManagerService.launchProfileDeleteTask(slotId, portId, seId, iccid) + euiccChannelManagerService.launchProfileDeleteTask(slotId, portId, iccid) .onStart { parentFragment?.notifyEuiccProfilesChanged() runCatching(::dismiss) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileRenameFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileRenameFragment.kt index 3f23286..281e625 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileRenameFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileRenameFragment.kt @@ -12,7 +12,6 @@ import androidx.appcompat.widget.Toolbar import androidx.lifecycle.lifecycleScope import com.google.android.material.textfield.TextInputLayout import im.angry.openeuicc.common.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.service.EuiccChannelManagerService.Companion.waitDone import im.angry.openeuicc.util.* import kotlinx.coroutines.launch @@ -25,8 +24,8 @@ class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragment const val TAG = "ProfileRenameFragment" - fun newInstance(slotId: Int, portId: Int, seId: EuiccChannel.SecureElementId, iccid: String, currentName: String) = - newInstanceEuicc(ProfileRenameFragment::class.java, slotId, portId, seId) { + fun newInstance(slotId: Int, portId: Int, iccid: String, currentName: String) = + newInstanceEuicc(ProfileRenameFragment::class.java, slotId, portId) { putString(FIELD_ICCID, iccid) putString(FIELD_CURRENT_NAME, currentName) } @@ -106,7 +105,7 @@ class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragment ensureEuiccChannelManager() euiccChannelManagerService.waitForForegroundTask() val response = euiccChannelManagerService - .launchProfileRenameTask(slotId, portId, seId, iccid, newName).waitDone() + .launchProfileRenameTask(slotId, portId, iccid, newName).waitDone() when (response) { is LocalProfileAssistant.ProfileNameTooLongException -> { diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/UsbCcidReaderFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/UsbCcidReaderFragment.kt index a14e47d..7a52ca0 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/UsbCcidReaderFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/UsbCcidReaderFragment.kt @@ -20,7 +20,6 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.commit import androidx.lifecycle.lifecycleScope import im.angry.openeuicc.common.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.core.EuiccChannelManager import im.angry.openeuicc.util.* import kotlinx.coroutines.Dispatchers @@ -157,9 +156,7 @@ class UsbCcidReaderFragment : Fragment(), OpenEuiccContextMarker { R.id.child_container, appContainer.uiComponentFactory.createEuiccManagementFragment( slotId = EuiccChannelManager.USB_CHANNEL_ID, - portId = 0, - // TODO: What if a USB card has multiple SEs? - seId = EuiccChannel.SecureElementId.DEFAULT + portId = 0 ) ) } diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardActivity.kt index b1d7e15..6574645 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardActivity.kt @@ -17,7 +17,6 @@ import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import im.angry.openeuicc.common.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.core.EuiccChannelManager import im.angry.openeuicc.ui.BaseEuiccAccessActivity import im.angry.openeuicc.util.* @@ -25,10 +24,10 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import net.typeblog.lpac_jni.LocalProfileAssistant -class DownloadWizardActivity : BaseEuiccAccessActivity() { +class DownloadWizardActivity: BaseEuiccAccessActivity() { data class DownloadWizardState( var currentStepFragmentClassName: String?, - var selectedSyntheticSlotId: Int, + var selectedLogicalSlot: Int, var smdp: String, var matchingId: String?, var confirmationCode: String?, @@ -67,7 +66,7 @@ class DownloadWizardActivity : BaseEuiccAccessActivity() { state = DownloadWizardState( currentStepFragmentClassName = null, - selectedSyntheticSlotId = intent.getIntExtra("selectedLogicalSlot", 0), + selectedLogicalSlot = intent.getIntExtra("selectedLogicalSlot", 0), smdp = "", matchingId = null, confirmationCode = null, @@ -152,7 +151,7 @@ class DownloadWizardActivity : BaseEuiccAccessActivity() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString("currentStepFragmentClassName", state.currentStepFragmentClassName) - outState.putInt("selectedLogicalSlot", state.selectedSyntheticSlotId) + outState.putInt("selectedLogicalSlot", state.selectedLogicalSlot) outState.putString("smdp", state.smdp) outState.putString("matchingId", state.matchingId) outState.putString("confirmationCode", state.confirmationCode) @@ -168,20 +167,16 @@ class DownloadWizardActivity : BaseEuiccAccessActivity() { "currentStepFragmentClassName", state.currentStepFragmentClassName ) - state.selectedSyntheticSlotId = - savedInstanceState.getInt("selectedSyntheticSlotId", state.selectedSyntheticSlotId) + state.selectedLogicalSlot = + savedInstanceState.getInt("selectedLogicalSlot", state.selectedLogicalSlot) state.smdp = savedInstanceState.getString("smdp", state.smdp) state.matchingId = savedInstanceState.getString("matchingId", state.matchingId) state.imei = savedInstanceState.getString("imei", state.imei) state.downloadStarted = savedInstanceState.getBoolean("downloadStarted", state.downloadStarted) state.downloadTaskID = savedInstanceState.getLong("downloadTaskID", state.downloadTaskID) - state.confirmationCode = - savedInstanceState.getString("confirmationCode", state.confirmationCode) - state.confirmationCodeRequired = savedInstanceState.getBoolean( - "confirmationCodeRequired", - state.confirmationCodeRequired - ) + state.confirmationCode = savedInstanceState.getString("confirmationCode", state.confirmationCode) + state.confirmationCodeRequired = savedInstanceState.getBoolean("confirmationCodeRequired", state.confirmationCodeRequired) } private fun onPrevPressed() { @@ -205,13 +200,10 @@ class DownloadWizardActivity : BaseEuiccAccessActivity() { progressBar.isIndeterminate = true lifecycleScope.launch(Dispatchers.Main) { - if (state.selectedSyntheticSlotId >= 0) { + if (state.selectedLogicalSlot >= 0) { try { - val (slotId, seId) = DownloadWizardSlotSelectFragment.decodeSyntheticSlotId( - state.selectedSyntheticSlotId - ) // This is run on IO by default - euiccChannelManager.withEuiccChannel(slotId, seId) { channel -> + euiccChannelManager.withEuiccChannel(state.selectedLogicalSlot) { channel -> // Be _very_ sure that the channel we got is valid if (!channel.valid) throw EuiccChannelManager.EuiccChannelNotFoundException() } diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardProgressFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardProgressFragment.kt index f8cb781..0048190 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardProgressFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardProgressFragment.kt @@ -153,12 +153,7 @@ class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStep } else { euiccChannelManagerService.waitForForegroundTask() - val (logicalSlotId, seId) = DownloadWizardSlotSelectFragment.decodeSyntheticSlotId(state.selectedSyntheticSlotId) - - val (slotId, portId) = euiccChannelManager.withEuiccChannel( - logicalSlotId, - seId - ) { channel -> + val (slotId, portId) = euiccChannelManager.withEuiccChannel(state.selectedLogicalSlot) { channel -> Pair(channel.slotId, channel.portId) } @@ -168,7 +163,6 @@ class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStep val ret = euiccChannelManagerService.launchProfileDownloadTask( slotId, portId, - seId, state.smdp, state.matchingId, state.confirmationCode, diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardSlotSelectFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardSlotSelectFragment.kt index fef90ba..8097058 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardSlotSelectFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardSlotSelectFragment.kt @@ -14,11 +14,8 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.ViewHolder import im.angry.openeuicc.common.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.core.EuiccChannelManager import im.angry.openeuicc.util.* -import kotlinx.coroutines.flow.asFlow -import kotlinx.coroutines.flow.flatMapConcat import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList import kotlinx.coroutines.launch @@ -27,28 +24,19 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt companion object { const val LOW_NVRAM_THRESHOLD = 30 * 1024 // < 30 KiB, alert about potential download failure - - fun decodeSyntheticSlotId(id: Int): Pair = - Pair(id shr 16, EuiccChannel.SecureElementId.createFromInt(id and 0xFF)) } private data class SlotInfo( val logicalSlotId: Int, val isRemovable: Boolean, val hasMultiplePorts: Boolean, - val hasMultipleSEs: Boolean, val portId: Int, - val seId: EuiccChannel.SecureElementId, val eID: String, val freeSpace: Int, val imei: String, val enabledProfileName: String?, val intrinsicChannelName: String?, - ) { - // A synthetic slot ID used to uniquely identify this slot + SE chip in the download process - // We assume we don't have anywhere near 2^16 ports... - val syntheticSlotId: Int = (logicalSlotId shl 16) + seId.id - } + ) private var loaded = false @@ -97,12 +85,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt recyclerView.adapter = adapter recyclerView.layoutManager = LinearLayoutManager(view.context, LinearLayoutManager.VERTICAL, false) - recyclerView.addItemDecoration( - DividerItemDecoration( - requireContext(), - LinearLayoutManager.VERTICAL - ) - ) + recyclerView.addItemDecoration(DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)) return view } @@ -114,43 +97,37 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt } @SuppressLint("NotifyDataSetChanged", "MissingPermission") - @OptIn(kotlinx.coroutines.FlowPreview::class) private suspend fun init() { ensureEuiccChannelManager() showProgressBar(-1) - val slots = euiccChannelManager.flowAllOpenEuiccPorts().flatMapConcat { (slotId, portId) -> - val ses = euiccChannelManager.flowEuiccSecureElements(slotId, portId).toList() - ses.asFlow().map { seId -> - euiccChannelManager.withEuiccChannel(slotId, portId, seId) { channel -> - SlotInfo( - channel.logicalSlotId, - channel.port.card.isRemovable, - channel.port.card.ports.size > 1, - ses.size > 1, - channel.portId, - channel.seId, - channel.lpa.eID, - channel.lpa.euiccInfo2?.freeNvram ?: 0, - try { - telephonyManager.getImei(channel.logicalSlotId) ?: "" - } catch (e: Exception) { - "" - }, - channel.lpa.profiles.enabled?.displayName, - channel.intrinsicChannelName, - ) - } + val slots = euiccChannelManager.flowAllOpenEuiccPorts().map { (slotId, portId) -> + euiccChannelManager.withEuiccChannel(slotId, portId) { channel -> + SlotInfo( + channel.logicalSlotId, + channel.port.card.isRemovable, + channel.port.card.ports.size > 1, + channel.portId, + channel.lpa.eID, + channel.lpa.euiccInfo2?.freeNvram ?: 0, + try { + telephonyManager.getImei(channel.logicalSlotId) ?: "" + } catch (e: Exception) { + "" + }, + channel.lpa.profiles.enabled?.displayName, + channel.intrinsicChannelName, + ) } - }.toList().sortedBy { it.syntheticSlotId } + }.toList().sortedBy { it.logicalSlotId } adapter.slots = slots // Ensure we always have a selected slot by default - val selectedIdx = slots.indexOfFirst { it.syntheticSlotId == state.selectedSyntheticSlotId } + val selectedIdx = slots.indexOfFirst { it.logicalSlotId == state.selectedLogicalSlot } adapter.currentSelectedIdx = if (selectedIdx > 0) { selectedIdx } else { if (slots.isNotEmpty()) { - state.selectedSyntheticSlotId = slots[0].syntheticSlotId + state.selectedLogicalSlot = slots[0].logicalSlotId } 0 } @@ -190,8 +167,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt adapter.notifyItemChanged(lastIdx) adapter.notifyItemChanged(curIdx) // Selected index isn't logical slot ID directly, needs a conversion - state.selectedSyntheticSlotId = - adapter.slots[adapter.currentSelectedIdx].syntheticSlotId + state.selectedLogicalSlot = adapter.slots[adapter.currentSelectedIdx].logicalSlotId state.imei = adapter.slots[adapter.currentSelectedIdx].imei } @@ -211,17 +187,11 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt title.text = if (item.logicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { item.intrinsicChannelName ?: root.context.getString(R.string.channel_type_usb) - } else if (item.hasMultipleSEs) { - appContainer.customizableTextProvider.formatNonUsbChannelNameWithSeId( - item.logicalSlotId, - item.seId - ) } else { - appContainer.customizableTextProvider.formatNonUsbChannelName(item.logicalSlotId) + appContainer.customizableTextProvider.formatInternalChannelName(item.logicalSlotId) } eID.text = item.eID - activeProfile.text = item.enabledProfileName - ?: root.context.getString(R.string.profile_no_enabled_profile) + activeProfile.text = item.enabledProfileName ?: root.context.getString(R.string.profile_no_enabled_profile) freeSpace.text = formatFreeSpace(item.freeSpace) checkBox.isChecked = adapter.currentSelectedIdx == idx } @@ -235,8 +205,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt get() = slots[currentSelectedIdx] override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SlotItemHolder { - val root = LayoutInflater.from(parent.context) - .inflate(R.layout.download_slot_item, parent, false) + val root = LayoutInflater.from(parent.context).inflate(R.layout.download_slot_item, parent, false) return SlotItemHolder(root) } diff --git a/app-common/src/main/java/im/angry/openeuicc/util/EuiccChannelFragmentUtils.kt b/app-common/src/main/java/im/angry/openeuicc/util/EuiccChannelFragmentUtils.kt index d2d8c4b..b44bef8 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/EuiccChannelFragmentUtils.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/EuiccChannelFragmentUtils.kt @@ -1,6 +1,5 @@ package im.angry.openeuicc.util -import android.os.Build import android.os.Bundle import androidx.fragment.app.Fragment import im.angry.openeuicc.core.EuiccChannel @@ -10,7 +9,6 @@ import im.angry.openeuicc.ui.BaseEuiccAccessActivity private const val FIELD_SLOT_ID = "slotId" private const val FIELD_PORT_ID = "portId" -private const val FIELD_SE_ID = "seId" interface EuiccChannelFragmentMarker : OpenEuiccContextMarker @@ -19,19 +17,12 @@ private typealias BundleSetter = Bundle.() -> Unit // We must use extension functions because there is no way to add bounds to the type of "self" // in the definition of an interface, so the only way is to limit where the extension functions // can be applied. -fun newInstanceEuicc( - clazz: Class, - slotId: Int, - portId: Int, - seId: EuiccChannel.SecureElementId, - addArguments: BundleSetter = {} -): T +fun newInstanceEuicc(clazz: Class, slotId: Int, portId: Int, addArguments: BundleSetter = {}): T where T : Fragment, T : EuiccChannelFragmentMarker = clazz.getDeclaredConstructor().newInstance().apply { arguments = Bundle() arguments!!.putInt(FIELD_SLOT_ID, slotId) arguments!!.putInt(FIELD_PORT_ID, portId) - arguments!!.putParcelable(FIELD_SE_ID, seId) arguments!!.addArguments() } @@ -44,18 +35,6 @@ val T.slotId: Int val T.portId: Int where T : Fragment, T : EuiccChannelFragmentMarker get() = requireArguments().getInt(FIELD_PORT_ID) -val T.seId: EuiccChannel.SecureElementId - where T : Fragment, T : EuiccChannelFragmentMarker - get() = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - requireArguments().getParcelable( - FIELD_SE_ID, - EuiccChannel.SecureElementId::class.java - )!! - } else { - @Suppress("DEPRECATION") - requireArguments().getParcelable(FIELD_SE_ID)!! - } val T.isUsb: Boolean where T : Fragment, T : EuiccChannelFragmentMarker get() = slotId == EuiccChannelManager.USB_CHANNEL_ID @@ -75,12 +54,7 @@ val T.euiccChannelManagerService: EuiccChannelManagerService suspend fun T.withEuiccChannel(fn: suspend (EuiccChannel) -> R): R where T : Fragment, T : EuiccChannelFragmentMarker { ensureEuiccChannelManager() - return euiccChannelManager.withEuiccChannel( - slotId, - portId, - seId, - fn - ) + return euiccChannelManager.withEuiccChannel(slotId, portId, fn) } suspend fun T.ensureEuiccChannelManager() where T : Fragment, T : OpenEuiccContextMarker = diff --git a/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt b/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt index c4e1ba1..9f95412 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt @@ -79,10 +79,9 @@ fun LocalProfileAssistant.disableActiveProfileKeepIccId(refresh: Boolean): Strin suspend inline fun EuiccChannelManager.beginTrackedOperation( slotId: Int, portId: Int, - seId: EuiccChannel.SecureElementId, op: () -> Boolean ) { - val latestSeq = withEuiccChannel(slotId, portId, seId) { channel -> + val latestSeq = withEuiccChannel(slotId, portId) { channel -> channel.lpa.notifications.firstOrNull()?.seqNumber ?: 0 } @@ -92,7 +91,7 @@ suspend inline fun EuiccChannelManager.beginTrackedOperation( try { // Note that the exact instance of "channel" might have changed here if reconnected; // this is why we need to use two distinct calls to withEuiccChannel() - withEuiccChannel(slotId, portId, seId) { channel -> + withEuiccChannel(slotId, portId) { channel -> channel.lpa.notifications.filter { it.seqNumber > latestSeq }.forEach { Log.d(TAG, "Handling notification $it") channel.lpa.handleNotification(it.seqNumber) diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index 36a046c..39a762f 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -9,7 +9,6 @@ Unknown Logical Slot %d - Logical Slot %d, SE %d USB OpenMobile API (OMAPI) diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedCustomizableTextProvider.kt b/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedCustomizableTextProvider.kt index 6310d65..929ce84 100644 --- a/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedCustomizableTextProvider.kt +++ b/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedCustomizableTextProvider.kt @@ -2,16 +2,9 @@ package im.angry.openeuicc.di import android.content.Context import im.angry.easyeuicc.R -import im.angry.openeuicc.core.EuiccChannel class UnprivilegedCustomizableTextProvider(private val context: Context) : DefaultCustomizableTextProvider(context) { - override fun formatNonUsbChannelName(logicalSlotId: Int): String = + override fun formatInternalChannelName(logicalSlotId: Int): String = context.getString(R.string.channel_name_format_unpriv, logicalSlotId) - - override fun formatNonUsbChannelNameWithSeId( - logicalSlotId: Int, - seId: EuiccChannel.SecureElementId - ): String = - context.getString(R.string.channel_name_format_unpriv_se, logicalSlotId, seId.id) } \ No newline at end of file diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedUiComponentFactory.kt b/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedUiComponentFactory.kt index c20a3b9..3eb09c0 100644 --- a/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedUiComponentFactory.kt +++ b/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedUiComponentFactory.kt @@ -1,7 +1,6 @@ package im.angry.openeuicc.di import androidx.fragment.app.Fragment -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.ui.EuiccManagementFragment import im.angry.openeuicc.ui.QuickCompatibilityFragment import im.angry.openeuicc.ui.UnprivilegedEuiccManagementFragment @@ -9,12 +8,8 @@ import im.angry.openeuicc.ui.UnprivilegedNoEuiccPlaceholderFragment import im.angry.openeuicc.ui.UnprivilegedSettingsFragment open class UnprivilegedUiComponentFactory : DefaultUiComponentFactory() { - override fun createEuiccManagementFragment( - slotId: Int, - portId: Int, - seId: EuiccChannel.SecureElementId - ): EuiccManagementFragment = - UnprivilegedEuiccManagementFragment.newInstance(slotId, portId, seId) + override fun createEuiccManagementFragment(slotId: Int, portId: Int): EuiccManagementFragment = + UnprivilegedEuiccManagementFragment.newInstance(slotId, portId) override fun createNoEuiccPlaceholderFragment(): Fragment = UnprivilegedNoEuiccPlaceholderFragment() diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/ui/QuickCompatibilityFragment.kt b/app-unpriv/src/main/java/im/angry/openeuicc/ui/QuickCompatibilityFragment.kt index 03647bb..9b41730 100644 --- a/app-unpriv/src/main/java/im/angry/openeuicc/ui/QuickCompatibilityFragment.kt +++ b/app-unpriv/src/main/java/im/angry/openeuicc/ui/QuickCompatibilityFragment.kt @@ -148,7 +148,7 @@ open class QuickCompatibilityFragment : Fragment(), UnprivilegedEuiccContextMark if (omapiSlots.isEmpty()) { return CompatibilityResult(Compatibility.NOT_COMPATIBLE) } - val formatChannelName = appContainer.customizableTextProvider::formatNonUsbChannelName + val formatChannelName = appContainer.customizableTextProvider::formatInternalChannelName return CompatibilityResult( Compatibility.COMPATIBLE, slotsOmapi = omapiSlots.map(formatChannelName), 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 764287c..7cf300c 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 @@ -7,7 +7,6 @@ import android.view.MenuInflater import android.view.MenuItem import android.widget.Toast import im.angry.easyeuicc.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.util.SIMToolkit import im.angry.openeuicc.util.newInstanceEuicc import im.angry.openeuicc.util.slotId @@ -17,12 +16,8 @@ class UnprivilegedEuiccManagementFragment : EuiccManagementFragment() { companion object { const val TAG = "UnprivilegedEuiccManagementFragment" - fun newInstance( - slotId: Int, - portId: Int, - seId: EuiccChannel.SecureElementId - ): EuiccManagementFragment = - newInstanceEuicc(UnprivilegedEuiccManagementFragment::class.java, slotId, portId, seId) + fun newInstance(slotId: Int, portId: Int): EuiccManagementFragment = + newInstanceEuicc(UnprivilegedEuiccManagementFragment::class.java, slotId, portId) } private val stk by lazy { diff --git a/app-unpriv/src/main/res/values/strings.xml b/app-unpriv/src/main/res/values/strings.xml index eafa6c0..76d1c76 100644 --- a/app-unpriv/src/main/res/values/strings.xml +++ b/app-unpriv/src/main/res/values/strings.xml @@ -1,7 +1,6 @@ EasyEUICC SIM %d - SIM %d, SE %d Compatibility Check Open SIM Toolkit diff --git a/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt b/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt index ec4ba22..876387f 100644 --- a/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt +++ b/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt @@ -15,14 +15,13 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto @Suppress("NAME_SHADOWING") override suspend fun tryOpenEuiccChannel( port: UiccPortInfoCompat, - isdrAid: ByteArray, - seId: EuiccChannel.SecureElementId, + isdrAid: ByteArray ): EuiccChannel? { val port = port as RealUiccPortInfoCompat if (port.card.isRemovable) { // Attempt unprivileged (OMAPI) before TelephonyManager // but still try TelephonyManager in case OMAPI is broken - super.tryOpenEuiccChannel(port, isdrAid, seId)?.let { return it } + super.tryOpenEuiccChannel(port, isdrAid)?.let { return it } } if (port.card.isEuicc || preferenceRepository.removableTelephonyManagerFlow.first()) { @@ -41,7 +40,6 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto context.preferenceRepository.verboseLoggingFlow ), isdrAid, - seId, context.preferenceRepository.verboseLoggingFlow, context.preferenceRepository.ignoreTLSCertificateFlow, context.preferenceRepository.es10xMssFlow, @@ -55,6 +53,6 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto } } - return super.tryOpenEuiccChannel(port, isdrAid, seId) + return super.tryOpenEuiccChannel(port, isdrAid) } } \ No newline at end of file diff --git a/app/src/main/java/im/angry/openeuicc/di/PrivilegedUiComponentFactory.kt b/app/src/main/java/im/angry/openeuicc/di/PrivilegedUiComponentFactory.kt index 8af5833..e5b747a 100644 --- a/app/src/main/java/im/angry/openeuicc/di/PrivilegedUiComponentFactory.kt +++ b/app/src/main/java/im/angry/openeuicc/di/PrivilegedUiComponentFactory.kt @@ -1,18 +1,13 @@ package im.angry.openeuicc.di import androidx.fragment.app.Fragment -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.ui.EuiccManagementFragment import im.angry.openeuicc.ui.PrivilegedEuiccManagementFragment import im.angry.openeuicc.ui.PrivilegedSettingsFragment class PrivilegedUiComponentFactory : DefaultUiComponentFactory() { - override fun createEuiccManagementFragment( - slotId: Int, - portId: Int, - seId: EuiccChannel.SecureElementId - ): EuiccManagementFragment = - PrivilegedEuiccManagementFragment.newInstance(slotId, portId, seId) + override fun createEuiccManagementFragment(slotId: Int, portId: Int): EuiccManagementFragment = + PrivilegedEuiccManagementFragment.newInstance(slotId, portId) override fun createSettingsFragment(): Fragment = PrivilegedSettingsFragment() diff --git a/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt b/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt index d5d1e39..02b3baf 100644 --- a/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt +++ b/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt @@ -8,7 +8,6 @@ import android.telephony.UiccSlotMapping import android.telephony.euicc.DownloadableSubscription import android.telephony.euicc.EuiccInfo import android.util.Log -import im.angry.openeuicc.core.EuiccChannel import net.typeblog.lpac_jni.LocalProfileInfo import im.angry.openeuicc.core.EuiccChannelManager import im.angry.openeuicc.service.EuiccChannelManagerService.Companion.waitDone @@ -166,71 +165,70 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker { return GetDefaultDownloadableSubscriptionListResult(RESULT_OK, arrayOf()) } - override fun onGetEuiccProfileInfoList(slotId: Int): GetEuiccProfileInfoListResult = - withEuiccChannelManager { - Log.i(TAG, "onGetEuiccProfileInfoList slotId=$slotId") - if (slotId == -1 || shouldIgnoreSlot(slotId)) { - Log.i(TAG, "ignoring slot $slotId") - return@withEuiccChannelManager GetEuiccProfileInfoListResult( - RESULT_FIRST_USER, - arrayOf(), - true - ) - } - - // TODO: Temporarily enable the slot to access its profiles if it is currently unmapped - val port = euiccChannelManager.findFirstAvailablePort(slotId) - if (port == -1) { - return@withEuiccChannelManager GetEuiccProfileInfoListResult( - RESULT_FIRST_USER, - arrayOf(), - true - ) - } - - return@withEuiccChannelManager try { - euiccChannelManager.withEuiccChannel(slotId, port) { channel -> - val filteredProfiles = - if (preferenceRepository.unfilteredProfileListFlow.first()) - channel.lpa.profiles - else - channel.lpa.profiles.operational - val profiles = filteredProfiles.map { - EuiccProfileInfo.Builder(it.iccid).apply { - setProfileName(it.name) - setNickname(it.displayName) - setServiceProviderName(it.providerName) - setState( - when (it.state) { - LocalProfileInfo.State.Enabled -> EuiccProfileInfo.PROFILE_STATE_ENABLED - LocalProfileInfo.State.Disabled -> EuiccProfileInfo.PROFILE_STATE_DISABLED - } - ) - setProfileClass( - when (it.profileClass) { - LocalProfileInfo.Clazz.Testing -> EuiccProfileInfo.PROFILE_CLASS_TESTING - LocalProfileInfo.Clazz.Provisioning -> EuiccProfileInfo.PROFILE_CLASS_PROVISIONING - LocalProfileInfo.Clazz.Operational -> EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL - } - ) - }.build() - } - - GetEuiccProfileInfoListResult( - RESULT_OK, - profiles.toTypedArray(), - channel.port.card.isRemovable - ) - } - } catch (e: EuiccChannelManager.EuiccChannelNotFoundException) { - GetEuiccProfileInfoListResult( - RESULT_FIRST_USER, - arrayOf(), - true - ) - } + override fun onGetEuiccProfileInfoList(slotId: Int): GetEuiccProfileInfoListResult = withEuiccChannelManager { + Log.i(TAG, "onGetEuiccProfileInfoList slotId=$slotId") + if (slotId == -1 || shouldIgnoreSlot(slotId)) { + Log.i(TAG, "ignoring slot $slotId") + return@withEuiccChannelManager GetEuiccProfileInfoListResult( + RESULT_FIRST_USER, + arrayOf(), + true + ) } + // TODO: Temporarily enable the slot to access its profiles if it is currently unmapped + val port = euiccChannelManager.findFirstAvailablePort(slotId) + if (port == -1) { + return@withEuiccChannelManager GetEuiccProfileInfoListResult( + RESULT_FIRST_USER, + arrayOf(), + true + ) + } + + return@withEuiccChannelManager try { + euiccChannelManager.withEuiccChannel(slotId, port) { channel -> + val filteredProfiles = + if (preferenceRepository.unfilteredProfileListFlow.first()) + channel.lpa.profiles + else + channel.lpa.profiles.operational + val profiles = filteredProfiles.map { + EuiccProfileInfo.Builder(it.iccid).apply { + setProfileName(it.name) + setNickname(it.displayName) + setServiceProviderName(it.providerName) + setState( + when (it.state) { + LocalProfileInfo.State.Enabled -> EuiccProfileInfo.PROFILE_STATE_ENABLED + LocalProfileInfo.State.Disabled -> EuiccProfileInfo.PROFILE_STATE_DISABLED + } + ) + setProfileClass( + when (it.profileClass) { + LocalProfileInfo.Clazz.Testing -> EuiccProfileInfo.PROFILE_CLASS_TESTING + LocalProfileInfo.Clazz.Provisioning -> EuiccProfileInfo.PROFILE_CLASS_PROVISIONING + LocalProfileInfo.Clazz.Operational -> EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL + } + ) + }.build() + } + + GetEuiccProfileInfoListResult( + RESULT_OK, + profiles.toTypedArray(), + channel.port.card.isRemovable + ) + } + } catch (e: EuiccChannelManager.EuiccChannelNotFoundException) { + GetEuiccProfileInfoListResult( + RESULT_FIRST_USER, + arrayOf(), + true + ) + } + } + override fun onGetEuiccInfo(slotId: Int): EuiccInfo { return EuiccInfo("Unknown") // TODO: Can we actually implement this? } @@ -252,12 +250,7 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker { if (enabledAnywhere) return@withEuiccChannelManager RESULT_FIRST_USER euiccChannelManagerService.waitForForegroundTask() - val success = euiccChannelManagerService.launchProfileDeleteTask( - slotId, - ports[0], - EuiccChannel.SecureElementId.DEFAULT, - iccid - ) + val success = euiccChannelManagerService.launchProfileDeleteTask(slotId, ports[0], iccid) .waitDone() == null return@withEuiccChannelManager if (success) { @@ -282,10 +275,7 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker { iccid: String?, forceDeactivateSim: Boolean ): Int = withEuiccChannelManager { - Log.i( - TAG, - "onSwitchToSubscriptionWithPort slotId=$slotId portIndex=$portIndex iccid=$iccid forceDeactivateSim=$forceDeactivateSim" - ) + Log.i(TAG,"onSwitchToSubscriptionWithPort slotId=$slotId portIndex=$portIndex iccid=$iccid forceDeactivateSim=$forceDeactivateSim") if (shouldIgnoreSlot(slotId)) return@withEuiccChannelManager RESULT_FIRST_USER try { @@ -367,7 +357,6 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker { val res = euiccChannelManagerService.launchProfileSwitchTask( foundSlotId, foundPortId, - EuiccChannel.SecureElementId.DEFAULT, foundIccid, enable, 30 * 1000 @@ -397,13 +386,7 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker { euiccChannelManagerService.waitForForegroundTask() val success = - (euiccChannelManagerService.launchProfileRenameTask( - slotId, - port, - EuiccChannel.SecureElementId.DEFAULT, - iccid, - nickname!! - ) + (euiccChannelManagerService.launchProfileRenameTask(slotId, port, iccid, nickname!!) .waitDone()) == null euiccChannelManager.withEuiccChannel(slotId, port) { channel -> diff --git a/app/src/main/java/im/angry/openeuicc/ui/PrivilegedEuiccManagementFragment.kt b/app/src/main/java/im/angry/openeuicc/ui/PrivilegedEuiccManagementFragment.kt index bc38fb5..12b60bd 100644 --- a/app/src/main/java/im/angry/openeuicc/ui/PrivilegedEuiccManagementFragment.kt +++ b/app/src/main/java/im/angry/openeuicc/ui/PrivilegedEuiccManagementFragment.kt @@ -5,18 +5,13 @@ import android.view.ViewGroup import android.widget.Button import android.widget.PopupMenu import im.angry.openeuicc.R -import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.util.* import net.typeblog.lpac_jni.LocalProfileInfo -class PrivilegedEuiccManagementFragment : EuiccManagementFragment() { +class PrivilegedEuiccManagementFragment: EuiccManagementFragment() { companion object { - fun newInstance( - slotId: Int, - portId: Int, - seId: EuiccChannel.SecureElementId - ): EuiccManagementFragment = - newInstanceEuicc(PrivilegedEuiccManagementFragment::class.java, slotId, portId, seId) + fun newInstance(slotId: Int, portId: Int): EuiccManagementFragment = + newInstanceEuicc(PrivilegedEuiccManagementFragment::class.java, slotId, portId) } private var isMEP = false