ProfileDownloadFragment.kt 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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.Toast
  7. import androidx.appcompat.widget.Toolbar
  8. import androidx.fragment.app.DialogFragment
  9. import androidx.lifecycle.lifecycleScope
  10. import com.journeyapps.barcodescanner.ScanContract
  11. import com.journeyapps.barcodescanner.ScanOptions
  12. import com.truphone.lpa.progress.DownloadProgress
  13. import im.angry.openeuicc.R
  14. import im.angry.openeuicc.databinding.FragmentProfileDownloadBinding
  15. import im.angry.openeuicc.util.setWidthPercent
  16. import kotlinx.coroutines.Dispatchers
  17. import kotlinx.coroutines.launch
  18. import kotlinx.coroutines.withContext
  19. import java.lang.Exception
  20. class ProfileDownloadFragment : DialogFragment(), EuiccFragmentMarker, Toolbar.OnMenuItemClickListener {
  21. companion object {
  22. const val TAG = "ProfileDownloadFragment"
  23. fun newInstance(slotId: Int): ProfileDownloadFragment =
  24. newInstanceEuicc(ProfileDownloadFragment::class.java, slotId)
  25. }
  26. private var _binding: FragmentProfileDownloadBinding? = null
  27. private val binding get() = _binding!!
  28. private var downloading = false
  29. private val barcodeScannerLauncher = registerForActivityResult(ScanContract()) { result ->
  30. result.contents?.let { content ->
  31. val components = content.split("$")
  32. if (components.size != 3 || components[0] != "LPA:1") return@registerForActivityResult
  33. binding.profileDownloadServer.editText?.setText(components[1])
  34. binding.profileDownloadCode.editText?.setText(components[2])
  35. }
  36. }
  37. override fun onCreateView(
  38. inflater: LayoutInflater,
  39. container: ViewGroup?,
  40. savedInstanceState: Bundle?
  41. ): View {
  42. _binding = FragmentProfileDownloadBinding.inflate(inflater, container, false)
  43. binding.toolbar.inflateMenu(R.menu.fragment_profile_download)
  44. return binding.root
  45. }
  46. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  47. super.onViewCreated(view, savedInstanceState)
  48. binding.toolbar.apply {
  49. setTitle(R.string.profile_download)
  50. setNavigationOnClickListener {
  51. if (!downloading) dismiss()
  52. }
  53. setOnMenuItemClickListener(this@ProfileDownloadFragment)
  54. }
  55. }
  56. override fun onMenuItemClick(item: MenuItem): Boolean = downloading ||
  57. when (item.itemId) {
  58. R.id.scan -> {
  59. barcodeScannerLauncher.launch(ScanOptions().apply {
  60. setDesiredBarcodeFormats(ScanOptions.QR_CODE)
  61. setOrientationLocked(false)
  62. })
  63. true
  64. }
  65. R.id.ok -> {
  66. startDownloadProfile()
  67. true
  68. }
  69. else -> false
  70. }
  71. override fun onResume() {
  72. super.onResume()
  73. setWidthPercent(95)
  74. }
  75. override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
  76. return super.onCreateDialog(savedInstanceState).also {
  77. it.window?.requestFeature(Window.FEATURE_NO_TITLE)
  78. it.setCanceledOnTouchOutside(false)
  79. }
  80. }
  81. private fun startDownloadProfile() {
  82. val server = binding.profileDownloadServer.editText!!.let {
  83. it.text.toString().trim().apply {
  84. if (isEmpty()) {
  85. it.requestFocus()
  86. return@startDownloadProfile
  87. }
  88. }
  89. }
  90. val code = binding.profileDownloadCode.editText!!.let {
  91. it.text.toString().trim().apply {
  92. if (isEmpty()) {
  93. it.requestFocus()
  94. return@startDownloadProfile
  95. }
  96. }
  97. }
  98. downloading = true
  99. binding.profileDownloadServer.editText!!.isEnabled = false
  100. binding.profileDownloadCode.editText!!.isEnabled = false
  101. binding.progress.isIndeterminate = true
  102. binding.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}", DownloadProgress().apply {
  120. setProgressListener { _, _, percentage, _ ->
  121. binding.progress.isIndeterminate = false
  122. binding.progress.progress = (percentage * 100).toInt()
  123. }
  124. })
  125. }
  126. }