EuiccChannelFragmentUtils.kt 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. package im.angry.openeuicc.util
  2. import android.os.Bundle
  3. import android.util.Log
  4. import androidx.fragment.app.Fragment
  5. import im.angry.openeuicc.core.EuiccChannel
  6. import kotlinx.coroutines.Dispatchers
  7. import kotlinx.coroutines.withContext
  8. import net.typeblog.lpac_jni.LocalProfileAssistant
  9. private const val TAG = "EuiccChannelFragmentUtils"
  10. interface EuiccChannelFragmentMarker: OpenEuiccContextMarker
  11. // We must use extension functions because there is no way to add bounds to the type of "self"
  12. // in the definition of an interface, so the only way is to limit where the extension functions
  13. // can be applied.
  14. fun <T> newInstanceEuicc(clazz: Class<T>, slotId: Int, portId: Int, addArguments: Bundle.() -> Unit = {}): T where T: Fragment, T: EuiccChannelFragmentMarker {
  15. val instance = clazz.newInstance()
  16. instance.arguments = Bundle().apply {
  17. putInt("slotId", slotId)
  18. putInt("portId", portId)
  19. addArguments()
  20. }
  21. return instance
  22. }
  23. val <T> T.slotId: Int where T: Fragment, T: EuiccChannelFragmentMarker
  24. get() = requireArguments().getInt("slotId")
  25. val <T> T.portId: Int where T: Fragment, T: EuiccChannelFragmentMarker
  26. get() = requireArguments().getInt("portId")
  27. val <T> T.channel: EuiccChannel where T: Fragment, T: EuiccChannelFragmentMarker
  28. get() =
  29. euiccChannelManager.findEuiccChannelByPortBlocking(slotId, portId)!!
  30. /*
  31. * Begin a "tracked" operation where notifications may be generated by the eSIM
  32. * Automatically handle any newly generated notification during the operation
  33. * if the function "op" returns true.
  34. */
  35. suspend fun <T> T.beginTrackedOperation(op: suspend () -> Boolean) where T : Fragment, T : EuiccChannelFragmentMarker =
  36. withContext(Dispatchers.IO) {
  37. val latestSeq = channel.lpa.notifications.firstOrNull()?.seqNumber ?: 0
  38. Log.d(TAG, "Latest notification is $latestSeq before operation")
  39. if (op()) {
  40. Log.d(TAG, "Operation has requested notification handling")
  41. // Note that the exact instance of "channel" might have changed here if reconnected;
  42. // so we MUST use the automatic getter for "channel"
  43. channel.lpa.notifications.filter { it.seqNumber > latestSeq }.forEach {
  44. Log.d(TAG, "Handling notification $it")
  45. channel.lpa.handleNotification(it.seqNumber)
  46. }
  47. }
  48. Log.d(TAG, "Operation complete")
  49. }
  50. interface EuiccProfilesChangedListener {
  51. fun onEuiccProfilesChanged()
  52. }