ProfileDownloadFragment.kt 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package im.angry.openeuicc.ui
  2. import android.app.Dialog
  3. import android.os.Bundle
  4. import android.util.Log
  5. import android.view.*
  6. import android.widget.ProgressBar
  7. import android.widget.Toast
  8. import androidx.appcompat.widget.Toolbar
  9. import androidx.fragment.app.DialogFragment
  10. import androidx.lifecycle.lifecycleScope
  11. import com.google.android.material.textfield.TextInputLayout
  12. import com.journeyapps.barcodescanner.ScanContract
  13. import com.journeyapps.barcodescanner.ScanOptions
  14. import com.truphone.lpa.progress.DownloadProgress
  15. import im.angry.openeuicc.R
  16. import im.angry.openeuicc.util.setWidthPercent
  17. import kotlinx.coroutines.Dispatchers
  18. import kotlinx.coroutines.launch
  19. import kotlinx.coroutines.withContext
  20. import java.lang.Exception
  21. class ProfileDownloadFragment : DialogFragment(), EuiccFragmentMarker, Toolbar.OnMenuItemClickListener {
  22. companion object {
  23. const val TAG = "ProfileDownloadFragment"
  24. fun newInstance(slotId: Int): ProfileDownloadFragment =
  25. newInstanceEuicc(ProfileDownloadFragment::class.java, slotId)
  26. }
  27. private lateinit var toolbar: Toolbar
  28. private lateinit var profileDownloadServer: TextInputLayout
  29. private lateinit var profileDownloadCode: TextInputLayout
  30. private lateinit var progress: ProgressBar
  31. private var downloading = false
  32. private val barcodeScannerLauncher = registerForActivityResult(ScanContract()) { result ->
  33. result.contents?.let { content ->
  34. Log.d(TAG, content)
  35. val components = content.split("$")
  36. if (components.size < 3 || components[0] != "LPA:1") return@registerForActivityResult
  37. profileDownloadServer.editText?.setText(components[1])
  38. profileDownloadCode.editText?.setText(components[2])
  39. }
  40. }
  41. override fun onCreateView(
  42. inflater: LayoutInflater,
  43. container: ViewGroup?,
  44. savedInstanceState: Bundle?
  45. ): View {
  46. val view = inflater.inflate(R.layout.fragment_profile_download, container, false)
  47. toolbar = view.findViewById(R.id.toolbar)
  48. profileDownloadServer = view.findViewById(R.id.profile_download_server)
  49. profileDownloadCode = view.findViewById(R.id.profile_download_code)
  50. progress = view.findViewById(R.id.progress)
  51. return view
  52. }
  53. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  54. super.onViewCreated(view, savedInstanceState)
  55. toolbar.apply {
  56. setTitle(R.string.profile_download)
  57. setNavigationOnClickListener {
  58. if (!downloading) dismiss()
  59. }
  60. setOnMenuItemClickListener(this@ProfileDownloadFragment)
  61. }
  62. }
  63. override fun onMenuItemClick(item: MenuItem): Boolean = downloading ||
  64. when (item.itemId) {
  65. R.id.scan -> {
  66. barcodeScannerLauncher.launch(ScanOptions().apply {
  67. setDesiredBarcodeFormats(ScanOptions.QR_CODE)
  68. setOrientationLocked(false)
  69. })
  70. true
  71. }
  72. R.id.ok -> {
  73. startDownloadProfile()
  74. true
  75. }
  76. else -> false
  77. }
  78. override fun onResume() {
  79. super.onResume()
  80. setWidthPercent(95)
  81. }
  82. override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
  83. return super.onCreateDialog(savedInstanceState).also {
  84. it.window?.requestFeature(Window.FEATURE_NO_TITLE)
  85. it.setCanceledOnTouchOutside(false)
  86. }
  87. }
  88. private fun startDownloadProfile() {
  89. val server = profileDownloadServer.editText!!.let {
  90. it.text.toString().trim().apply {
  91. if (isEmpty()) {
  92. it.requestFocus()
  93. return@startDownloadProfile
  94. }
  95. }
  96. }
  97. val code = profileDownloadCode.editText!!.text.toString().trim()
  98. downloading = true
  99. profileDownloadServer.editText!!.isEnabled = false
  100. profileDownloadCode.editText!!.isEnabled = false
  101. progress.isIndeterminate = true
  102. progress.visibility = View.VISIBLE
  103. lifecycleScope.launch {
  104. try {
  105. doDownloadProfile(server, code)
  106. } catch (e: Exception) {
  107. Log.d(TAG, "Error downloading profile")
  108. Log.d(TAG, Log.getStackTraceString(e))
  109. Toast.makeText(context, R.string.profile_download_failed, Toast.LENGTH_LONG).show()
  110. } finally {
  111. if (parentFragment is EuiccProfilesChangedListener) {
  112. (parentFragment as EuiccProfilesChangedListener).onEuiccProfilesChanged()
  113. }
  114. dismiss()
  115. }
  116. }
  117. }
  118. private suspend fun doDownloadProfile(server: String, code: String) = withContext(Dispatchers.IO) {
  119. channel.lpa.downloadProfile("1\$${server}\$${code}", channel.imei, DownloadProgress().apply {
  120. setProgressListener { _, _, percentage, _ ->
  121. progress.isIndeterminate = false
  122. progress.progress = (percentage * 100).toInt()
  123. }
  124. })
  125. }
  126. }