Compare commits
No commits in common. "790a5cf778ed88f8920f1c23330ad238bccf2863" and "df9cece94b6aa91c085b906a7361134bba745c27" have entirely different histories.
790a5cf778
...
df9cece94b
4 changed files with 47 additions and 70 deletions
|
@ -1,10 +1,15 @@
|
||||||
package im.angry.openeuicc.util
|
package im.angry.openeuicc.util
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import im.angry.openeuicc.core.EuiccChannel
|
import im.angry.openeuicc.core.EuiccChannel
|
||||||
import im.angry.openeuicc.core.EuiccChannelManager
|
import im.angry.openeuicc.core.EuiccChannelManager
|
||||||
import im.angry.openeuicc.ui.BaseEuiccAccessActivity
|
import im.angry.openeuicc.ui.BaseEuiccAccessActivity
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
private const val TAG = "EuiccChannelFragmentUtils"
|
||||||
|
|
||||||
interface EuiccChannelFragmentMarker: OpenEuiccContextMarker
|
interface EuiccChannelFragmentMarker: OpenEuiccContextMarker
|
||||||
|
|
||||||
|
@ -32,9 +37,32 @@ val <T> T.channel: EuiccChannel where T: Fragment, T: EuiccChannelFragmentMarker
|
||||||
get() =
|
get() =
|
||||||
euiccChannelManager.findEuiccChannelByPortBlocking(slotId, portId)!!
|
euiccChannelManager.findEuiccChannelByPortBlocking(slotId, portId)!!
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Begin a "tracked" operation where notifications may be generated by the eSIM
|
||||||
|
* Automatically handle any newly generated notification during the operation
|
||||||
|
* if the function "op" returns true.
|
||||||
|
*/
|
||||||
|
suspend fun <T> T.beginTrackedOperation(op: suspend () -> Boolean) where T : Fragment, T : EuiccChannelFragmentMarker =
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val latestSeq = channel.lpa.notifications.firstOrNull()?.seqNumber ?: 0
|
||||||
|
Log.d(TAG, "Latest notification is $latestSeq before operation")
|
||||||
|
if (op()) {
|
||||||
|
Log.d(TAG, "Operation has requested notification handling")
|
||||||
|
try {
|
||||||
|
// Note that the exact instance of "channel" might have changed here if reconnected;
|
||||||
|
// so we MUST use the automatic getter for "channel"
|
||||||
|
channel.lpa.notifications.filter { it.seqNumber > latestSeq }.forEach {
|
||||||
|
Log.d(TAG, "Handling notification $it")
|
||||||
|
channel.lpa.handleNotification(it.seqNumber)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Ignore any error during notification handling
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Operation complete")
|
||||||
|
}
|
||||||
|
|
||||||
interface EuiccProfilesChangedListener {
|
interface EuiccProfilesChangedListener {
|
||||||
fun onEuiccProfilesChanged()
|
fun onEuiccProfilesChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun <T> T.beginTrackedOperation(op: suspend () -> Boolean) where T: Fragment, T: EuiccChannelFragmentMarker =
|
|
||||||
channel.lpa.beginTrackedOperation(op)
|
|
|
@ -2,14 +2,9 @@ package im.angry.openeuicc.util
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import im.angry.openeuicc.core.EuiccChannel
|
import im.angry.openeuicc.core.EuiccChannel
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||||
import net.typeblog.lpac_jni.LocalProfileInfo
|
import net.typeblog.lpac_jni.LocalProfileInfo
|
||||||
|
|
||||||
const val TAG = "LPAUtils"
|
|
||||||
|
|
||||||
val LocalProfileInfo.displayName: String
|
val LocalProfileInfo.displayName: String
|
||||||
get() = nickName.ifEmpty { name }
|
get() = nickName.ifEmpty { name }
|
||||||
|
|
||||||
|
@ -31,7 +26,7 @@ val List<EuiccChannel>.hasMultipleChips: Boolean
|
||||||
*/
|
*/
|
||||||
fun LocalProfileAssistant.disableActiveProfile(refresh: Boolean): Boolean =
|
fun LocalProfileAssistant.disableActiveProfile(refresh: Boolean): Boolean =
|
||||||
profiles.find { it.isEnabled }?.let {
|
profiles.find { it.isEnabled }?.let {
|
||||||
Log.i(TAG, "Disabling active profile ${it.iccid}")
|
Log.i("LPAUtils", "Disabling active profile ${it.iccid}")
|
||||||
disableProfile(it.iccid, refresh)
|
disableProfile(it.iccid, refresh)
|
||||||
} ?: true
|
} ?: true
|
||||||
|
|
||||||
|
@ -45,34 +40,4 @@ fun LocalProfileAssistant.disableActiveProfileWithUndo(refreshOnDisable: Boolean
|
||||||
profiles.find { it.isEnabled }?.let {
|
profiles.find { it.isEnabled }?.let {
|
||||||
disableProfile(it.iccid, refreshOnDisable)
|
disableProfile(it.iccid, refreshOnDisable)
|
||||||
return { enableProfile(it.iccid) }
|
return { enableProfile(it.iccid) }
|
||||||
} ?: { }
|
} ?: { }
|
||||||
|
|
||||||
/**
|
|
||||||
* Begin a "tracked" operation where notifications may be generated by the eSIM
|
|
||||||
* Automatically handle any newly generated notification during the operation
|
|
||||||
* if the function "op" returns true.
|
|
||||||
*/
|
|
||||||
suspend fun LocalProfileAssistant.beginTrackedOperation(op: suspend () -> Boolean) =
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
beginTrackedOperationBlocking { op() }
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun LocalProfileAssistant.beginTrackedOperationBlocking(op: () -> Boolean) {
|
|
||||||
val latestSeq = notifications.firstOrNull()?.seqNumber ?: 0
|
|
||||||
Log.d(TAG, "Latest notification is $latestSeq before operation")
|
|
||||||
if (op()) {
|
|
||||||
Log.d(TAG, "Operation has requested notification handling")
|
|
||||||
try {
|
|
||||||
// Note that the exact instance of "channel" might have changed here if reconnected;
|
|
||||||
// so we MUST use the automatic getter for "channel"
|
|
||||||
notifications.filter { it.seqNumber > latestSeq }.forEach {
|
|
||||||
Log.d(TAG, "Handling notification $it")
|
|
||||||
handleNotification(it.seqNumber)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// Ignore any error during notification handling
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.d(TAG, "Operation complete")
|
|
||||||
}
|
|
|
@ -12,8 +12,6 @@ import net.typeblog.lpac_jni.LocalProfileInfo
|
||||||
import im.angry.openeuicc.core.EuiccChannel
|
import im.angry.openeuicc.core.EuiccChannel
|
||||||
import im.angry.openeuicc.core.EuiccChannelManager
|
import im.angry.openeuicc.core.EuiccChannelManager
|
||||||
import im.angry.openeuicc.util.*
|
import im.angry.openeuicc.util.*
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.flow.single
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.lang.IllegalStateException
|
import java.lang.IllegalStateException
|
||||||
|
|
||||||
|
@ -228,17 +226,11 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channels[0].lpa.beginTrackedOperationBlocking {
|
return if (channels[0].lpa.deleteProfile(iccid)) {
|
||||||
if (channels[0].lpa.deleteProfile(iccid)) {
|
RESULT_OK
|
||||||
return RESULT_OK
|
} else {
|
||||||
}
|
RESULT_FIRST_USER
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
preferenceRepository.notificationDeleteFlow.first()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_FIRST_USER
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return RESULT_FIRST_USER
|
return RESULT_FIRST_USER
|
||||||
}
|
}
|
||||||
|
@ -291,22 +283,14 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
||||||
return RESULT_FIRST_USER
|
return RESULT_FIRST_USER
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.lpa.beginTrackedOperationBlocking {
|
// Disable any active profile first if present
|
||||||
if (iccid != null) {
|
if (!channel.lpa.disableActiveProfile(false)) {
|
||||||
// Disable any active profile first if present
|
return RESULT_FIRST_USER
|
||||||
channel.lpa.disableActiveProfile(false)
|
}
|
||||||
if (!channel.lpa.enableProfile(iccid)) {
|
|
||||||
return RESULT_FIRST_USER
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!channel.lpa.disableActiveProfile(true)) {
|
|
||||||
return RESULT_FIRST_USER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runBlocking {
|
if (iccid != null) {
|
||||||
// TODO: The enable / disable operations should really be one
|
if (!channel.lpa.enableProfile(iccid)) {
|
||||||
preferenceRepository.notificationEnableFlow.first()
|
return RESULT_FIRST_USER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ interface LocalProfileAssistant {
|
||||||
|
|
||||||
// All blocking functions in this class assume that they are executed on non-Main threads
|
// 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.
|
// The IO context in Kotlin's coroutine library is recommended.
|
||||||
fun enableProfile(iccid: String, refresh: Boolean = true): Boolean
|
fun enableProfile(iccid: String, refresh: Boolean = false): Boolean
|
||||||
fun disableProfile(iccid: String, refresh: Boolean = true): Boolean
|
fun disableProfile(iccid: String, refresh: Boolean = false): Boolean
|
||||||
fun deleteProfile(iccid: String): Boolean
|
fun deleteProfile(iccid: String): Boolean
|
||||||
|
|
||||||
fun downloadProfile(smdp: String, matchingId: String?, imei: String?,
|
fun downloadProfile(smdp: String, matchingId: String?, imei: String?,
|
||||||
|
|
Loading…
Add table
Reference in a new issue