From f294fb5e17aa19bdda92769c82bc150105acefb6 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Fri, 13 Dec 2024 08:33:02 -0500 Subject: [PATCH 1/2] ui: wizard: Reintroduce support for downloading to USB readers ...and fixup our API which caused this problem in the first place. --- .../openeuicc/core/DefaultEuiccChannelManager.kt | 11 +++++++++-- .../im/angry/openeuicc/core/EuiccChannelManager.kt | 11 ++++++++++- .../main/java/im/angry/openeuicc/ui/MainActivity.kt | 2 +- .../ui/wizard/DownloadWizardSlotSelectFragment.kt | 9 +++++++-- .../angry/openeuicc/util/PrivilegedTelephonyUtils.kt | 2 +- 5 files changed, 28 insertions(+), 7 deletions(-) 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 c75af40..07db80b 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 @@ -13,7 +13,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.flow.merge import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext @@ -208,7 +208,7 @@ open class DefaultEuiccChannelManager( } } - override fun flowEuiccPorts(): Flow> = flow { + override fun flowInternalEuiccPorts(): Flow> = flow { uiccCards.forEach { info -> info.ports.forEach { port -> tryOpenEuiccChannel(port)?.also { @@ -223,6 +223,13 @@ open class DefaultEuiccChannelManager( } }.flowOn(Dispatchers.IO) + override fun flowAllOpenEuiccPorts(): Flow> = + merge(flowInternalEuiccPorts(), flow { + if (tryOpenUsbEuiccChannel().second) { + emit(Pair(EuiccChannelManager.USB_CHANNEL_ID, 0)) + } + }) + override suspend fun tryOpenUsbEuiccChannel(): Pair = withContext(Dispatchers.IO) { usbManager.deviceList.values.forEach { device -> 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 c485cd2..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 @@ -26,7 +26,16 @@ interface EuiccChannelManager { * * To obtain a temporary reference to a EuiccChannel, use `withEuiccChannel()`. */ - fun flowEuiccPorts(): Flow> + fun flowInternalEuiccPorts(): Flow> + + /** + * Same as flowInternalEuiccPorts(), except that this includes non-device internal eUICC chips + * as well. Namely, this includes the USB reader. + * + * Non-internal readers will only be included if they have been opened properly, i.e. with permissions + * granted by the user. + */ + fun flowAllOpenEuiccPorts(): Flow> /** * Scan all possible USB devices for CCID readers that may contain eUICC cards. 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 b11a3dd..767e7e0 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 @@ -151,7 +151,7 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { val newPages: MutableList = mutableListOf() - euiccChannelManager.flowEuiccPorts().onEach { (slotId, portId) -> + euiccChannelManager.flowInternalEuiccPorts().onEach { (slotId, portId) -> Log.d(TAG, "slot $slotId port $portId") euiccChannelManager.withEuiccChannel(slotId, portId) { channel -> 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 b268b62..ffb3ce1 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,6 +14,7 @@ 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.EuiccChannelManager import im.angry.openeuicc.util.* import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList @@ -91,7 +92,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt private suspend fun init() { ensureEuiccChannelManager() showProgressBar(-1) - val slots = euiccChannelManager.flowEuiccPorts().map { (slotId, portId) -> + val slots = euiccChannelManager.flowAllOpenEuiccPorts().map { (slotId, portId) -> euiccChannelManager.withEuiccChannel(slotId, portId) { channel -> SlotInfo( channel.logicalSlotId, @@ -174,7 +175,11 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt ) } - title.text = root.context.getString(R.string.download_wizard_slot_title, item.logicalSlotId) + title.text = if (item.logicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { + root.context.getString(R.string.usb) + } else { + root.context.getString(R.string.download_wizard_slot_title, item.logicalSlotId) + } eID.text = item.eID activeProfile.text = item.enabledProfileName ?: root.context.getString(R.string.unknown) freeSpace.text = formatFreeSpace(item.freeSpace) diff --git a/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyUtils.kt b/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyUtils.kt index edeb49f..650fe74 100644 --- a/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyUtils.kt +++ b/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyUtils.kt @@ -18,7 +18,7 @@ val TelephonyManager.dsdsEnabled: Boolean fun TelephonyManager.setDsdsEnabled(euiccManager: EuiccChannelManager, enabled: Boolean) { // Disable all eSIM profiles before performing a DSDS switch (only for internal eSIMs) runBlocking { - euiccManager.flowEuiccPorts().onEach { (slotId, portId) -> + euiccManager.flowInternalEuiccPorts().onEach { (slotId, portId) -> euiccManager.withEuiccChannel(slotId, portId) { if (!it.port.card.isRemovable) { it.lpa.disableActiveProfile(false) From aed247904487ba9b2f01ac2030406a9bd0c1c37c Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Fri, 13 Dec 2024 08:34:21 -0500 Subject: [PATCH 2/2] ui: wizard: Prevent de-selecting checkboxes --- .../openeuicc/ui/wizard/DownloadWizardSlotSelectFragment.kt | 1 + 1 file changed, 1 insertion(+) 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 ffb3ce1..54dbc08 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 @@ -151,6 +151,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt @Suppress("UNUSED_PARAMETER") fun onSelect(view: View) { if (curIdx < 0) return + checkBox.isChecked = true if (adapter.currentSelectedIdx == curIdx) return val lastIdx = adapter.currentSelectedIdx adapter.currentSelectedIdx = curIdx