浏览代码

ui: Switch completely to the new download flow

...and delete the old ProfileDownloadFragment
Peter Cai 1 年之前
父节点
当前提交
2d66c1f334

+ 3 - 11
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)
             }
         }
     }

+ 0 - 298
app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt

@@ -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()
-        }
-    }
-}

+ 0 - 3
app-common/src/main/java/im/angry/openeuicc/ui/SettingsFragment.kt

@@ -74,9 +74,6 @@ class SettingsFragment: PreferenceFragmentCompat() {
         findPreference<CheckBoxPreference>("pref_advanced_verbose_logging")
             ?.bindBooleanFlow(preferenceRepository.verboseLoggingFlow, PreferenceKeys.VERBOSE_LOGGING)
 
-        findPreference<CheckBoxPreference>("pref_developer_experimental_download_wizard")
-            ?.bindBooleanFlow(preferenceRepository.experimentalDownloadWizardFlow, PreferenceKeys.EXPERIMENTAL_DOWNLOAD_WIZARD)
-
         findPreference<CheckBoxPreference>("pref_developer_unfiltered_profile_list")
             ?.bindBooleanFlow(preferenceRepository.unfilteredProfileListFlow, PreferenceKeys.UNFILTERED_PROFILE_LIST)
 

+ 0 - 2
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)
 

+ 0 - 126
app-common/src/main/res/layout/fragment_profile_download.xml

@@ -1,126 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="?attr/colorSurface">
-
-    <com.google.android.material.appbar.MaterialToolbar
-        android:id="@+id/toolbar"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintWidth_percent="1"
-        app:navigationIcon="?homeAsUpIndicator" />
-
-    <View
-        android:id="@+id/guideline"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:orientation="vertical"
-        android:visibility="invisible"
-        app:layout_constraintBottom_toBottomOf="@id/toolbar"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent" />
-
-    <ProgressBar
-        android:id="@+id/progress"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:visibility="gone"
-        app:layout_constraintTop_toBottomOf="@id/toolbar"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/guideline"
-        style="@style/Widget.AppCompat.ProgressBar.Horizontal" />
-
-    <com.google.android.material.textfield.TextInputLayout
-        android:id="@+id/profile_download_server"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="15dp"
-        android:hint="@string/profile_download_server"
-        app:layout_constraintTop_toBottomOf="@id/toolbar"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintWidth_percent=".8">
-
-        <com.google.android.material.textfield.TextInputEditText
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-
-    </com.google.android.material.textfield.TextInputLayout>
-
-    <com.google.android.material.textfield.TextInputLayout
-        android:id="@+id/profile_download_code"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginVertical="15dp"
-        android:hint="@string/profile_download_code"
-        app:layout_constraintTop_toBottomOf="@id/profile_download_server"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintWidth_percent=".8"
-        app:passwordToggleEnabled="true">
-
-        <com.google.android.material.textfield.TextInputEditText
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:inputType="textPassword" />
-
-    </com.google.android.material.textfield.TextInputLayout>
-
-    <com.google.android.material.textfield.TextInputLayout
-        android:id="@+id/profile_download_confirmation_code"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginVertical="15dp"
-        android:hint="@string/profile_download_confirmation_code"
-        app:layout_constraintTop_toBottomOf="@id/profile_download_code"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintWidth_percent=".8"
-        app:passwordToggleEnabled="true">
-
-        <com.google.android.material.textfield.TextInputEditText
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:inputType="textPassword" />
-
-    </com.google.android.material.textfield.TextInputLayout>
-
-    <com.google.android.material.textfield.TextInputLayout
-        android:id="@+id/profile_download_imei"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="15dp"
-        android:layout_marginBottom="6dp"
-        android:hint="@string/profile_download_imei"
-        app:layout_constraintTop_toBottomOf="@id/profile_download_confirmation_code"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/profile_download_free_space"
-        app:layout_constraintWidth_percent=".8"
-        app:passwordToggleEnabled="true">
-
-        <com.google.android.material.textfield.TextInputEditText
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:inputType="textPassword" />
-
-    </com.google.android.material.textfield.TextInputLayout>
-
-    <TextView
-        android:id="@+id/profile_download_free_space"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:gravity="center"
-        android:textSize="11sp"
-        android:layout_marginBottom="4dp"
-        app:layout_constraintTop_toBottomOf="@id/profile_download_imei"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>

+ 0 - 21
app-common/src/main/res/menu/fragment_profile_download.xml

@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
-    <item
-        android:id="@+id/scan"
-        android:icon="@drawable/ic_scan_black"
-        android:title="@string/profile_download_scan"
-        app:showAsAction="ifRoom"/>
-
-    <item
-        android:id="@+id/scan_from_gallery"
-        android:icon="@drawable/ic_gallery_black"
-        android:title="@string/profile_download_scan_from_gallery"
-        app:showAsAction="ifRoom" />
-
-    <item
-        android:id="@+id/ok"
-        android:icon="@drawable/ic_check_black"
-        android:title="@string/profile_download_ok"
-        app:showAsAction="always"/>
-</menu>

+ 0 - 7
app-common/src/main/res/values-ja/strings.xml

@@ -37,11 +37,6 @@
     <string name="profile_download_code">アクティベーションコード</string>
     <string name="profile_download_confirmation_code">確認コード (オプション)</string>
     <string name="profile_download_imei">IMEI (オプション)</string>
-    <string name="profile_download_free_space">残りの容量: %s</string>
-    <string name="profile_download_scan">QR コードをスキャン</string>
-    <string name="profile_download_scan_from_gallery">ギャラリーから QR コードをスキャン</string>
-    <string name="profile_download_ok">ダウンロード</string>
-    <string name="profile_download_failed">eSIM のダウンロードに失敗しました。アクティベーションまたは QR コードを確認してください。</string>
     <string name="profile_download_low_nvram_title">ダウンロードに失敗する可能性があります</string>
     <string name="profile_download_low_nvram_message">残り容量が少ないため、ダウンロードに失敗する可能性があります。</string>
     <string name="download_wizard">ダウンロードウィザード</string>
@@ -128,8 +123,6 @@
     <string name="pref_advanced_logs">ログ</string>
     <string name="pref_advanced_logs_desc">アプリの最新デバッグログを表示します</string>
     <string name="pref_developer">開発者オプション</string>
-    <string name="pref_developer_experimental_download_wizard">実験的なダウンロードウィザード</string>
-    <string name="pref_developer_experimental_download_wizard_desc">実験的な新しいダウンロードウィザードを有効化します。まだ完全に機能していないことにご注意ください。</string>
     <string name="pref_developer_ignore_tls_certificate">SM-DP+ TLS 証明書を無視する</string>
     <string name="pref_developer_ignore_tls_certificate_desc">SM-DP+ TLS 証明書を無視して任意の RSP を許可します</string>
     <string name="pref_info">情報</string>

+ 0 - 7
app-common/src/main/res/values/strings.xml

@@ -53,11 +53,6 @@
     <string name="profile_download_code">Activation Code</string>
     <string name="profile_download_confirmation_code">Confirmation Code (Optional)</string>
     <string name="profile_download_imei">IMEI (Optional)</string>
-    <string name="profile_download_free_space">Space remaining: %s</string>
-    <string name="profile_download_scan">Scan QR Code</string>
-    <string name="profile_download_scan_from_gallery">Scan QR Code from Gallery</string>
-    <string name="profile_download_ok">Download</string>
-    <string name="profile_download_failed">Failed to download eSIM. Check your activation / QR code.</string>
 
     <string name="profile_download_low_nvram_title">This download may fail</string>
     <string name="profile_download_low_nvram_message">This download may fail due to low remaining capacity.</string>
@@ -159,8 +154,6 @@
     <string name="pref_advanced_logs">Logs</string>
     <string name="pref_advanced_logs_desc">View recent debug logs of the application</string>
     <string name="pref_developer">Developer Options</string>
-    <string name="pref_developer_experimental_download_wizard">Experimental Download Wizard</string>
-    <string name="pref_developer_experimental_download_wizard_desc">Enable the experimental new download wizard. Note that it is not fully working yet.</string>
     <string name="pref_developer_unfiltered_profile_list">Show unfiltered profile list</string>
     <string name="pref_developer_unfiltered_profile_list_desc">Include non-production profiles in the list</string>
     <string name="pref_developer_ignore_tls_certificate">Ignore SM-DP+ TLS certificate</string>

+ 0 - 6
app-common/src/main/res/xml/pref_settings.xml

@@ -57,12 +57,6 @@
         app:title="@string/pref_developer"
         app:iconSpaceReserved="false">
 
-        <CheckBoxPreference
-            app:key="pref_developer_experimental_download_wizard"
-            app:iconSpaceReserved="false"
-            app:title="@string/pref_developer_experimental_download_wizard"
-            app:summary="@string/pref_developer_experimental_download_wizard_desc" />
-
         <CheckBoxPreference
             app:iconSpaceReserved="false"
             app:key="pref_developer_unfiltered_profile_list"