diff --git a/app-common/src/main/AndroidManifest.xml b/app-common/src/main/AndroidManifest.xml
index a33838f..f53e6ff 100644
--- a/app-common/src/main/AndroidManifest.xml
+++ b/app-common/src/main/AndroidManifest.xml
@@ -19,11 +19,6 @@
android:name="im.angry.openeuicc.ui.NotificationsActivity"
android:label="@string/profile_notifications" />
-
-
@@ -33,9 +28,15 @@
android:label="@string/pref_advanced_logs" />
+
+
- euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
- Triple(slotId, channel.logicalSlotId, portId)
- }
- }.toList().sortedBy { it.second }
- }
-
- when {
- knownChannels.isEmpty() -> {
- finish()
- }
- // Detect multiple eUICC chips
- knownChannels.distinctBy { it.first }.size > 1 -> {
- SlotSelectFragment.newInstance(
- knownChannels.map { it.first },
- knownChannels.map { it.second },
- knownChannels.map { it.third })
- .show(supportFragmentManager, SlotSelectFragment.TAG)
- }
- else -> {
- // If the device has only one eSIM "chip" (but may be mapped to multiple slots),
- // we can skip the slot selection dialog since there is only one chip to save to.
- onSlotSelected(
- knownChannels[0].first,
- knownChannels[0].third
- )
- }
- }
- }
- }
-
- override fun onSlotSelected(slotId: Int, portId: Int) {
- ProfileDownloadFragment.newInstance(slotId, portId, finishWhenDone = true)
- .show(supportFragmentManager, ProfileDownloadFragment.TAG)
- }
-
- override fun onSlotSelectCancelled() = finish()
-}
\ No newline at end of file
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 824b683..8e7b158 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
@@ -37,7 +37,6 @@ import im.angry.openeuicc.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -110,16 +109,9 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
LinearLayoutManager(view.context, LinearLayoutManager.VERTICAL, false)
fab.setOnClickListener {
- lifecycleScope.launch {
- if (preferenceRepository.experimentalDownloadWizardFlow.first()) {
- Intent(requireContext(), DownloadWizardActivity::class.java).apply {
- putExtra("selectedLogicalSlot", logicalSlotId)
- startActivity(this)
- }
- } else {
- ProfileDownloadFragment.newInstance(slotId, portId)
- .show(childFragmentManager, ProfileDownloadFragment.TAG)
- }
+ Intent(requireContext(), DownloadWizardActivity::class.java).apply {
+ putExtra("selectedLogicalSlot", logicalSlotId)
+ startActivity(this)
}
}
}
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 7711643..b11a3dd 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
@@ -126,7 +126,10 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
}
private fun ensureNotificationPermissions() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
+ val needsNotificationPerms = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
+ val notificationPermsGranted =
+ needsNotificationPerms && checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
+ if (needsNotificationPerms && !notificationPermsGranted) {
requestPermissions(
arrayOf(android.Manifest.permission.POST_NOTIFICATIONS),
PERMISSION_REQUEST_CODE
@@ -160,38 +163,29 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
// but it could change in the future
euiccChannelManager.notifyEuiccProfilesChanged(channel.logicalSlotId)
- newPages.add(
- Page(
- channel.logicalSlotId,
- getString(R.string.channel_name_format, channel.logicalSlotId)
- ) {
- appContainer.uiComponentFactory.createEuiccManagementFragment(
- slotId,
- portId
- )
- })
+ val channelName = getString(R.string.channel_name_format, channel.logicalSlotId)
+ newPages.add(Page(channel.logicalSlotId, channelName) {
+ 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 {
- newPages.add(
- Page(
- EuiccChannelManager.USB_CHANNEL_ID,
- it.productName ?: getString(R.string.usb)
- ) { UsbCcidReaderFragment() })
+ val productName = it.productName ?: getString(R.string.usb)
+ newPages.add(Page(EuiccChannelManager.USB_CHANNEL_ID, productName) {
+ UsbCcidReaderFragment()
+ })
}
viewPager.visibility = View.VISIBLE
if (newPages.size > 1) {
tabs.visibility = View.VISIBLE
} else if (newPages.isEmpty()) {
- newPages.add(
- Page(
- -1,
- ""
- ) { appContainer.uiComponentFactory.createNoEuiccPlaceholderFragment() })
+ newPages.add(Page(-1, "") {
+ appContainer.uiComponentFactory.createNoEuiccPlaceholderFragment()
+ })
}
newPages.sortBy { it.logicalSlotId }
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 181aeee..a06b587 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
@@ -38,14 +38,13 @@ class ProfileDeleteFragment : DialogFragment(), EuiccChannelFragmentMarker {
get() = editText.text.toString() == requireArguments().getString("name")!!
private var deleting = false
- override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
- return AlertDialog.Builder(requireContext(), R.style.AlertDialogTheme).apply {
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
+ AlertDialog.Builder(requireContext(), R.style.AlertDialogTheme).apply {
setMessage(getString(R.string.profile_delete_confirm, requireArguments().getString("name")))
setView(editText)
setPositiveButton(android.R.string.ok, null) // Set listener to null to prevent auto closing
setNegativeButton(android.R.string.cancel, null)
}.create()
- }
override fun onResume() {
super.onResume()
diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt
deleted file mode 100644
index f590d36..0000000
--- a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt
+++ /dev/null
@@ -1,298 +0,0 @@
-package im.angry.openeuicc.ui
-
-import android.annotation.SuppressLint
-import android.app.Dialog
-import android.content.DialogInterface
-import android.graphics.BitmapFactory
-import android.os.Bundle
-import android.text.Editable
-import android.util.Log
-import android.view.*
-import android.widget.ProgressBar
-import android.widget.TextView
-import android.widget.Toast
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.appcompat.app.AlertDialog
-import androidx.appcompat.widget.Toolbar
-import androidx.lifecycle.lifecycleScope
-import com.google.android.material.textfield.TextInputLayout
-import com.journeyapps.barcodescanner.ScanContract
-import com.journeyapps.barcodescanner.ScanOptions
-import im.angry.openeuicc.common.R
-import im.angry.openeuicc.service.EuiccChannelManagerService
-import im.angry.openeuicc.service.EuiccChannelManagerService.Companion.waitDone
-import im.angry.openeuicc.util.*
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-
-class ProfileDownloadFragment : BaseMaterialDialogFragment(),
- Toolbar.OnMenuItemClickListener, EuiccChannelFragmentMarker {
- companion object {
- const val TAG = "ProfileDownloadFragment"
-
- const val LOW_NVRAM_THRESHOLD = 30 * 1024 // < 30 KiB, the alert may fail
-
- fun newInstance(slotId: Int, portId: Int, finishWhenDone: Boolean = false): ProfileDownloadFragment =
- newInstanceEuicc(ProfileDownloadFragment::class.java, slotId, portId) {
- putBoolean("finishWhenDone", finishWhenDone)
- }
- }
-
- private lateinit var toolbar: Toolbar
- private lateinit var profileDownloadServer: TextInputLayout
- private lateinit var profileDownloadCode: TextInputLayout
- private lateinit var profileDownloadConfirmationCode: TextInputLayout
- private lateinit var profileDownloadIMEI: TextInputLayout
- private lateinit var profileDownloadFreeSpace: TextView
- private lateinit var progress: ProgressBar
-
- private var freeNvram: Int = -1
-
- private var downloading = false
-
- private val finishWhenDone by lazy {
- requireArguments().getBoolean("finishWhenDone", false)
- }
-
- private val barcodeScannerLauncher = registerForActivityResult(ScanContract()) { result ->
- result.contents?.let { content ->
- onScanResult(content)
- }
- }
-
- private val gallerySelectorLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { result ->
- if (result == null) return@registerForActivityResult
-
- lifecycleScope.launch(Dispatchers.IO) {
- runCatching {
- requireContext().contentResolver.openInputStream(result)?.let { input ->
- val bmp = BitmapFactory.decodeStream(input)
- input.close()
-
- decodeQrFromBitmap(bmp)?.let {
- withContext(Dispatchers.Main) {
- onScanResult(it)
- }
- }
-
- bmp.recycle()
- }
- }
- }
- }
-
- private fun onScanResult(result: String) {
- val components = result.split("$")
- if (components.size < 3 || components[0] != "LPA:1") return
- profileDownloadServer.editText?.setText(components[1])
- profileDownloadCode.editText?.setText(components[2])
- }
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- val view = inflater.inflate(R.layout.fragment_profile_download, container, false)
-
- toolbar = view.requireViewById(R.id.toolbar)
- profileDownloadServer = view.requireViewById(R.id.profile_download_server)
- profileDownloadCode = view.requireViewById(R.id.profile_download_code)
- profileDownloadConfirmationCode = view.requireViewById(R.id.profile_download_confirmation_code)
- profileDownloadIMEI = view.requireViewById(R.id.profile_download_imei)
- profileDownloadFreeSpace = view.requireViewById(R.id.profile_download_free_space)
- progress = view.requireViewById(R.id.progress)
-
- toolbar.inflateMenu(R.menu.fragment_profile_download)
-
- return view
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- toolbar.apply {
- setTitle(R.string.profile_download)
- setNavigationOnClickListener {
- if (!downloading) {
- dismiss()
- }
- }
- setOnMenuItemClickListener(this@ProfileDownloadFragment)
- }
- }
-
- override fun onMenuItemClick(item: MenuItem): Boolean = downloading ||
- when (item.itemId) {
- R.id.scan -> {
- barcodeScannerLauncher.launch(ScanOptions().apply {
- setDesiredBarcodeFormats(ScanOptions.QR_CODE)
- setOrientationLocked(false)
- })
- true
- }
- R.id.scan_from_gallery -> {
- gallerySelectorLauncher.launch("image/*")
- true
- }
- R.id.ok -> {
- if (freeNvram > LOW_NVRAM_THRESHOLD) {
- startDownloadProfile()
- } else {
- AlertDialog.Builder(requireContext()).apply {
- setTitle(R.string.profile_download_low_nvram_title)
- setMessage(R.string.profile_download_low_nvram_message)
- setIcon(android.R.drawable.ic_dialog_alert)
- setCancelable(true)
- setPositiveButton(android.R.string.ok) { _, _ ->
- startDownloadProfile()
- }
- setNegativeButton(android.R.string.cancel, null)
- show()
- }
- }
- true
- }
- else -> false
- }
-
- override fun onResume() {
- super.onResume()
- setWidthPercent(95)
- }
-
- @SuppressLint("MissingPermission")
- override fun onStart() {
- super.onStart()
-
- lifecycleScope.launch(Dispatchers.IO) {
- ensureEuiccChannelManager()
- if (euiccChannelManagerService.isForegroundTaskRunning) {
- withContext(Dispatchers.Main) {
- dismiss()
- }
- return@launch
- }
-
- withEuiccChannel { channel ->
- val imei = try {
- telephonyManager.getImei(channel.logicalSlotId) ?: ""
- } catch (e: Exception) {
- ""
- }
-
- // Fetch remaining NVRAM
- val str = channel.lpa.euiccInfo2?.freeNvram?.also {
- freeNvram = it
- }?.let { formatFreeSpace(it) }
-
- withContext(Dispatchers.Main) {
- profileDownloadFreeSpace.text = getString(
- R.string.profile_download_free_space,
- str ?: getText(R.string.unknown)
- )
- profileDownloadIMEI.editText!!.text =
- Editable.Factory.getInstance().newEditable(imei)
- }
- }
- }
- }
-
- override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
- return super.onCreateDialog(savedInstanceState).also {
- it.setCanceledOnTouchOutside(false)
- }
- }
-
- private fun startDownloadProfile() {
- val server = profileDownloadServer.editText!!.let {
- it.text.toString().trim().apply {
- if (isEmpty()) {
- it.requestFocus()
- return@startDownloadProfile
- }
- }
- }
-
- val code = profileDownloadCode.editText!!.text.toString().trim()
- .ifBlank { null }
- val confirmationCode = profileDownloadConfirmationCode.editText!!.text.toString().trim()
- .ifBlank { null }
- val imei = profileDownloadIMEI.editText!!.text.toString().trim()
- .ifBlank { null }
-
- downloading = true
-
- profileDownloadServer.editText!!.isEnabled = false
- profileDownloadCode.editText!!.isEnabled = false
- profileDownloadConfirmationCode.editText!!.isEnabled = false
- profileDownloadIMEI.editText!!.isEnabled = false
-
- progress.isIndeterminate = true
- progress.visibility = View.VISIBLE
-
- lifecycleScope.launch {
- ensureEuiccChannelManager()
- euiccChannelManagerService.waitForForegroundTask()
- val err = doDownloadProfile(server, code, confirmationCode, imei)
-
- if (err != null) {
- Log.d(TAG, "Error downloading profile")
- Log.d(TAG, Log.getStackTraceString(err))
-
- Toast.makeText(requireContext(), R.string.profile_download_failed, Toast.LENGTH_LONG).show()
- }
-
- if (parentFragment is EuiccProfilesChangedListener) {
- (parentFragment as EuiccProfilesChangedListener).onEuiccProfilesChanged()
- }
-
- try {
- dismiss()
- } catch (e: IllegalStateException) {
- // Ignored
- }
- }
- }
-
- private suspend fun doDownloadProfile(
- server: String,
- code: String?,
- confirmationCode: String?,
- imei: String?
- ) = withContext(Dispatchers.Main) {
- // The service is responsible for launching the actual blocking part on the IO context
- // On our side, we need the Main context because of the UI updates
- euiccChannelManagerService.launchProfileDownloadTask(
- slotId,
- portId,
- server,
- code,
- confirmationCode,
- imei
- ).onEach {
- if (it is EuiccChannelManagerService.ForegroundTaskState.InProgress) {
- progress.progress = it.progress
- progress.isIndeterminate = it.progress == 0
- } else {
- progress.progress = 100
- progress.isIndeterminate = false
- }
- }.waitDone()
- }
-
- override fun onDismiss(dialog: DialogInterface) {
- super.onDismiss(dialog)
- if (finishWhenDone) {
- activity?.finish()
- }
- }
-
- override fun onCancel(dialog: DialogInterface) {
- super.onCancel(dialog)
- if (finishWhenDone) {
- activity?.finish()
- }
- }
-}
\ No newline at end of file
diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/SettingsActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/SettingsActivity.kt
index 52e3272..bb299a3 100644
--- a/app-common/src/main/java/im/angry/openeuicc/ui/SettingsActivity.kt
+++ b/app-common/src/main/java/im/angry/openeuicc/ui/SettingsActivity.kt
@@ -4,10 +4,14 @@ import android.os.Bundle
import android.view.MenuItem
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
+import im.angry.openeuicc.OpenEuiccApplication
import im.angry.openeuicc.common.R
import im.angry.openeuicc.util.*
class SettingsActivity: AppCompatActivity() {
+ private val appContainer
+ get() = (application as OpenEuiccApplication).appContainer
+
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
@@ -15,8 +19,9 @@ class SettingsActivity: AppCompatActivity() {
setSupportActionBar(requireViewById(R.id.toolbar))
setupToolbarInsets()
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
+ val settingsFragment = appContainer.uiComponentFactory.createSettingsFragment()
supportFragmentManager.beginTransaction()
- .replace(R.id.settings_container, SettingsFragment())
+ .replace(R.id.settings_container, settingsFragment)
.commit()
}
diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/SettingsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/SettingsFragment.kt
index 6ad74c4..c2cbee3 100644
--- a/app-common/src/main/java/im/angry/openeuicc/ui/SettingsFragment.kt
+++ b/app-common/src/main/java/im/angry/openeuicc/ui/SettingsFragment.kt
@@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
-class SettingsFragment: PreferenceFragmentCompat() {
+open class SettingsFragment: PreferenceFragmentCompat() {
private lateinit var developerPref: PreferenceCategory
// Hidden developer options switch
@@ -35,9 +35,9 @@ class SettingsFragment: PreferenceFragmentCompat() {
// Show / hide developer preference based on whether it is enabled
lifecycleScope.launch {
- preferenceRepository.developerOptionsEnabledFlow.onEach {
- developerPref.isVisible = it
- }.collect()
+ preferenceRepository.developerOptionsEnabledFlow
+ .onEach { developerPref.isVisible = it }
+ .collect()
}
findPreference("pref_info_app_version")?.apply {
@@ -74,9 +74,6 @@ class SettingsFragment: PreferenceFragmentCompat() {
findPreference("pref_advanced_verbose_logging")
?.bindBooleanFlow(preferenceRepository.verboseLoggingFlow, PreferenceKeys.VERBOSE_LOGGING)
- findPreference("pref_developer_experimental_download_wizard")
- ?.bindBooleanFlow(preferenceRepository.experimentalDownloadWizardFlow, PreferenceKeys.EXPERIMENTAL_DOWNLOAD_WIZARD)
-
findPreference("pref_developer_unfiltered_profile_list")
?.bindBooleanFlow(preferenceRepository.unfilteredProfileListFlow, PreferenceKeys.UNFILTERED_PROFILE_LIST)
@@ -139,4 +136,22 @@ class SettingsFragment: PreferenceFragmentCompat() {
true
}
}
+
+ protected fun mergePreferenceOverlay(overlayKey: String, targetKey: String) {
+ val overlayCat = findPreference(overlayKey)!!
+ val targetCat = findPreference(targetKey)!!
+
+ val prefs = buildList {
+ for (i in 0..
+ if (uri == null) return@registerForActivityResult
+ requireActivity().contentResolver.openFileDescriptor(uri, "w")?.use {
+ FileOutputStream(it.fileDescriptor).use { os ->
+ os.write(diagnosticTextView.text.toString().encodeToByteArray())
+ }
+ }
+ }
+
override fun createNextFragment(): DownloadWizardActivity.DownloadWizardStepFragment? = null
override fun createPrevFragment(): DownloadWizardActivity.DownloadWizardStepFragment? = null
@@ -26,7 +40,15 @@ class DownloadWizardDiagnosticsFragment : DownloadWizardActivity.DownloadWizardS
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_download_diagnostics, container, false)
- diagnosticTextView = view.requireViewById(R.id.download_wizard_diagnostics_text)
+ view.requireViewById(R.id.download_wizard_diagnostics_save).setOnClickListener {
+ saveDiagnostics.launch(
+ getString(
+ R.string.download_wizard_diagnostics_file_template,
+ SimpleDateFormat.getDateTimeInstance().format(Date())
+ )
+ )
+ }
+ diagnosticTextView = view.requireViewById(R.id.download_wizard_diagnostics_text)
return view
}
@@ -44,6 +66,14 @@ class DownloadWizardDiagnosticsFragment : DownloadWizardActivity.DownloadWizardS
private fun buildDiagnosticsText(): String? = state.downloadError?.let { err ->
val ret = StringBuilder()
+ ret.appendLine(
+ getString(
+ R.string.download_wizard_diagnostics_error_code,
+ err.lpaErrorReason
+ )
+ )
+ ret.appendLine()
+
err.lastHttpResponse?.let { resp ->
if (resp.rcode != 200) {
// Only show the status if it's not 200
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 f6f63fd..1b816d4 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
@@ -113,18 +113,19 @@ class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStep
is EuiccChannelManagerService.ForegroundTaskState.Done -> {
hideProgressBar()
- // Change the state of the last InProgress item to Error
+ state.downloadError =
+ it.error as? LocalProfileAssistant.ProfileDownloadException
+
+ // Change the state of the last InProgress item to success (or error)
progressItems.forEachIndexed { index, progressItem ->
if (progressItem.state == ProgressState.InProgress) {
- progressItem.state = ProgressState.Error
+ progressItem.state =
+ if (state.downloadError == null) ProgressState.Done else ProgressState.Error
}
adapter.notifyItemChanged(index)
}
- state.downloadError =
- it.error as? LocalProfileAssistant.ProfileDownloadException
-
isDone = true
refreshButtons()
}
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 c9a9e0f..b268b62 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
@@ -7,6 +7,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.TextView
+import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
@@ -20,6 +21,11 @@ import kotlinx.coroutines.launch
import net.typeblog.lpac_jni.LocalProfileInfo
class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardStepFragment() {
+ companion object {
+ const val LOW_NVRAM_THRESHOLD =
+ 30 * 1024 // < 30 KiB, alert about potential download failure
+ }
+
private data class SlotInfo(
val logicalSlotId: Int,
val isRemovable: Boolean,
@@ -45,6 +51,21 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt
override fun createPrevFragment(): DownloadWizardActivity.DownloadWizardStepFragment? = null
+ override fun beforeNext() {
+ super.beforeNext()
+
+ if (adapter.selected.freeSpace < LOW_NVRAM_THRESHOLD) {
+ AlertDialog.Builder(requireContext()).apply {
+ setTitle(R.string.profile_download_low_nvram_title)
+ setMessage(R.string.profile_download_low_nvram_message)
+ setCancelable(true)
+ setPositiveButton(android.R.string.ok, null)
+ setNegativeButton(android.R.string.cancel, null)
+ show()
+ }
+ }
+ }
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -165,6 +186,9 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt
var slots: List = listOf()
var currentSelectedIdx = -1
+ val selected: SlotInfo
+ 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)
return SlotItemHolder(root)
diff --git a/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt b/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt
index 807706e..e768fa9 100644
--- a/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt
+++ b/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt
@@ -31,7 +31,6 @@ object PreferenceKeys {
// ---- Developer Options ----
val DEVELOPER_OPTIONS_ENABLED = booleanPreferencesKey("developer_options_enabled")
- val EXPERIMENTAL_DOWNLOAD_WIZARD = booleanPreferencesKey("experimental_download_wizard")
val UNFILTERED_PROFILE_LIST = booleanPreferencesKey("unfiltered_profile_list")
val IGNORE_TLS_CERTIFICATE = booleanPreferencesKey("ignore_tls_certificate")
}
@@ -49,7 +48,6 @@ class PreferenceRepository(private val context: Context) {
// ---- Developer Options ----
val developerOptionsEnabledFlow = bindFlow(PreferenceKeys.DEVELOPER_OPTIONS_ENABLED, false)
- val experimentalDownloadWizardFlow = bindFlow(PreferenceKeys.EXPERIMENTAL_DOWNLOAD_WIZARD, false)
val unfilteredProfileListFlow = bindFlow(PreferenceKeys.UNFILTERED_PROFILE_LIST, false)
val ignoreTLSCertificateFlow = bindFlow(PreferenceKeys.IGNORE_TLS_CERTIFICATE, false)
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 ca36d64..3f58844 100644
--- a/app-common/src/main/res/layout/fragment_download_details.xml
+++ b/app-common/src/main/res/layout/fragment_download_details.xml
@@ -16,10 +16,10 @@
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="20sp"
- android:layout_marginTop="20sp"
- android:layout_marginBottom="20sp"
- android:layout_marginStart="60sp"
- android:layout_marginEnd="60sp"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="20dp"
+ android:layout_marginStart="60dp"
+ android:layout_marginEnd="60dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constrainedWidth="true"
diff --git a/app-common/src/main/res/layout/fragment_download_diagnostics.xml b/app-common/src/main/res/layout/fragment_download_diagnostics.xml
index b9a0bc2..88b1ffb 100644
--- a/app-common/src/main/res/layout/fragment_download_diagnostics.xml
+++ b/app-common/src/main/res/layout/fragment_download_diagnostics.xml
@@ -17,15 +17,26 @@
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="20sp"
- android:layout_marginTop="20sp"
- android:layout_marginBottom="20sp"
- android:layout_marginStart="60sp"
- android:layout_marginEnd="60sp"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="20dp"
+ android:layout_marginStart="60dp"
+ android:layout_marginEnd="60dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toTopOf="parent" />
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app-common/src/main/res/menu/fragment_profile_download.xml b/app-common/src/main/res/menu/fragment_profile_download.xml
deleted file mode 100644
index f93ae8d..0000000
--- a/app-common/src/main/res/menu/fragment_profile_download.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app-common/src/main/res/values-ja/strings.xml b/app-common/src/main/res/values-ja/strings.xml
index fed185d..d25af49 100644
--- a/app-common/src/main/res/values-ja/strings.xml
+++ b/app-common/src/main/res/values-ja/strings.xml
@@ -37,11 +37,6 @@
アクティベーションコード
確認コード (オプション)
IMEI (オプション)
- 残りの容量: %s
- QR コードをスキャン
- ギャラリーから QR コードをスキャン
- ダウンロード
- eSIM のダウンロードに失敗しました。アクティベーションまたは QR コードを確認してください。
ダウンロードに失敗する可能性があります
残り容量が少ないため、ダウンロードに失敗する可能性があります。
ダウンロードウィザード
@@ -53,7 +48,6 @@
リムーバブル
内部
内部 - ポート: %d
- eID:
有効なプロファイル:
空き容量:
eSIM プロファイルをどの方法でダウンロードしますか?
@@ -68,6 +62,7 @@
eSIM プロファイルをダウンロード中です
eSIM プロファイルをストレージに読み込み中です
エラー診断
+ エラーコード: %s
最終の HTTP ステータス (サーバー): %d
最終の HTTP レスポンス (サーバー):
最終の HTTP 例外:
@@ -75,6 +70,8 @@
最終の APDU レスポンス (SIM) は成功しました
最終の APDU レスポンス (SIM) は失敗しました
最終の APDU 例外:
+ 保存
+ %s のエラー診断
新しいニックネーム
%s のプロファイルを削除してもよろしいですか?この操作は元に戻せません。
削除を確認するには「%s」を入力してください
@@ -92,11 +89,10 @@
eUICC 情報 (%s)
アクセスモード
リムーバブル
- EID
eUICC OS のバージョン
グローバルプラットフォームのバージョン
SAS 認定番号
- 保護されたプロファイルのバージョン
+ Protected Profileのバージョン
NVRAM の空き容量 (eSIM プロファイルストレージ)
GSMA プロダクション証明書
GSMA テスト証明書
@@ -125,8 +121,6 @@
ログ
アプリの最新デバッグログを表示します
開発者オプション
- 実験的なダウンロードウィザード
- 実験的な新しいダウンロードウィザードを有効化します。まだ完全に機能していないことにご注意ください。
SM-DP+ TLS 証明書を無視する
SM-DP+ TLS 証明書を無視して任意の RSP を許可します
情報
diff --git a/app-common/src/main/res/values-zh-rCN/strings.xml b/app-common/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..3bb0d04
--- /dev/null
+++ b/app-common/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,137 @@
+
+
+ 在此设备上未检测到此应用程序可访问的可插拔 eUICC 卡。请插入兼容卡或 USB 读卡器。
+ 此 eSIM 上还没有配置文件
+ 未知
+ 帮助
+ 重新加载卡槽
+ 逻辑卡槽 %d
+ 已启用
+ 已禁用
+ 提供商:
+ 类型:
+ 启用
+ 禁用
+ 删除
+ 重命名
+ 等待 eSIM 芯片切换配置文件时超时。这可能是您手机基带固件中的一个错误。请尝试切换飞行模式、重新启动应用程序或重新启动手机
+ 操作成功, 但是您手机的基带拒绝刷新。您可能需要切换飞行模式或重新启动,以便使用新的配置文件。
+ 无法切换到新的 eSIM 配置文件。
+ 昵称不能超过 64 个字符
+ 已复制 ICCID 到剪贴板
+ 选择卡槽
+ 选择
+ 授予 USB 权限
+ 需要获得访问 USB 智能卡读卡器的权限。
+ 无法通过 USB 智能卡读卡器连接到 eSIM。
+ 长时间运行的后台任务
+ 正在下载 eSIM 配置文件
+ 无法下载 eSIM 配置文件
+ 正在重命名 eSIM 配置文件
+ 无法重命名 eSIM 配置文件
+ 正在删除 eSIM 配置文件
+ 无法删除 eSIM 配置文件
+ 正在切换 eSIM 配置文件
+ 无法切换 eSIM 配置文件
+ 添加新 eSIM
+ 服务器 (RSP / SM-DP+)
+ 激活码
+ 确认码 (可选)
+ IMEI (可选)
+ 本次下载可能会失败
+ 当前芯片的剩余空间不足,可能导致配置下载失败。\n是否继续下载?
+ 新昵称
+ 您确定要删除 %s 吗?此操作是不可逆的。
+ 请输入\'%s\'以确认删除
+ 通知列表
+ 通知列表 (%s)
+ 管理通知
+ eSIM 配置文件可以在下载、删除、启用或禁用时向运营商发送通知。此处列出了要发送的这些通知的队列。\n\n在\"设置\"中,您可以指定是否自动发送每种类型的通知。请注意,即使通知已发送,也不会自动从记录中删除,除非队列空间不足。\n\n在这里,您可以手动发送或删除每个待处理的通知。
+ 已下载
+ 已删除
+ 已启用
+ 已禁用
+ 处理
+ 删除
+ 保存日志
+ %s 的日志
+ 设置
+ 通知
+ 操作 eSIM 配置文件会向运营商发送通知。根据需要在此处微调此行为。
+ 下载
+ 发送 下载 配置文件的通知
+ 删除
+ 发送 删除 配置文件的通知
+ 切换
+ 发送 切换 配置文件的通知\n注意,这种类型的通知是不可靠的。
+ 高级
+ 允许 禁用/删除 已启用的配置文件
+ 默认情况下,此应用程序会阻止您禁用可插拔 eSIM 中已启用的配置文件。\n因为这样做 有时 会使其无法访问。\n勾选此框以 移除 此保护措施。
+ 记录详细日志
+ 详细日志中包含敏感信息,开启此功能后请仅与你信任的人共享你的日志。
+ 日志
+ 查看应用程序的最新调试日志
+ 信息
+ App 版本
+ 源码
+ 测试
+ 准备中
+ 可用
+ 下载向导
+ 返回
+ 下一步
+ 请选择或确认下载目标 eSIM 卡槽:
+ 逻辑卡槽 %d
+ 类型:
+ 可插拔
+ 内置
+ 内置, 端口 %d
+ 当前配置文件:
+ 剩余空间:
+ 您想要如何下载 eSIM 配置文件?
+ 用相机扫描二维码
+ 从图库选择二维码
+ 手动输入
+ 请输入或确认下载 eSIM 的详细信息:
+ 正在下载您的 eSIM...
+ 准备中
+ 正在连接服务器
+ 正在向服务器认证您的设备
+ 正在下载 eSIM 配置文件
+ 正在写入 eSIM 配置文件
+ 错误诊断
+ 错误代码: %s
+ 上次 HTTP 状态码 (来自服务器): %d
+ 上次 HTTP 应答 (来自服务器):
+ 上次 HTTP 错误:
+ 上次 APDU 应答 (来自 SIM): %s
+ 上次 APDU 应答 (来自 SIM) 是成功的
+ 上次 APDU 应答 (来自 SIM) 是失败的
+ 上次 APDU 错误:
+ 保存
+ %s 的错误诊断
+ eUICC 详情
+ eUICC 详情 (%s)
+ 访问方式
+ 可插拔
+ eUICC OS 版本
+ GlobalPlatform 版本
+ SAS 认证号码
+ Protected Profile 版本
+ NVRAM 剩余空间 (eSIM 存储容量)
+ GSMA 生产环境证书
+ GSMA 测试环境证书
+ 兼容
+ 不兼容
+ 是
+ 否
+ 还有 %d 步成为开发者
+ 你现在是开发者了!
+ 语言
+ 选择 App 语言
+ 开发者选项
+ 显示未经过滤的配置文件列表
+ 在配置文件列表中包括非生产环境的配置文件
+ 无视 SM-DP+ 的 TLS 证书
+ 允许 RSP 服务器使用任意证书
+
\ No newline at end of file
diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml
index a5a05ab..4a9f529 100644
--- a/app-common/src/main/res/values/strings.xml
+++ b/app-common/src/main/res/values/strings.xml
@@ -53,11 +53,6 @@
Activation Code
Confirmation Code (Optional)
IMEI (Optional)
- Space remaining: %s
- Scan QR Code
- Scan QR Code from Gallery
- Download
- Failed to download eSIM. Check your activation / QR code.
This download may fail
This download may fail due to low remaining capacity.
@@ -71,7 +66,7 @@
Removable
Internal
Internal, port %d
- eID:
+ eID:
Active Profile:
Free Space:
How would you like to download the eSIM profile?
@@ -86,6 +81,7 @@
Downloading eSIM profile
Loading eSIM profile into storage
Error diagnostics
+ Error code: %s
Last HTTP status (from server): %d
Last HTTP response (from server):
Last HTTP exception:
@@ -93,6 +89,8 @@
Last APDU response (from SIM) is successful
Last APDU response (from SIM) is a failure
Last APDU exception:
+ Save
+ Diagnostics at %s
New nickname
@@ -116,7 +114,7 @@
eUICC Info (%s)
Access Mode
Removable
- EID
+ EID
eUICC OS Version
GlobalPlatform Version
SAS Accreditation Number
@@ -156,12 +154,10 @@
Logs
View recent debug logs of the application
Developer Options
- Experimental Download Wizard
- Enable the experimental new download wizard. Note that it is not fully working yet.
Show unfiltered profile list
Include non-production profiles in the list
Ignore SM-DP+ TLS certificate
- Ignore SM-DP+ TLS certificate, allow any RSP
+ Accept any TLS certificate used by the RSP server
Info
App Version
Source Code
diff --git a/app-common/src/main/res/xml/locale_config.xml b/app-common/src/main/res/xml/locale_config.xml
index dd9d189..e1a13f8 100644
--- a/app-common/src/main/res/xml/locale_config.xml
+++ b/app-common/src/main/res/xml/locale_config.xml
@@ -2,4 +2,5 @@
+
\ No newline at end of file
diff --git a/app-common/src/main/res/xml/pref_settings.xml b/app-common/src/main/res/xml/pref_settings.xml
index 52815b9..1da1fd4 100644
--- a/app-common/src/main/res/xml/pref_settings.xml
+++ b/app-common/src/main/res/xml/pref_settings.xml
@@ -57,12 +57,6 @@
app:title="@string/pref_developer"
app:iconSpaceReserved="false">
-
-
("pref_info_ara_m")?.apply {
+ summary = firstSigner.encodeHex()
+ setOnPreferenceClickListener {
+ requireContext().getSystemService(ClipboardManager::class.java)!!
+ .setPrimaryClip(ClipData.newPlainText("ara-m", summary))
+ Toast.makeText(requireContext(), R.string.toast_ara_m_copied, Toast.LENGTH_SHORT)
+ .show()
+ true
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app-unpriv/src/main/res/values-ja/strings.xml b/app-unpriv/src/main/res/values-ja/strings.xml
index b8fac39..053a8d1 100644
--- a/app-unpriv/src/main/res/values-ja/strings.xml
+++ b/app-unpriv/src/main/res/values-ja/strings.xml
@@ -30,4 +30,5 @@
挿入された取り外し可能な eSIM がデバイス上で管理できるかどうかは判断できません。デバイスが OMAPI のサポートを宣言していないため、このデバイス上で取り外し可能な eSIM を管理することはサポートされていない可能性があります。\n%s
挿入された取り外し可能な eSIM がデバイス上で管理できるかどうかを確認できません。\n%s
ただし、eSIM プロファイルがすでに読み込まれている場合、有効化されたプロファイル自体は引き続き機能します。また、プロファイルが管理できない場合は、このデバイスで USB カードリーダーを介してプロファイルを管理できる可能性があります。
+ ARA-M SHA-1 をクリップボードにコピーしました
diff --git a/app-unpriv/src/main/res/values-zh-rCN/strings.xml b/app-unpriv/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..8d3060d
--- /dev/null
+++ b/app-unpriv/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,32 @@
+
+ 兼容性检查
+ 打开 SIM 卡应用程序
+ 系统功能
+ 您的设备是否具有管理可插拔 eUICC 卡所需的所有功能。例如,基本的电话功能和 OMAPI 支持。
+ 您的设备没有电话功能。
+ 您的设备/系统未声明支持 OMAPI。这可能是由于缺少硬件支持,或者可能仅仅是由于缺少标志。请参阅以下两项检查以确定 OMAPI 是否确实受支持。
+ OMAPI 连接
+ 您的设备是否允许通过 OMAPI 访问 SIM 卡上的安全元件?
+ 无法通过 OMAPI 检测到 SIM 卡的 Secure Element。如果您尚未在此设备中插入 SIM 卡,请尝试插入一张 SIM 卡并重试此检查。
+ 已成功检测到可访问 Secure Element 的卡槽,但仅限于以下 SIM 卡槽:SIM%s。
+ ISD-R 通道访问
+ 您的设备是否支持通过 OMAPI 打开 eSIM 的 ISD-R (管理) 通道?
+ 无法确定是否支持通过 OMAPI 进行 ISD-R 访问。如果尚未插入,您可能需要插入 SIM 卡 (任何 SIM 卡都可以) 重试。
+ OMAPI 只能在以下 SIM 插槽上访问 ISD-R:SIM%s。
+ 不在已知的 BUG 名单中
+ 确保您的设备不存在与可插拔 eSIM 相关的错误。
+ 糟糕,您的设备在访问可插拔 eSIM 时存在错误。这并不表示完全无法使用,但我们不保证该应用在您设备上的行为。
+ USB 读卡器支持
+ 您的设备是否支持通过 USB 读卡器管理 eSIM?
+ 您可以通过此设备上的标准 USB CCID 读取器管理 eSIM (即使您在这里有任何其他检查项失败)。请插入读卡器,然后打开此应用程序以这种方式管理 eSIM。
+ 您的设备不支持 USB 读卡器。
+ 结论 (USB 读卡器以外)
+ 根据之前的所有检查,您的设备与可插拔 eSIM 卡兼容的可能性有多大?
+ 您可以使用和管理插入此设备的可插拔 eSIM 卡。
+ 已知您的设备在访问可插拔 eSIM 卡时存在问题。\n%s
+ 我们无法确定是否可以在您的设备上管理可插拔 eSIM 卡。不过,您的设备确实声明支持 OMAPI,因此它工作的可能性略高。\n%s
+ 我们无法确定是否可以在您的设备上管理可插拔 eSIM 卡。由于您的设备未声明支持OMAPI,因此更有可能不支持在此设备上管理可插拔 eSIM。\n%s
+ 我们无法确定是否可以在您的设备上管理可插拔 eSIM 卡。\n%s
+ 然而,已经加载了eSIM配置文件的可插拔 eSIM 卡仍然可以工作; 即使无法在装置上直接管理可插拔 eSIM 卡中的配置文件,您仍然可以使用 USB 卡读卡器来管理配置文件。
+ ARA-M SHA-1 已拷贝到剪贴板
+
\ No newline at end of file
diff --git a/app-unpriv/src/main/res/values/strings.xml b/app-unpriv/src/main/res/values/strings.xml
index 3cf7347..9d80b0e 100644
--- a/app-unpriv/src/main/res/values/strings.xml
+++ b/app-unpriv/src/main/res/values/strings.xml
@@ -4,6 +4,12 @@
Compatibility Check
Open SIM Toolkit
+
+ ARA-M SHA-1
+
+
+ ARA-M SHA-1 copied to clipboard
+
System Features
Whether your device has all the required features for managing removable eUICC cards. For example, basic telephony and OMAPI support.
diff --git a/app-unpriv/src/main/res/xml/pref_unprivileged_settings.xml b/app-unpriv/src/main/res/xml/pref_unprivileged_settings.xml
new file mode 100644
index 0000000..3281caf
--- /dev/null
+++ b/app-unpriv/src/main/res/xml/pref_unprivileged_settings.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
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 d626333..3c522c5 100644
--- a/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt
+++ b/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt
@@ -110,7 +110,7 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
telephonyManager.simSlotMapping = mappings
return
} catch (_: Exception) {
-
+ // ignore
}
// Sometimes hardware supports one ordering but not the reverse
diff --git a/app/src/main/java/im/angry/openeuicc/ui/LuiActivity.kt b/app/src/main/java/im/angry/openeuicc/ui/LuiActivity.kt
index d7ac213..de2ca24 100644
--- a/app/src/main/java/im/angry/openeuicc/ui/LuiActivity.kt
+++ b/app/src/main/java/im/angry/openeuicc/ui/LuiActivity.kt
@@ -8,6 +8,7 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import im.angry.openeuicc.R
+import im.angry.openeuicc.ui.wizard.DownloadWizardActivity
class LuiActivity : AppCompatActivity() {
override fun onStart() {
@@ -25,10 +26,11 @@ class LuiActivity : AppCompatActivity() {
}
requireViewById(R.id.lui_skip).setOnClickListener { finish() }
- // TODO: Deactivate LuiActivity if there is no eSIM found.
+ // TODO: Deactivate DownloadWizardActivity if there is no eSIM found.
// TODO: Support pre-filled download info (from carrier apps); UX
requireViewById(R.id.lui_download).setOnClickListener {
- startActivity(Intent(this, DirectProfileDownloadActivity::class.java))
+ startActivity(Intent(this, DownloadWizardActivity::class.java))
+ finish()
}
}
}
\ No newline at end of file
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 688ae6c..12b60bd 100644
--- a/app/src/main/java/im/angry/openeuicc/ui/PrivilegedEuiccManagementFragment.kt
+++ b/app/src/main/java/im/angry/openeuicc/ui/PrivilegedEuiccManagementFragment.kt
@@ -17,19 +17,16 @@ class PrivilegedEuiccManagementFragment: EuiccManagementFragment() {
private var isMEP = false
private var isRemovable = false
- override suspend fun doRefresh() {
- super.doRefresh()
- withEuiccChannel { channel ->
- isMEP = channel.isMEP
- isRemovable = channel.port.card.isRemovable
- }
- }
-
override suspend fun onCreateFooterViews(
parent: ViewGroup,
profiles: List
): List =
super.onCreateFooterViews(parent, profiles).let { footers ->
+ withEuiccChannel { channel ->
+ isMEP = channel.isMEP
+ isRemovable = channel.port.card.isRemovable
+ }
+
if (isMEP) {
val view = layoutInflater.inflate(R.layout.footer_mep, parent, false)
view.requireViewById