ソースを参照

ui: wizard: Reintroduce support for downloading to USB readers

...and fixup our API which caused this problem in the first place.
Peter Cai 1 年間 前
コミット
f294fb5e17

+ 9 - 2
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.flow
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
 import kotlinx.coroutines.sync.withLock
 import kotlinx.coroutines.withContext
 import kotlinx.coroutines.withContext
@@ -208,7 +208,7 @@ open class DefaultEuiccChannelManager(
         }
         }
     }
     }
 
 
-    override fun flowEuiccPorts(): Flow<Pair<Int, Int>> = flow {
+    override fun flowInternalEuiccPorts(): Flow<Pair<Int, Int>> = flow {
         uiccCards.forEach { info ->
         uiccCards.forEach { info ->
             info.ports.forEach { port ->
             info.ports.forEach { port ->
                 tryOpenEuiccChannel(port)?.also {
                 tryOpenEuiccChannel(port)?.also {
@@ -223,6 +223,13 @@ open class DefaultEuiccChannelManager(
         }
         }
     }.flowOn(Dispatchers.IO)
     }.flowOn(Dispatchers.IO)
 
 
+    override fun flowAllOpenEuiccPorts(): Flow<Pair<Int, Int>> =
+        merge(flowInternalEuiccPorts(), flow {
+            if (tryOpenUsbEuiccChannel().second) {
+                emit(Pair(EuiccChannelManager.USB_CHANNEL_ID, 0))
+            }
+        })
+
     override suspend fun tryOpenUsbEuiccChannel(): Pair<UsbDevice?, Boolean> =
     override suspend fun tryOpenUsbEuiccChannel(): Pair<UsbDevice?, Boolean> =
         withContext(Dispatchers.IO) {
         withContext(Dispatchers.IO) {
             usbManager.deviceList.values.forEach { device ->
             usbManager.deviceList.values.forEach { device ->

+ 10 - 1
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()`.
      * To obtain a temporary reference to a EuiccChannel, use `withEuiccChannel()`.
      */
      */
-    fun flowEuiccPorts(): Flow<Pair<Int, Int>>
+    fun flowInternalEuiccPorts(): Flow<Pair<Int, Int>>
+
+    /**
+     * 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<Pair<Int, Int>>
 
 
     /**
     /**
      * Scan all possible USB devices for CCID readers that may contain eUICC cards.
      * Scan all possible USB devices for CCID readers that may contain eUICC cards.

+ 1 - 1
app-common/src/main/java/im/angry/openeuicc/ui/MainActivity.kt

@@ -151,7 +151,7 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
 
 
         val newPages: MutableList<Page> = mutableListOf()
         val newPages: MutableList<Page> = mutableListOf()
 
 
-        euiccChannelManager.flowEuiccPorts().onEach { (slotId, portId) ->
+        euiccChannelManager.flowInternalEuiccPorts().onEach { (slotId, portId) ->
             Log.d(TAG, "slot $slotId port $portId")
             Log.d(TAG, "slot $slotId port $portId")
 
 
             euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
             euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->

+ 7 - 2
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
 import androidx.recyclerview.widget.RecyclerView.ViewHolder
 import androidx.recyclerview.widget.RecyclerView.ViewHolder
 import im.angry.openeuicc.common.R
 import im.angry.openeuicc.common.R
+import im.angry.openeuicc.core.EuiccChannelManager
 import im.angry.openeuicc.util.*
 import im.angry.openeuicc.util.*
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.toList
 import kotlinx.coroutines.flow.toList
@@ -91,7 +92,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt
     private suspend fun init() {
     private suspend fun init() {
         ensureEuiccChannelManager()
         ensureEuiccChannelManager()
         showProgressBar(-1)
         showProgressBar(-1)
-        val slots = euiccChannelManager.flowEuiccPorts().map { (slotId, portId) ->
+        val slots = euiccChannelManager.flowAllOpenEuiccPorts().map { (slotId, portId) ->
             euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
             euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
                 SlotInfo(
                 SlotInfo(
                     channel.logicalSlotId,
                     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
             eID.text = item.eID
             activeProfile.text = item.enabledProfileName ?: root.context.getString(R.string.unknown)
             activeProfile.text = item.enabledProfileName ?: root.context.getString(R.string.unknown)
             freeSpace.text = formatFreeSpace(item.freeSpace)
             freeSpace.text = formatFreeSpace(item.freeSpace)

+ 1 - 1
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) {
 fun TelephonyManager.setDsdsEnabled(euiccManager: EuiccChannelManager, enabled: Boolean) {
     // Disable all eSIM profiles before performing a DSDS switch (only for internal eSIMs)
     // Disable all eSIM profiles before performing a DSDS switch (only for internal eSIMs)
     runBlocking {
     runBlocking {
-        euiccManager.flowEuiccPorts().onEach { (slotId, portId) ->
+        euiccManager.flowInternalEuiccPorts().onEach { (slotId, portId) ->
             euiccManager.withEuiccChannel(slotId, portId) {
             euiccManager.withEuiccChannel(slotId, portId) {
                 if (!it.port.card.isRemovable) {
                 if (!it.port.card.isRemovable) {
                     it.lpa.disableActiveProfile(false)
                     it.lpa.disableActiveProfile(false)