LPAUtils.kt 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package im.angry.openeuicc.util
  2. import android.util.Log
  3. import im.angry.openeuicc.core.EuiccChannel
  4. import im.angry.openeuicc.core.EuiccChannelManager
  5. import net.typeblog.lpac_jni.LocalProfileAssistant
  6. import net.typeblog.lpac_jni.LocalProfileInfo
  7. const val TAG = "LPAUtils"
  8. val LocalProfileInfo.displayName: String
  9. get() = nickName.ifEmpty { name }
  10. val LocalProfileInfo.isEnabled: Boolean
  11. get() = state == LocalProfileInfo.State.Enabled
  12. val List<LocalProfileInfo>.operational: List<LocalProfileInfo>
  13. get() = filter { it.profileClass == LocalProfileInfo.Clazz.Operational }
  14. val List<LocalProfileInfo>.enabled: LocalProfileInfo?
  15. get() = find { it.isEnabled }
  16. val List<EuiccChannel>.hasMultipleChips: Boolean
  17. get() = distinctBy { it.slotId }.size > 1
  18. fun LocalProfileAssistant.switchProfile(
  19. iccid: String,
  20. enable: Boolean = false,
  21. refresh: Boolean = false
  22. ): Boolean =
  23. if (enable) {
  24. enableProfile(iccid, refresh)
  25. } else {
  26. disableProfile(iccid, refresh)
  27. }
  28. /**
  29. * Disable the current active profile if any. If refresh is true, also cause a refresh command.
  30. * See EuiccManager.waitForReconnect()
  31. */
  32. fun LocalProfileAssistant.disableActiveProfile(refresh: Boolean): Boolean =
  33. profiles.enabled?.let {
  34. Log.i(TAG, "Disabling active profile ${it.iccid}")
  35. disableProfile(it.iccid, refresh)
  36. } ?: true
  37. /**
  38. * Disable the current active profile if any. If refresh is true, also cause a refresh command.
  39. * See EuiccManager.waitForReconnect()
  40. *
  41. * Return the iccid of the profile being disabled, or null if no active profile found or failed to
  42. * disable.
  43. */
  44. fun LocalProfileAssistant.disableActiveProfileKeepIccId(refresh: Boolean): String? =
  45. profiles.enabled?.let {
  46. Log.i(TAG, "Disabling active profile ${it.iccid}")
  47. if (disableProfile(it.iccid, refresh)) {
  48. it.iccid
  49. } else {
  50. null
  51. }
  52. }
  53. /**
  54. * Begin a "tracked" operation where notifications may be generated by the eSIM
  55. * Automatically handle any newly generated notification during the operation
  56. * if the function "op" returns true.
  57. *
  58. * This requires the EuiccChannelManager object and a slotId / portId instead of
  59. * just an LPA object, because a LPA might become invalid during an operation
  60. * that generates notifications. As such, we will end up having to reconnect
  61. * when this happens.
  62. *
  63. * Note that however, if reconnect is required and will not be instant, waiting
  64. * should be the concern of op() itself, and this function assumes that when
  65. * op() returns, the slotId and portId will correspond to a valid channel again.
  66. */
  67. suspend inline fun EuiccChannelManager.beginTrackedOperation(
  68. slotId: Int,
  69. portId: Int,
  70. op: () -> Boolean
  71. ) {
  72. val latestSeq = withEuiccChannel(slotId, portId) { channel ->
  73. channel.lpa.notifications.firstOrNull()?.seqNumber
  74. ?: 0
  75. }
  76. Log.d(TAG, "Latest notification is $latestSeq before operation")
  77. if (op()) {
  78. Log.d(TAG, "Operation has requested notification handling")
  79. try {
  80. // Note that the exact instance of "channel" might have changed here if reconnected;
  81. // this is why we need to use two distinct calls to withEuiccChannel()
  82. withEuiccChannel(slotId, portId) { channel ->
  83. channel.lpa.notifications.filter { it.seqNumber > latestSeq }.forEach {
  84. Log.d(TAG, "Handling notification $it")
  85. channel.lpa.handleNotification(it.seqNumber)
  86. }
  87. }
  88. } catch (e: Exception) {
  89. // Ignore any error during notification handling
  90. e.printStackTrace()
  91. }
  92. }
  93. Log.d(TAG, "Operation complete")
  94. }