ソースを参照

MainActivity: switch to flowEuiccPorts()

Peter Cai 1 年間 前
コミット
5e5210ae2d

+ 2 - 3
app-common/src/main/java/im/angry/openeuicc/di/DefaultUiComponentFactory.kt

@@ -1,13 +1,12 @@
 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.NoEuiccPlaceholderFragment
 
 open class DefaultUiComponentFactory : UiComponentFactory {
-    override fun createEuiccManagementFragment(channel: EuiccChannel): EuiccManagementFragment =
-        EuiccManagementFragment.newInstance(channel.slotId, channel.portId)
+    override fun createEuiccManagementFragment(slotId: Int, portId: Int): EuiccManagementFragment =
+        EuiccManagementFragment.newInstance(slotId, portId)
 
     override fun createNoEuiccPlaceholderFragment(): Fragment = NoEuiccPlaceholderFragment()
 }

+ 1 - 2
app-common/src/main/java/im/angry/openeuicc/di/UiComponentFactory.kt

@@ -1,10 +1,9 @@
 package im.angry.openeuicc.di
 
 import androidx.fragment.app.Fragment
-import im.angry.openeuicc.core.EuiccChannel
 import im.angry.openeuicc.ui.EuiccManagementFragment
 
 interface UiComponentFactory {
-    fun createEuiccManagementFragment(channel: EuiccChannel): EuiccManagementFragment
+    fun createEuiccManagementFragment(slotId: Int, portId: Int): EuiccManagementFragment
     fun createNoEuiccPlaceholderFragment(): Fragment
 }

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

@@ -23,9 +23,12 @@ import androidx.viewpager2.widget.ViewPager2
 import com.google.android.material.tabs.TabLayout
 import com.google.android.material.tabs.TabLayoutMediator
 import im.angry.openeuicc.common.R
+import im.angry.openeuicc.core.EuiccChannelManager
 import im.angry.openeuicc.util.*
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 
@@ -44,6 +47,7 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
     private var refreshing = false
 
     private data class Page(
+        val logicalSlotId: Int,
         val title: String,
         val createFragment: () -> Fragment
     )
@@ -138,65 +142,83 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
         // Prevent concurrent access with any running foreground task
         euiccChannelManagerService.waitForForegroundTask()
 
-        val knownChannels = withContext(Dispatchers.IO) {
-            euiccChannelManager.enumerateEuiccChannels().onEach {
-                Log.d(TAG, "slot ${it.slotId} port ${it.portId}")
+        val (usbDevice, _) = withContext(Dispatchers.IO) {
+            euiccChannelManager.enumerateUsbEuiccChannel()
+        }
+
+        val newPages: MutableList<Page> = mutableListOf()
+
+        euiccChannelManager.flowEuiccPorts().onEach { (slotId, portId) ->
+            Log.d(TAG, "slot $slotId port $portId")
+
+            euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
                 if (preferenceRepository.verboseLoggingFlow.first()) {
-                    Log.d(TAG, it.lpa.eID)
+                    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(it.logicalSlotId)
+                euiccChannelManager.notifyEuiccProfilesChanged(channel.logicalSlotId)
+
+                newPages.add(
+                    Page(
+                        channel.logicalSlotId,
+                        getString(R.string.channel_name_format, channel.logicalSlotId)
+                    ) {
+                        appContainer.uiComponentFactory.createEuiccManagementFragment(
+                            slotId,
+                            portId
+                        )
+                    })
             }
+        }.collect()
+
+        // If USB readers exist, add them at the very last
+        // We use a wrapper fragment to handle logic specific to USB readers
+        usbDevice?.let {
+            pages.add(
+                Page(
+                    EuiccChannelManager.USB_CHANNEL_ID,
+                    it.productName ?: getString(R.string.usb)
+                ) { UsbCcidReaderFragment() })
         }
-
-        val (usbDevice, _) = withContext(Dispatchers.IO) {
-            euiccChannelManager.enumerateUsbEuiccChannel()
+        viewPager.visibility = View.VISIBLE
+
+        if (pages.size > 1) {
+            tabs.visibility = View.VISIBLE
+        } else if (pages.isEmpty()) {
+            pages.add(
+                Page(
+                    -1,
+                    ""
+                ) { appContainer.uiComponentFactory.createNoEuiccPlaceholderFragment() })
         }
 
-        withContext(Dispatchers.Main) {
-            loadingProgress.visibility = View.GONE
-
-            knownChannels.sortedBy { it.logicalSlotId }.forEach { channel ->
-                pages.add(Page(
-                    getString(R.string.channel_name_format, channel.logicalSlotId)
-                ) { appContainer.uiComponentFactory.createEuiccManagementFragment(channel) })
-            }
-
-            // If USB readers exist, add them at the very last
-            // We use a wrapper fragment to handle logic specific to USB readers
-            usbDevice?.let {
-                pages.add(Page(it.productName ?: getString(R.string.usb)) { UsbCcidReaderFragment() })
-            }
-            viewPager.visibility = View.VISIBLE
-
-            if (pages.size > 1) {
-                tabs.visibility = View.VISIBLE
-            } else if (pages.isEmpty()) {
-                pages.add(Page("") { appContainer.uiComponentFactory.createNoEuiccPlaceholderFragment() })
-            }
+        newPages.sortBy { it.logicalSlotId }
 
-            pagerAdapter.notifyDataSetChanged()
-            // Reset the adapter so that the current view actually gets cleared
-            // notifyDataSetChanged() doesn't cause the current view to be removed.
-            viewPager.adapter = pagerAdapter
+        pages.clear()
+        pages.addAll(newPages)
 
-            if (fromUsbEvent && usbDevice != null) {
-                // If this refresh was triggered by a USB insertion while active, scroll to that page
-                viewPager.post {
-                    viewPager.setCurrentItem(pages.size - 1, true)
-                }
-            } else {
-                viewPager.currentItem = 0
-            }
+        loadingProgress.visibility = View.GONE
+        pagerAdapter.notifyDataSetChanged()
+        // Reset the adapter so that the current view actually gets cleared
+        // notifyDataSetChanged() doesn't cause the current view to be removed.
+        viewPager.adapter = pagerAdapter
 
-            if (pages.size > 0) {
-                ensureNotificationPermissions()
+        if (fromUsbEvent && usbDevice != null) {
+            // If this refresh was triggered by a USB insertion while active, scroll to that page
+            viewPager.post {
+                viewPager.setCurrentItem(pages.size - 1, true)
             }
+        } else {
+            viewPager.currentItem = 0
+        }
 
-            refreshing = false
+        if (pages.size > 0) {
+            ensureNotificationPermissions()
         }
+
+        refreshing = false
     }
 
     private fun refresh(fromUsbEvent: Boolean = false) {

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

@@ -157,7 +157,10 @@ class UsbCcidReaderFragment : Fragment(), OpenEuiccContextMarker {
             childFragmentManager.commit {
                 replace(
                     R.id.child_container,
-                    appContainer.uiComponentFactory.createEuiccManagementFragment(channel)
+                    appContainer.uiComponentFactory.createEuiccManagementFragment(
+                        channel.slotId,
+                        channel.portId
+                    )
                 )
             }
         } else {

+ 2 - 3
app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedUiComponentFactory.kt

@@ -1,14 +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.UnprivilegedEuiccManagementFragment
 import im.angry.openeuicc.ui.UnprivilegedNoEuiccPlaceholderFragment
 
 class UnprivilegedUiComponentFactory : DefaultUiComponentFactory() {
-    override fun createEuiccManagementFragment(channel: EuiccChannel): EuiccManagementFragment =
-        UnprivilegedEuiccManagementFragment.newInstance(channel.slotId, channel.portId)
+    override fun createEuiccManagementFragment(slotId: Int, portId: Int): EuiccManagementFragment =
+        UnprivilegedEuiccManagementFragment.newInstance(slotId, portId)
 
     override fun createNoEuiccPlaceholderFragment(): Fragment =
         UnprivilegedNoEuiccPlaceholderFragment()

+ 2 - 3
app/src/main/java/im/angry/openeuicc/di/PrivilegedUiComponentFactory.kt

@@ -1,10 +1,9 @@
 package im.angry.openeuicc.di
 
-import im.angry.openeuicc.core.EuiccChannel
 import im.angry.openeuicc.ui.EuiccManagementFragment
 import im.angry.openeuicc.ui.PrivilegedEuiccManagementFragment
 
 class PrivilegedUiComponentFactory : DefaultUiComponentFactory() {
-    override fun createEuiccManagementFragment(channel: EuiccChannel): EuiccManagementFragment =
-        PrivilegedEuiccManagementFragment.newInstance(channel.slotId, channel.portId)
+    override fun createEuiccManagementFragment(slotId: Int, portId: Int): EuiccManagementFragment =
+        PrivilegedEuiccManagementFragment.newInstance(slotId, portId)
 }