diff --git a/app-common/src/main/java/im/angry/openeuicc/core/ApduInterfaceAtrProvider.kt b/app-common/src/main/java/im/angry/openeuicc/core/ApduInterfaceAtrProvider.kt deleted file mode 100644 index c3646d2..0000000 --- a/app-common/src/main/java/im/angry/openeuicc/core/ApduInterfaceAtrProvider.kt +++ /dev/null @@ -1,5 +0,0 @@ -package im.angry.openeuicc.core - -interface ApduInterfaceAtrProvider { - val atr: ByteArray? -} \ No newline at end of file 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 293042c..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 @@ -184,30 +184,20 @@ open class DefaultEuiccChannelManager( } override suspend fun waitForReconnect(physicalSlotId: Int, portId: Int, timeoutMillis: Long) { - if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { - 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 - channelCache.find { it.slotId == physicalSlotId && it.portId == portId }?.apply { - if (valid) close() - } + if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) return + + // 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 + channelCache.find { it.slotId == physicalSlotId && it.portId == portId }?.apply { + if (valid) close() } withTimeout(timeoutMillis) { while (true) { try { - val channel = if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { - // tryOpenUsbEuiccChannel() will always try to reopen the channel, even if - // a USB channel already exists - tryOpenUsbEuiccChannel() - usbChannel!! - } else { - // tryOpenEuiccChannel() will automatically dispose of invalid channels - // and recreate when needed - findEuiccChannelByPort(physicalSlotId, portId)!! - } + // tryOpenEuiccChannel() will automatically dispose of invalid channels + // and recreate when needed + val channel = findEuiccChannelByPort(physicalSlotId, portId)!! check(channel.valid) { "Invalid channel" } break } catch (e: Exception) { 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 5f399ea..541f867 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 @@ -16,11 +16,6 @@ interface EuiccChannel { val valid: Boolean - /** - * Answer to Reset (ATR) value of the underlying interface, if any - */ - val atr: ByteArray? - /** * Intrinsic name of this channel. For device-internal SIM slots, * this should be null; for USB readers, this should be the name of 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 a82cb97..a281948 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 @@ -11,7 +11,7 @@ class EuiccChannelImpl( override val type: String, override val port: UiccPortInfoCompat, override val intrinsicChannelName: String?, - private val apduInterface: ApduInterface, + apduInterface: ApduInterface, verboseLoggingFlow: Flow, ignoreTLSCertificateFlow: Flow ) : EuiccChannel { @@ -22,9 +22,6 @@ class EuiccChannelImpl( override val lpa: LocalProfileAssistant = LocalProfileAssistantImpl(apduInterface, HttpInterfaceImpl(verboseLoggingFlow, ignoreTLSCertificateFlow)) - override val atr: ByteArray? - get() = (apduInterface as? ApduInterfaceAtrProvider)?.atr - override val valid: Boolean get() = lpa.valid 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 4204e82..6011f53 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 @@ -33,8 +33,6 @@ class EuiccChannelWrapper(orig: EuiccChannel) : EuiccChannel { get() = channel.valid override val intrinsicChannelName: String? get() = channel.intrinsicChannelName - override val atr: ByteArray? - get() = channel.atr override fun close() = channel.close() diff --git a/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt b/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt index c70669d..71aa386 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt @@ -15,7 +15,7 @@ class OmapiApduInterface( private val service: SEService, private val port: UiccPortInfoCompat, private val verboseLoggingFlow: Flow -): ApduInterface, ApduInterfaceAtrProvider { +): ApduInterface { companion object { const val TAG = "OmapiApduInterface" } @@ -26,9 +26,6 @@ class OmapiApduInterface( override val valid: Boolean get() = service.isConnected && (this::session.isInitialized && !session.isClosed) - override val atr: ByteArray? - get() = session.atr - override fun connect() { session = service.getUiccReaderCompat(port.logicalSlotIndex + 1).openSession() } diff --git a/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt b/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt index 624ef89..9894343 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt @@ -3,7 +3,6 @@ package im.angry.openeuicc.core.usb import android.hardware.usb.UsbDeviceConnection import android.hardware.usb.UsbEndpoint import android.util.Log -import im.angry.openeuicc.core.ApduInterfaceAtrProvider import im.angry.openeuicc.util.* import kotlinx.coroutines.flow.Flow import net.typeblog.lpac_jni.ApduInterface @@ -13,7 +12,7 @@ class UsbApduInterface( private val bulkIn: UsbEndpoint, private val bulkOut: UsbEndpoint, private val verboseLoggingFlow: Flow -) : ApduInterface, ApduInterfaceAtrProvider { +): ApduInterface { companion object { private const val TAG = "UsbApduInterface" } @@ -23,8 +22,6 @@ class UsbApduInterface( private var channelId = -1 - override var atr: ByteArray? = null - override fun connect() { ccidDescription = UsbCcidDescription.fromRawDescriptors(conn.rawDescriptors)!! @@ -35,9 +32,7 @@ class UsbApduInterface( transceiver = UsbCcidTransceiver(conn, bulkIn, bulkOut, ccidDescription, verboseLoggingFlow) try { - // 6.1.1.1 PC_to_RDR_IccPowerOn (Page 20 of 40) - // https://www.usb.org/sites/default/files/DWG_Smart-Card_USB-ICC_ICCD_rev10.pdf - atr = transceiver.iccPowerOn().data + transceiver.iccPowerOn() } catch (e: Exception) { e.printStackTrace() throw e 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 760f1af..f76f1dc 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 @@ -362,6 +362,9 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { ) } + val isForegroundTaskRunning: Boolean + get() = foregroundTaskState.value != ForegroundTaskState.Idle + suspend fun waitForForegroundTask() { foregroundTaskState.takeWhile { it != ForegroundTaskState.Idle } .collect() @@ -445,7 +448,7 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { portId: Int, iccid: String, enable: Boolean, // Enable or disable the profile indicated in iccid - reconnectTimeoutMillis: Long = 0 // 0 = do not wait for reconnect + reconnectTimeoutMillis: Long = 0 // 0 = do not wait for reconnect, useful for USB readers ): ForegroundTaskSubscriberFlow = launchForegroundTask( getString(R.string.task_profile_switch), 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 b303e33..aca2572 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 @@ -41,7 +41,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { @StringRes val titleResId: Int, val content: String?, - val copiedToastResId: Int? = null, + val copiedToastResId: Int? = null ) override fun onCreate(savedInstanceState: Bundle?) { @@ -114,7 +114,6 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { ) ) channel.lpa.euiccInfo2.let { info -> - add(Item(R.string.euicc_info_sgp22_version, info?.sgp22Version)) add(Item(R.string.euicc_info_firmware_version, info?.euiccFirmwareVersion)) add(Item(R.string.euicc_info_globalplatform_version, info?.globalPlatformVersion)) add(Item(R.string.euicc_info_pp_version, info?.ppVersion)) @@ -134,13 +133,6 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { } add(Item(R.string.euicc_info_ci_type, getString(resId))) } - add( - Item( - R.string.euicc_info_atr, - channel.atr?.encodeHex() ?: getString(R.string.unavailable), - copiedToastResId = R.string.toast_atr_copied, - ) - ) } private fun formatByBoolean(b: Boolean, res: Pair): String = 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 842f4ec..f806ae0 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 @@ -228,7 +228,11 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, portId, iccid, enable, - reconnectTimeoutMillis = 30 * 1000 + reconnectTimeoutMillis = if (isUsb) { + 0 + } else { + 30 * 1000 + } ).waitDone() when (err) { 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 25c5273..e3f2d8d 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 @@ -54,7 +54,6 @@ class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragment override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - profileRenameNewName.editText!!.setText(requireArguments().getString("currentName")) toolbar.apply { setTitle(R.string.rename) setNavigationOnClickListener { @@ -67,6 +66,11 @@ class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragment } } + override fun onStart() { + super.onStart() + profileRenameNewName.editText!!.setText(requireArguments().getString("currentName")) + } + override fun onResume() { super.onResume() setWidthPercent(95) 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 e342dee..66b31bc 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 @@ -5,21 +5,15 @@ import android.view.View import android.view.inputmethod.InputMethodManager import android.widget.Button import android.widget.ProgressBar -import android.widget.Toast import androidx.activity.OnBackPressedCallback import androidx.activity.enableEdgeToEdge import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat 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.EuiccChannelManager import im.angry.openeuicc.ui.BaseEuiccAccessActivity import im.angry.openeuicc.util.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import net.typeblog.lpac_jni.LocalProfileAssistant class DownloadWizardActivity: BaseEuiccAccessActivity() { @@ -155,39 +149,13 @@ class DownloadWizardActivity: BaseEuiccAccessActivity() { private fun onNextPressed() { hideIme() - nextButton.isEnabled = false - progressBar.visibility = View.VISIBLE - progressBar.isIndeterminate = true - - lifecycleScope.launch(Dispatchers.Main) { - if (state.selectedLogicalSlot >= 0) { - try { - // This is run on IO by default - euiccChannelManager.withEuiccChannel(state.selectedLogicalSlot) { channel -> - // Be _very_ sure that the channel we got is valid - if (!channel.valid) throw EuiccChannelManager.EuiccChannelNotFoundException() - } - } catch (e: EuiccChannelManager.EuiccChannelNotFoundException) { - Toast.makeText( - this@DownloadWizardActivity, - R.string.download_wizard_slot_removed, - Toast.LENGTH_LONG - ).show() - finish() - } - } - - progressBar.visibility = View.GONE - nextButton.isEnabled = true - - if (currentFragment?.hasNext == true) { - currentFragment?.beforeNext() - val nextFrag = currentFragment?.createNextFragment() - if (nextFrag == null) { - finish() - } else { - showFragment(nextFrag, R.anim.slide_in_right, R.anim.slide_out_left) - } + if (currentFragment?.hasNext == true) { + currentFragment?.beforeNext() + val nextFrag = currentFragment?.createNextFragment() + if (nextFrag == null) { + finish() + } else { + showFragment(nextFrag, R.anim.slide_in_right, R.anim.slide_out_left) } } } diff --git a/app-common/src/main/res/layout/euicc_info_item.xml b/app-common/src/main/res/layout/euicc_info_item.xml index fa148fb..39d15a6 100644 --- a/app-common/src/main/res/layout/euicc_info_item.xml +++ b/app-common/src/main/res/layout/euicc_info_item.xml @@ -22,6 +22,8 @@ android:layout_height="wrap_content" android:layout_marginHorizontal="24dp" android:layout_marginVertical="12dp" + android:maxLines="1" + android:ellipsize="marquee" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/euicc_info_title" diff --git a/app-common/src/main/res/layout/fragment_download_details.xml b/app-common/src/main/res/layout/fragment_download_details.xml index 1a25075..be01ad2 100644 --- a/app-common/src/main/res/layout/fragment_download_details.xml +++ b/app-common/src/main/res/layout/fragment_download_details.xml @@ -82,7 +82,7 @@ android:maxLines="1" android:layout_width="match_parent" android:layout_height="match_parent" - android:inputType="numberPassword" /> + android:inputType="textPassword" /> diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index bc46825..7b0ff69 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -3,7 +3,6 @@ No removable eUICC card accessible by this app is detected on this device. Insert a compatible card or a USB reader. No profiles (yet) on this eSIM. Unknown - Unavailable Help Reload Slots @@ -32,7 +31,6 @@ Confirmation string mismatch ICCID copied to clipboard EID copied to clipboard - ATR copied to clipboard Grant USB permission Permission is needed to access the USB smart card reader. @@ -63,7 +61,6 @@ Download Wizard Back Next - Selected SIM has been removed Select or confirm the eSIM you would like to download to: Type: Removable @@ -124,7 +121,6 @@ Access Mode Removable EID - SGP.22 Version eUICC OS Version GlobalPlatform Version SAS Accreditation Number @@ -134,7 +130,6 @@ GSMA Live CI GSMA Test CI Unknown eSIM CI - Answer To Reset (ATR) Yes No diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt index 6c73051..e69c7ff 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt @@ -2,7 +2,6 @@ package net.typeblog.lpac_jni /* Corresponds to EuiccInfo2 in SGP.22 */ data class EuiccInfo2( - val sgp22Version: String, val profileVersion: String, val euiccFirmwareVersion: String, val globalPlatformVersion: String, diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt index 370fcab..d50c1c1 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt @@ -62,7 +62,6 @@ internal object LpacJni { external fun notificationsFree(head: Long) // EuiccInfo2 external fun euiccInfo2Free(info: Long) - external fun euiccInfo2GetSGP22Version(info: Long): String external fun euiccInfo2GetProfileVersion(info: Long): String external fun euiccInfo2GetEuiccFirmwareVersion(info: Long): String external fun euiccInfo2GetGlobalPlatformVersion(info: Long): String diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 7310acd..0330d82 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -171,7 +171,6 @@ class LocalProfileAssistantImpl( } val ret = EuiccInfo2( - LpacJni.euiccInfo2GetSGP22Version(cInfo), LpacJni.euiccInfo2GetProfileVersion(cInfo), LpacJni.euiccInfo2GetEuiccFirmwareVersion(cInfo), LpacJni.euiccInfo2GetGlobalPlatformVersion(cInfo), diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c index 38d4f3a..e438107 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c @@ -266,7 +266,6 @@ void lpac_jni_euiccinfo2_free(struct es10c_ex_euiccinfo2 *info) { LPAC_JNI_STRUCT_GETTER_NULL_TERM_LIST_NEXT(char*, stringArr) LPAC_JNI_STRUCT_FREE(struct es10c_ex_euiccinfo2, euiccInfo2, lpac_jni_euiccinfo2_free) -LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, svn, SGP22Version) LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, profileVersion, ProfileVersion) LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, euiccFirmwareVer, EuiccFirmwareVersion) LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, globalplatformVersion, GlobalPlatformVersion)