EuiccChannelFragmentUtils.kt 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package im.angry.openeuicc.util
  2. import android.os.Build
  3. import android.os.Bundle
  4. import androidx.fragment.app.Fragment
  5. import im.angry.openeuicc.core.EuiccChannel
  6. import im.angry.openeuicc.core.EuiccChannelManager
  7. import im.angry.openeuicc.service.EuiccChannelManagerService
  8. import im.angry.openeuicc.ui.BaseEuiccAccessActivity
  9. private const val FIELD_SLOT_ID = "slotId"
  10. private const val FIELD_PORT_ID = "portId"
  11. private const val FIELD_SE_ID = "seId"
  12. interface EuiccChannelFragmentMarker : OpenEuiccContextMarker
  13. private typealias BundleSetter = Bundle.() -> Unit
  14. // We must use extension functions because there is no way to add bounds to the type of "self"
  15. // in the definition of an interface, so the only way is to limit where the extension functions
  16. // can be applied.
  17. fun <T> newInstanceEuicc(
  18. clazz: Class<T>,
  19. slotId: Int,
  20. portId: Int,
  21. seId: EuiccChannel.SecureElementId,
  22. addArguments: BundleSetter = {}
  23. ): T
  24. where T : Fragment, T : EuiccChannelFragmentMarker =
  25. clazz.getDeclaredConstructor().newInstance().apply {
  26. arguments = Bundle()
  27. arguments!!.putInt(FIELD_SLOT_ID, slotId)
  28. arguments!!.putInt(FIELD_PORT_ID, portId)
  29. arguments!!.putParcelable(FIELD_SE_ID, seId)
  30. arguments!!.addArguments()
  31. }
  32. // Convenient methods to avoid using `channel` for these
  33. // `channel` requires that the channel actually exists in EuiccChannelManager, which is
  34. // not always the case during operations such as switching
  35. val <T> T.slotId: Int
  36. where T : Fragment, T : EuiccChannelFragmentMarker
  37. get() = requireArguments().getInt(FIELD_SLOT_ID)
  38. val <T> T.portId: Int
  39. where T : Fragment, T : EuiccChannelFragmentMarker
  40. get() = requireArguments().getInt(FIELD_PORT_ID)
  41. val <T> T.seId: EuiccChannel.SecureElementId
  42. where T : Fragment, T : EuiccChannelFragmentMarker
  43. get() =
  44. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
  45. requireArguments().getParcelable(
  46. FIELD_SE_ID,
  47. EuiccChannel.SecureElementId::class.java
  48. )!!
  49. } else {
  50. @Suppress("DEPRECATION")
  51. requireArguments().getParcelable(FIELD_SE_ID)!!
  52. }
  53. val <T> T.isUsb: Boolean
  54. where T : Fragment, T : EuiccChannelFragmentMarker
  55. get() = slotId == EuiccChannelManager.USB_CHANNEL_ID
  56. private fun <T> T.requireEuiccActivity(): BaseEuiccAccessActivity
  57. where T : Fragment, T : OpenEuiccContextMarker =
  58. requireActivity() as BaseEuiccAccessActivity
  59. val <T> T.euiccChannelManager: EuiccChannelManager
  60. where T : Fragment, T : OpenEuiccContextMarker
  61. get() = requireEuiccActivity().euiccChannelManager
  62. val <T> T.euiccChannelManagerService: EuiccChannelManagerService
  63. where T : Fragment, T : OpenEuiccContextMarker
  64. get() = requireEuiccActivity().euiccChannelManagerService
  65. suspend fun <T, R> T.withEuiccChannel(fn: suspend (EuiccChannel) -> R): R
  66. where T : Fragment, T : EuiccChannelFragmentMarker {
  67. ensureEuiccChannelManager()
  68. return euiccChannelManager.withEuiccChannel(
  69. slotId,
  70. portId,
  71. seId,
  72. fn
  73. )
  74. }
  75. suspend fun <T> T.ensureEuiccChannelManager() where T : Fragment, T : OpenEuiccContextMarker =
  76. requireEuiccActivity().euiccChannelManagerLoaded.await()
  77. fun <T> T.notifyEuiccProfilesChanged() where T : Fragment {
  78. if (this !is EuiccProfilesChangedListener) return
  79. // Trigger a refresh in the parent fragment -- it should wait until
  80. // any foreground task is completed before actually doing a refresh
  81. this.onEuiccProfilesChanged()
  82. }
  83. interface EuiccProfilesChangedListener {
  84. fun onEuiccProfilesChanged()
  85. }