refactor: Stop exitting the application when enabling/disabling profiles
..instead, attempt to reconnect the LPA. This is needed to properly send notifications after the operation.
This commit is contained in:
parent
6784eae43b
commit
451b17d0a5
|
@ -127,7 +127,6 @@ open class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfi
|
|||
|
||||
private fun enableOrDisableProfile(iccid: String, enable: Boolean) {
|
||||
swipeRefresh.isRefreshing = true
|
||||
swipeRefresh.isEnabled = false
|
||||
fab.isEnabled = false
|
||||
|
||||
lifecycleScope.launch {
|
||||
|
@ -137,15 +136,12 @@ open class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfi
|
|||
} else {
|
||||
doDisableProfile(iccid)
|
||||
}
|
||||
Toast.makeText(context, R.string.toast_profile_enabled, Toast.LENGTH_LONG).show()
|
||||
// The APDU channel will be invalid when the SIM reboots. For now, just exit the app
|
||||
euiccChannelManager.invalidate()
|
||||
requireActivity().finish()
|
||||
refresh()
|
||||
fab.isEnabled = true
|
||||
} catch (e: Exception) {
|
||||
Log.d(TAG, "Failed to enable / disable profile $iccid")
|
||||
Log.d(TAG, Log.getStackTraceString(e))
|
||||
fab.isEnabled = true
|
||||
swipeRefresh.isEnabled = true
|
||||
Toast.makeText(context, R.string.toast_profile_enable_failed, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
@ -153,14 +149,14 @@ open class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfi
|
|||
|
||||
private suspend fun doEnableProfile(iccid: String) =
|
||||
channel.lpa.beginOperation {
|
||||
channel.lpa.enableProfile(iccid)
|
||||
preferenceRepository.notificationEnableFlow.first()
|
||||
channel.lpa.enableProfile(iccid, reconnectTimeout = 15 * 1000) &&
|
||||
preferenceRepository.notificationEnableFlow.first()
|
||||
}
|
||||
|
||||
private suspend fun doDisableProfile(iccid: String) =
|
||||
channel.lpa.beginOperation {
|
||||
channel.lpa.disableProfile(iccid)
|
||||
preferenceRepository.notificationDisableFlow.first()
|
||||
channel.lpa.disableProfile(iccid, reconnectTimeout = 15 * 1000) &&
|
||||
preferenceRepository.notificationDisableFlow.first()
|
||||
}
|
||||
|
||||
sealed class ViewHolder(root: View) : RecyclerView.ViewHolder(root) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
<string name="delete">Delete</string>
|
||||
<string name="rename">Rename</string>
|
||||
|
||||
<string name="toast_profile_enabled">eSIM profile switched. Please wait for a while when the card is restarting.</string>
|
||||
<string name="toast_profile_enable_failed">Cannot switch to new eSIM profile.</string>
|
||||
<string name="toast_profile_name_too_long">Nickname cannot be longer than 64 characters</string>
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ class TelephonyManagerApduInterface(
|
|||
|
||||
override fun disconnect() {
|
||||
// Do nothing
|
||||
lastChannel = -1
|
||||
}
|
||||
|
||||
override fun logicalChannelOpen(aid: ByteArray): Int {
|
||||
|
|
|
@ -17,8 +17,8 @@ interface LocalProfileAssistant {
|
|||
|
||||
// All blocking functions in this class assume that they are executed on non-Main threads
|
||||
// The IO context in Kotlin's coroutine library is recommended.
|
||||
fun enableProfile(iccid: String): Boolean
|
||||
fun disableProfile(iccid: String): Boolean
|
||||
fun enableProfile(iccid: String, reconnectTimeout: Long = 0): Boolean
|
||||
fun disableProfile(iccid: String, reconnectTimeout: Long = 0): Boolean
|
||||
fun deleteProfile(iccid: String): Boolean
|
||||
|
||||
fun downloadProfile(smdp: String, matchingId: String?, imei: String?,
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package net.typeblog.lpac_jni.impl
|
||||
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import net.typeblog.lpac_jni.LpacJni
|
||||
import net.typeblog.lpac_jni.ApduInterface
|
||||
import net.typeblog.lpac_jni.EuiccInfo2
|
||||
|
@ -11,20 +14,52 @@ import net.typeblog.lpac_jni.LocalProfileNotification
|
|||
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
||||
|
||||
class LocalProfileAssistantImpl(
|
||||
apduInterface: ApduInterface,
|
||||
httpInterface: HttpInterface
|
||||
private val apduInterface: ApduInterface,
|
||||
private val httpInterface: HttpInterface
|
||||
): LocalProfileAssistant {
|
||||
companion object {
|
||||
private const val TAG = "LocalProfileAssistantImpl"
|
||||
}
|
||||
|
||||
private val contextHandle: Long = LpacJni.createContext(apduInterface, httpInterface)
|
||||
private var contextHandle: Long = LpacJni.createContext(apduInterface, httpInterface)
|
||||
init {
|
||||
if (LpacJni.es10xInit(contextHandle) < 0) {
|
||||
throw IllegalArgumentException("Failed to initialize LPA")
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryReconnect(timeoutMillis: Long) = runBlocking {
|
||||
withTimeout(timeoutMillis) {
|
||||
try {
|
||||
LpacJni.es10xFini(contextHandle)
|
||||
LpacJni.destroyContext(contextHandle)
|
||||
} catch (e: Exception) {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
apduInterface.disconnect()
|
||||
} catch (e: Exception) {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
try {
|
||||
apduInterface.connect()
|
||||
contextHandle = LpacJni.createContext(apduInterface, httpInterface)
|
||||
val res = LpacJni.es10xInit(contextHandle)
|
||||
Log.d(TAG, "$res")
|
||||
check(res >= 0) { "Reconnect attempt failed" }
|
||||
break
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
// continue retrying
|
||||
delay(1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val profiles: List<LocalProfileInfo>
|
||||
get() = LpacJni.es10cGetProfilesInfo(contextHandle)!!.asList()
|
||||
|
||||
|
@ -39,12 +74,28 @@ class LocalProfileAssistantImpl(
|
|||
override val euiccInfo2: EuiccInfo2?
|
||||
get() = LpacJni.es10cexGetEuiccInfo2(contextHandle)
|
||||
|
||||
override fun enableProfile(iccid: String): Boolean {
|
||||
return LpacJni.es10cEnableProfile(contextHandle, iccid) == 0
|
||||
override fun enableProfile(iccid: String, reconnectTimeout: Long): Boolean {
|
||||
val res = LpacJni.es10cEnableProfile(contextHandle, iccid) == 0
|
||||
if (reconnectTimeout > 0) {
|
||||
try {
|
||||
tryReconnect(reconnectTimeout)
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
override fun disableProfile(iccid: String): Boolean {
|
||||
return LpacJni.es10cDisableProfile(contextHandle, iccid) == 0
|
||||
override fun disableProfile(iccid: String, reconnectTimeout: Long): Boolean {
|
||||
val res = LpacJni.es10cDisableProfile(contextHandle, iccid) == 0
|
||||
if (reconnectTimeout > 0) {
|
||||
try {
|
||||
tryReconnect(reconnectTimeout)
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
override fun deleteProfile(iccid: String): Boolean {
|
||||
|
|
Loading…
Reference in a new issue