| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- package im.angry.openeuicc.util
- import android.os.Build
- import android.os.Bundle
- import androidx.fragment.app.Fragment
- import im.angry.openeuicc.core.EuiccChannel
- import im.angry.openeuicc.core.EuiccChannelManager
- import im.angry.openeuicc.service.EuiccChannelManagerService
- import im.angry.openeuicc.ui.BaseEuiccAccessActivity
- private const val FIELD_SLOT_ID = "slotId"
- private const val FIELD_PORT_ID = "portId"
- private const val FIELD_SE_ID = "seId"
- interface EuiccChannelFragmentMarker : OpenEuiccContextMarker
- private typealias BundleSetter = Bundle.() -> Unit
- // We must use extension functions because there is no way to add bounds to the type of "self"
- // in the definition of an interface, so the only way is to limit where the extension functions
- // can be applied.
- fun <T> newInstanceEuicc(
- clazz: Class<T>,
- slotId: Int,
- portId: Int,
- seId: EuiccChannel.SecureElementId,
- addArguments: BundleSetter = {}
- ): T
- where T : Fragment, T : EuiccChannelFragmentMarker =
- clazz.getDeclaredConstructor().newInstance().apply {
- arguments = Bundle()
- arguments!!.putInt(FIELD_SLOT_ID, slotId)
- arguments!!.putInt(FIELD_PORT_ID, portId)
- arguments!!.putParcelable(FIELD_SE_ID, seId)
- arguments!!.addArguments()
- }
- // Convenient methods to avoid using `channel` for these
- // `channel` requires that the channel actually exists in EuiccChannelManager, which is
- // not always the case during operations such as switching
- val <T> T.slotId: Int
- where T : Fragment, T : EuiccChannelFragmentMarker
- get() = requireArguments().getInt(FIELD_SLOT_ID)
- val <T> T.portId: Int
- where T : Fragment, T : EuiccChannelFragmentMarker
- get() = requireArguments().getInt(FIELD_PORT_ID)
- val <T> T.seId: EuiccChannel.SecureElementId
- where T : Fragment, T : EuiccChannelFragmentMarker
- get() =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- requireArguments().getParcelable(
- FIELD_SE_ID,
- EuiccChannel.SecureElementId::class.java
- )!!
- } else {
- @Suppress("DEPRECATION")
- requireArguments().getParcelable(FIELD_SE_ID)!!
- }
- val <T> T.isUsb: Boolean
- where T : Fragment, T : EuiccChannelFragmentMarker
- get() = slotId == EuiccChannelManager.USB_CHANNEL_ID
- private fun <T> T.requireEuiccActivity(): BaseEuiccAccessActivity
- where T : Fragment, T : OpenEuiccContextMarker =
- requireActivity() as BaseEuiccAccessActivity
- val <T> T.euiccChannelManager: EuiccChannelManager
- where T : Fragment, T : OpenEuiccContextMarker
- get() = requireEuiccActivity().euiccChannelManager
- val <T> T.euiccChannelManagerService: EuiccChannelManagerService
- where T : Fragment, T : OpenEuiccContextMarker
- get() = requireEuiccActivity().euiccChannelManagerService
- suspend fun <T, R> T.withEuiccChannel(fn: suspend (EuiccChannel) -> R): R
- where T : Fragment, T : EuiccChannelFragmentMarker {
- ensureEuiccChannelManager()
- return euiccChannelManager.withEuiccChannel(
- slotId,
- portId,
- seId,
- fn
- )
- }
- suspend fun <T> T.ensureEuiccChannelManager() where T : Fragment, T : OpenEuiccContextMarker =
- requireEuiccActivity().euiccChannelManagerLoaded.await()
- fun <T> T.notifyEuiccProfilesChanged() where T : Fragment {
- if (this !is EuiccProfilesChangedListener) return
- // Trigger a refresh in the parent fragment -- it should wait until
- // any foreground task is completed before actually doing a refresh
- this.onEuiccProfilesChanged()
- }
- interface EuiccProfilesChangedListener {
- fun onEuiccProfilesChanged()
- }
|