| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- package im.angry.openeuicc.ui
- import android.annotation.SuppressLint
- import android.app.Dialog
- import android.os.Bundle
- import android.text.Editable
- import android.text.format.Formatter
- import android.util.Log
- import android.view.*
- import android.widget.ProgressBar
- import android.widget.TextView
- import android.widget.Toast
- 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.util.openEuiccApplication
- import im.angry.openeuicc.util.preferenceRepository
- import im.angry.openeuicc.util.setWidthPercent
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.flow.first
- import kotlinx.coroutines.launch
- import kotlinx.coroutines.withContext
- import net.typeblog.lpac_jni.ProfileDownloadCallback
- import kotlin.Exception
- class ProfileDownloadFragment : BaseMaterialDialogFragment(), EuiccFragmentMarker, Toolbar.OnMenuItemClickListener {
- companion object {
- const val TAG = "ProfileDownloadFragment"
- fun newInstance(slotId: Int, portId: Int): ProfileDownloadFragment =
- newInstanceEuicc(ProfileDownloadFragment::class.java, slotId, portId)
- }
- 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 barcodeScannerLauncher = registerForActivityResult(ScanContract()) { result ->
- result.contents?.let { content ->
- Log.d(TAG, content)
- val components = content.split("$")
- if (components.size < 3 || components[0] != "LPA:1") return@registerForActivityResult
- 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.findViewById(R.id.toolbar)
- profileDownloadServer = view.findViewById(R.id.profile_download_server)
- profileDownloadCode = view.findViewById(R.id.profile_download_code)
- profileDownloadConfirmationCode = view.findViewById(R.id.profile_download_confirmation_code)
- profileDownloadIMEI = view.findViewById(R.id.profile_download_imei)
- profileDownloadFreeSpace = view.findViewById(R.id.profile_download_free_space)
- progress = view.findViewById(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.ok -> {
- startDownloadProfile()
- true
- }
- else -> false
- }
- override fun onResume() {
- super.onResume()
- setWidthPercent(95)
- }
- @SuppressLint("MissingPermission")
- override fun onStart() {
- super.onStart()
- profileDownloadIMEI.editText!!.text = Editable.Factory.getInstance().newEditable(
- try {
- openEuiccApplication.telephonyManager.getImei(channel.logicalSlotId)
- } catch (e: Exception) {
- ""
- }
- )
- lifecycleScope.launch(Dispatchers.IO) {
- // Fetch remaining NVRAM
- val str = channel.lpa.euiccInfo2?.freeNvram?.also {
- freeNvram = it
- }?.let { Formatter.formatShortFileSize(requireContext(), it.toLong()) }
- withContext(Dispatchers.Main) {
- profileDownloadFreeSpace.text = getString(R.string.profile_download_free_space,
- str ?: getText(R.string.unknown))
- }
- }
- }
- 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 {
- try {
- doDownloadProfile(server, code, confirmationCode, imei)
- } catch (e: Exception) {
- Log.d(TAG, "Error downloading profile")
- Log.d(TAG, Log.getStackTraceString(e))
- Toast.makeText(context, R.string.profile_download_failed, Toast.LENGTH_LONG).show()
- } finally {
- if (parentFragment is EuiccProfilesChangedListener) {
- (parentFragment as EuiccProfilesChangedListener).onEuiccProfilesChanged()
- }
- dismiss()
- }
- }
- }
- private suspend fun doDownloadProfile(server: String, code: String?, confirmationCode: String?, imei: String?) = channel.lpa.beginOperation {
- downloadProfile(server, code, imei, confirmationCode, object : ProfileDownloadCallback {
- override fun onStateUpdate(state: ProfileDownloadCallback.DownloadState) {
- lifecycleScope.launch(Dispatchers.Main) {
- progress.isIndeterminate = false
- progress.progress = state.progress
- }
- }
- })
- // If we get here, we are successful
- // Only send notifications if the user allowed us to
- preferenceRepository.notificationDownloadFlow.first()
- }
- }
|