package im.angry.openeuicc.ui import android.annotation.SuppressLint import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.hardware.usb.UsbManager import android.os.Bundle import android.telephony.TelephonyManager import android.util.Log import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.ProgressBar import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator import im.angry.openeuicc.common.R import im.angry.openeuicc.util.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @SuppressLint("NotifyDataSetChanged") open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { companion object { const val TAG = "MainActivity" } private lateinit var loadingProgress: ProgressBar private lateinit var tabs: TabLayout private lateinit var viewPager: ViewPager2 private data class Page( val title: String, val createFragment: () -> Fragment ) private val pages: MutableList = mutableListOf() private val pagerAdapter by lazy { object : FragmentStateAdapter(this) { override fun getItemCount() = pages.size override fun createFragment(position: Int): Fragment = pages[position].createFragment() } } var loading: Boolean get() = loadingProgress.visibility == View.VISIBLE set(value) { loadingProgress.visibility = if (value) { View.VISIBLE } else { View.GONE } } protected lateinit var tm: TelephonyManager private val usbReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (intent?.action == UsbManager.ACTION_USB_DEVICE_ATTACHED || intent?.action == UsbManager.ACTION_USB_DEVICE_DETACHED) { refresh() } } } @SuppressLint("WrongConstant", "UnspecifiedRegisterReceiverFlag") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(requireViewById(R.id.toolbar)) loadingProgress = requireViewById(R.id.loading) tabs = requireViewById(R.id.main_tabs) viewPager = requireViewById(R.id.view_pager) viewPager.adapter = pagerAdapter TabLayoutMediator(tabs, viewPager) { tab, pos -> tab.text = pages[pos].title }.attach() tm = telephonyManager registerReceiver(usbReceiver, IntentFilter().apply { addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED) addAction(UsbManager.ACTION_USB_DEVICE_DETACHED) }) } override fun onDestroy() { super.onDestroy() unregisterReceiver(usbReceiver) } override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.activity_main, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.settings -> { startActivity(Intent(this, SettingsActivity::class.java)); true } R.id.reload -> { refresh() true } else -> super.onOptionsItemSelected(item) } override fun onInit() { lifecycleScope.launch { init() } } private suspend fun init() { loading = true viewPager.visibility = View.GONE tabs.visibility = View.GONE val knownChannels = withContext(Dispatchers.IO) { euiccChannelManager.enumerateEuiccChannels().onEach { Log.d(TAG, "slot ${it.slotId} port ${it.portId}") Log.d(TAG, it.lpa.eID) // Request the system to refresh the list of profiles every time we start // Note that this is currently supposed to be no-op when unprivileged, // but it could change in the future euiccChannelManager.notifyEuiccProfilesChanged(it.logicalSlotId) } } val (usbDevice, _) = withContext(Dispatchers.IO) { euiccChannelManager.enumerateUsbEuiccChannel() } withContext(Dispatchers.Main) { loading = false knownChannels.sortedBy { it.logicalSlotId }.forEach { channel -> pages.add(Page( getString(R.string.channel_name_format, channel.logicalSlotId) ) { appContainer.uiComponentFactory.createEuiccManagementFragment(channel) }) } // If USB readers exist, add them at the very last // We use a wrapper fragment to handle logic specific to USB readers usbDevice?.let { //spinnerAdapter.add(it.productName) pages.add(Page(it.productName ?: "USB") { UsbCcidReaderFragment() }) } pagerAdapter.notifyDataSetChanged() viewPager.visibility = View.VISIBLE if (pages.size > 1) { tabs.visibility = View.VISIBLE } else if (pages.isEmpty()) { pages.add(Page("") { appContainer.uiComponentFactory.createNoEuiccPlaceholderFragment() }) pagerAdapter.notifyDataSetChanged() } } } private fun refresh() { lifecycleScope.launch { loading = true viewPager.visibility = View.GONE tabs.visibility = View.GONE pages.clear() pagerAdapter.notifyDataSetChanged() init() } } }