OpenEuiccService.kt 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package im.angry.openeuicc.service
  2. import android.service.euicc.*
  3. import android.telephony.euicc.DownloadableSubscription
  4. import android.telephony.euicc.EuiccInfo
  5. import com.truphone.lpa.LocalProfileInfo
  6. import com.truphone.lpad.progress.Progress
  7. import com.truphone.util.TextUtil
  8. import im.angry.openeuicc.OpenEuiccApplication
  9. import im.angry.openeuicc.core.EuiccChannel
  10. import im.angry.openeuicc.util.*
  11. class OpenEuiccService : EuiccService() {
  12. private val openEuiccApplication
  13. get() = application as OpenEuiccApplication
  14. private fun findChannel(slotId: Int): EuiccChannel? =
  15. openEuiccApplication.euiccChannelManager
  16. .findEuiccChannelBySlotBlocking(slotId)
  17. override fun onGetEid(slotId: Int): String? =
  18. findChannel(slotId)?.lpa?.eid
  19. override fun onGetOtaStatus(slotId: Int): Int {
  20. // Not implemented
  21. return 5 // EUICC_OTA_STATUS_UNAVAILABLE
  22. }
  23. override fun onStartOtaIfNecessary(
  24. slotId: Int,
  25. statusChangedCallback: OtaStatusChangedCallback?
  26. ) {
  27. // Not implemented
  28. }
  29. override fun onGetDownloadableSubscriptionMetadata(
  30. slotId: Int,
  31. subscription: DownloadableSubscription?,
  32. forceDeactivateSim: Boolean
  33. ): GetDownloadableSubscriptionMetadataResult {
  34. // Stub: return as-is and do not fetch anything
  35. // This is incompatible with carrier eSIM apps; should we make it compatible?
  36. return GetDownloadableSubscriptionMetadataResult(RESULT_OK, subscription)
  37. }
  38. override fun onGetDefaultDownloadableSubscriptionList(
  39. slotId: Int,
  40. forceDeactivateSim: Boolean
  41. ): GetDefaultDownloadableSubscriptionListResult {
  42. // Stub: we do not implement this (as this would require phoning in a central GSMA server)
  43. return GetDefaultDownloadableSubscriptionListResult(RESULT_OK, arrayOf())
  44. }
  45. override fun onGetEuiccProfileInfoList(slotId: Int): GetEuiccProfileInfoListResult? {
  46. val channel = findChannel(slotId) ?: return null
  47. val profiles = channel.lpa.profiles.filter {
  48. it.profileClass != LocalProfileInfo.Clazz.Testing
  49. }.map {
  50. EuiccProfileInfo.Builder(it.iccidLittleEndian).apply {
  51. setProfileName(it.name)
  52. setNickname(it.nickName)
  53. setServiceProviderName(it.providerName)
  54. setState(
  55. when (it.state) {
  56. LocalProfileInfo.State.Enabled -> EuiccProfileInfo.PROFILE_STATE_ENABLED
  57. LocalProfileInfo.State.Disabled -> EuiccProfileInfo.PROFILE_STATE_DISABLED
  58. }
  59. )
  60. setProfileClass(
  61. when (it.profileClass) {
  62. LocalProfileInfo.Clazz.Testing -> EuiccProfileInfo.PROFILE_CLASS_TESTING
  63. LocalProfileInfo.Clazz.Provisioning -> EuiccProfileInfo.PROFILE_CLASS_PROVISIONING
  64. LocalProfileInfo.Clazz.Operational -> EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL
  65. }
  66. )
  67. }.build()
  68. }
  69. return GetEuiccProfileInfoListResult(RESULT_OK, profiles.toTypedArray(), channel.removable)
  70. }
  71. override fun onGetEuiccInfo(slotId: Int): EuiccInfo {
  72. return EuiccInfo("Unknown") // TODO: Can we actually implement this?
  73. }
  74. override fun onDeleteSubscription(slotId: Int, iccid: String): Int {
  75. try {
  76. val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
  77. val iccidBig = TextUtil.iccidLittleToBig(iccid)
  78. val profile = channel.lpa.profiles.find {
  79. it.iccid == iccidBig
  80. } ?: return RESULT_FIRST_USER
  81. if (profile.state == LocalProfileInfo.State.Enabled) {
  82. // Must disable the profile first
  83. return RESULT_FIRST_USER
  84. }
  85. return if (channel.lpa.deleteProfile(iccidBig, Progress()) == "0") {
  86. RESULT_OK
  87. } else {
  88. RESULT_FIRST_USER
  89. }
  90. } catch (e: Exception) {
  91. return RESULT_FIRST_USER
  92. }
  93. }
  94. // TODO: on some devices we need to update the mapping (and potentially disable a pSIM)
  95. // for eSIM to be usable, in which case we will have to respect forceDeactivateSim.
  96. // This is the same for our custom LUI. Both have to take this into consideration.
  97. @Deprecated("Deprecated in Java")
  98. override fun onSwitchToSubscription(
  99. slotId: Int,
  100. iccid: String?,
  101. forceDeactivateSim: Boolean
  102. ): Int {
  103. try {
  104. val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
  105. if (iccid == null) {
  106. // Disable active profile
  107. val activeProfile = channel.lpa.profiles.find {
  108. it.state == LocalProfileInfo.State.Enabled
  109. } ?: return RESULT_OK
  110. return if (channel.lpa.disableProfile(activeProfile.iccid, Progress()) == "0") {
  111. RESULT_OK
  112. } else {
  113. RESULT_FIRST_USER
  114. }
  115. } else {
  116. val iccidBig = TextUtil.iccidLittleToBig(iccid)
  117. return if (channel.lpa.enableProfile(iccidBig, Progress()) == "0") {
  118. RESULT_OK
  119. } else {
  120. RESULT_FIRST_USER
  121. }
  122. }
  123. } catch (e: Exception) {
  124. return RESULT_FIRST_USER
  125. } finally {
  126. openEuiccApplication.euiccChannelManager.invalidate()
  127. }
  128. }
  129. override fun onUpdateSubscriptionNickname(slotId: Int, iccid: String, nickname: String?): Int {
  130. val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
  131. val success = channel.lpa
  132. .setNickname(TextUtil.iccidLittleToBig(iccid), nickname)
  133. openEuiccApplication.subscriptionManager.tryRefreshCachedEuiccInfo(channel.cardId)
  134. return if (success) {
  135. RESULT_OK
  136. } else {
  137. RESULT_FIRST_USER
  138. }
  139. }
  140. @Deprecated("Deprecated in Java")
  141. override fun onEraseSubscriptions(slotId: Int): Int {
  142. // No-op
  143. return RESULT_FIRST_USER
  144. }
  145. override fun onRetainSubscriptionsForFactoryReset(slotId: Int): Int {
  146. // No-op -- we do not care
  147. return RESULT_FIRST_USER
  148. }
  149. }