MainActivity.kt 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package im.angry.openeuicc.ui
  2. import android.annotation.SuppressLint
  3. import android.content.BroadcastReceiver
  4. import android.content.Context
  5. import android.content.Intent
  6. import android.content.IntentFilter
  7. import android.hardware.usb.UsbManager
  8. import android.os.Bundle
  9. import android.telephony.TelephonyManager
  10. import android.util.Log
  11. import android.view.Menu
  12. import android.view.MenuItem
  13. import android.view.View
  14. import android.widget.ProgressBar
  15. import androidx.fragment.app.Fragment
  16. import androidx.lifecycle.lifecycleScope
  17. import androidx.viewpager2.adapter.FragmentStateAdapter
  18. import androidx.viewpager2.widget.ViewPager2
  19. import com.google.android.material.tabs.TabLayout
  20. import com.google.android.material.tabs.TabLayoutMediator
  21. import im.angry.openeuicc.common.R
  22. import im.angry.openeuicc.util.*
  23. import kotlinx.coroutines.Dispatchers
  24. import kotlinx.coroutines.launch
  25. import kotlinx.coroutines.withContext
  26. @SuppressLint("NotifyDataSetChanged")
  27. open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
  28. companion object {
  29. const val TAG = "MainActivity"
  30. }
  31. private lateinit var loadingProgress: ProgressBar
  32. private lateinit var tabs: TabLayout
  33. private lateinit var viewPager: ViewPager2
  34. private data class Page(
  35. val title: String,
  36. val createFragment: () -> Fragment
  37. )
  38. private val pages: MutableList<Page> = mutableListOf()
  39. private val pagerAdapter by lazy {
  40. object : FragmentStateAdapter(this) {
  41. override fun getItemCount() = pages.size
  42. override fun createFragment(position: Int): Fragment = pages[position].createFragment()
  43. }
  44. }
  45. var loading: Boolean
  46. get() = loadingProgress.visibility == View.VISIBLE
  47. set(value) {
  48. loadingProgress.visibility = if (value) {
  49. View.VISIBLE
  50. } else {
  51. View.GONE
  52. }
  53. }
  54. protected lateinit var tm: TelephonyManager
  55. private val usbReceiver = object : BroadcastReceiver() {
  56. override fun onReceive(context: Context?, intent: Intent?) {
  57. if (intent?.action == UsbManager.ACTION_USB_DEVICE_ATTACHED || intent?.action == UsbManager.ACTION_USB_DEVICE_DETACHED) {
  58. refresh()
  59. }
  60. }
  61. }
  62. @SuppressLint("WrongConstant", "UnspecifiedRegisterReceiverFlag")
  63. override fun onCreate(savedInstanceState: Bundle?) {
  64. super.onCreate(savedInstanceState)
  65. setContentView(R.layout.activity_main)
  66. setSupportActionBar(requireViewById(R.id.toolbar))
  67. loadingProgress = requireViewById(R.id.loading)
  68. tabs = requireViewById(R.id.main_tabs)
  69. viewPager = requireViewById(R.id.view_pager)
  70. viewPager.adapter = pagerAdapter
  71. TabLayoutMediator(tabs, viewPager) { tab, pos ->
  72. tab.text = pages[pos].title
  73. }.attach()
  74. tm = telephonyManager
  75. registerReceiver(usbReceiver, IntentFilter().apply {
  76. addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
  77. addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
  78. })
  79. }
  80. override fun onDestroy() {
  81. super.onDestroy()
  82. unregisterReceiver(usbReceiver)
  83. }
  84. override fun onCreateOptionsMenu(menu: Menu): Boolean {
  85. menuInflater.inflate(R.menu.activity_main, menu)
  86. return true
  87. }
  88. override fun onOptionsItemSelected(item: MenuItem): Boolean =
  89. when (item.itemId) {
  90. R.id.settings -> {
  91. startActivity(Intent(this, SettingsActivity::class.java));
  92. true
  93. }
  94. R.id.reload -> {
  95. refresh()
  96. true
  97. }
  98. else -> super.onOptionsItemSelected(item)
  99. }
  100. override fun onInit() {
  101. lifecycleScope.launch {
  102. init()
  103. }
  104. }
  105. private suspend fun init() {
  106. loading = true
  107. viewPager.visibility = View.GONE
  108. tabs.visibility = View.GONE
  109. val knownChannels = withContext(Dispatchers.IO) {
  110. euiccChannelManager.enumerateEuiccChannels().onEach {
  111. Log.d(TAG, "slot ${it.slotId} port ${it.portId}")
  112. Log.d(TAG, it.lpa.eID)
  113. // Request the system to refresh the list of profiles every time we start
  114. // Note that this is currently supposed to be no-op when unprivileged,
  115. // but it could change in the future
  116. euiccChannelManager.notifyEuiccProfilesChanged(it.logicalSlotId)
  117. }
  118. }
  119. val (usbDevice, _) = withContext(Dispatchers.IO) {
  120. euiccChannelManager.enumerateUsbEuiccChannel()
  121. }
  122. withContext(Dispatchers.Main) {
  123. loading = false
  124. knownChannels.sortedBy { it.logicalSlotId }.forEach { channel ->
  125. pages.add(Page(
  126. getString(R.string.channel_name_format, channel.logicalSlotId)
  127. ) { appContainer.uiComponentFactory.createEuiccManagementFragment(channel) })
  128. }
  129. // If USB readers exist, add them at the very last
  130. // We use a wrapper fragment to handle logic specific to USB readers
  131. usbDevice?.let {
  132. //spinnerAdapter.add(it.productName)
  133. pages.add(Page(it.productName ?: "USB") { UsbCcidReaderFragment() })
  134. }
  135. pagerAdapter.notifyDataSetChanged()
  136. viewPager.visibility = View.VISIBLE
  137. if (pages.size > 1) {
  138. tabs.visibility = View.VISIBLE
  139. } else if (pages.isEmpty()) {
  140. pages.add(Page("") { appContainer.uiComponentFactory.createNoEuiccPlaceholderFragment() })
  141. pagerAdapter.notifyDataSetChanged()
  142. }
  143. }
  144. }
  145. private fun refresh() {
  146. lifecycleScope.launch {
  147. loading = true
  148. viewPager.visibility = View.GONE
  149. tabs.visibility = View.GONE
  150. pages.clear()
  151. pagerAdapter.notifyDataSetChanged()
  152. init()
  153. }
  154. }
  155. }