From 93d1c3fd384398ffaefd2b8798728f508e8330c5 Mon Sep 17 00:00:00 2001 From: septs Date: Mon, 10 Mar 2025 23:02:09 +0800 Subject: [PATCH] refactor: profile list --- .../openeuicc/ui/EuiccManagementFragment.kt | 7 +- .../java/im/angry/openeuicc/util/LPAUtils.kt | 6 +- .../openeuicc/service/OpenEuiccService.kt | 12 +- .../net/typeblog/lpac_jni/LocalProfileInfo.kt | 38 +----- .../java/net/typeblog/lpac_jni/LpacJni.kt | 12 +- .../impl/LocalProfileAssistantImpl.kt | 24 +--- .../src/main/jni/lpac-jni/lpac-convertor.c | 57 +++++++++ .../src/main/jni/lpac-jni/lpac-convertor.h | 13 +++ .../lpac-jni/src/main/jni/lpac-jni/lpac-jni.c | 109 ++++++++---------- 9 files changed, 146 insertions(+), 132 deletions(-) create mode 100644 libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.c create mode 100644 libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.h diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt index 12995ff..5b7b21e 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt @@ -43,6 +43,7 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext +import net.typeblog.lpac_jni.ProfileClass open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, EuiccChannelFragmentMarker { @@ -387,9 +388,9 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, profileClass.isVisible = unfilteredProfileListFlow.value profileClass.setText( when (profile.profileClass) { - LocalProfileInfo.Clazz.Testing -> R.string.profile_class_testing - LocalProfileInfo.Clazz.Provisioning -> R.string.profile_class_provisioning - LocalProfileInfo.Clazz.Operational -> R.string.profile_class_operational + ProfileClass.Testing -> R.string.profile_class_testing + ProfileClass.Provisioning -> R.string.profile_class_provisioning + ProfileClass.Operational -> R.string.profile_class_operational } ) iccid.text = profile.iccid diff --git a/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt b/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt index 9f95412..cc1001b 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt @@ -5,6 +5,8 @@ import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.core.EuiccChannelManager import net.typeblog.lpac_jni.LocalProfileAssistant import net.typeblog.lpac_jni.LocalProfileInfo +import net.typeblog.lpac_jni.ProfileClass +import net.typeblog.lpac_jni.ProfileState const val TAG = "LPAUtils" @@ -13,10 +15,10 @@ val LocalProfileInfo.displayName: String val LocalProfileInfo.isEnabled: Boolean - get() = state == LocalProfileInfo.State.Enabled + get() = state == ProfileState.Enabled val List.operational: List - get() = filter { it.profileClass == LocalProfileInfo.Clazz.Operational } + get() = filter { it.profileClass == ProfileClass.Operational } val List.enabled: LocalProfileInfo? get() = find { it.isEnabled } diff --git a/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt b/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt index 02b3baf..8ce7958 100644 --- a/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt +++ b/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt @@ -15,6 +15,8 @@ import im.angry.openeuicc.util.* import kotlinx.coroutines.delay import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking +import net.typeblog.lpac_jni.ProfileClass +import net.typeblog.lpac_jni.ProfileState import kotlin.IllegalStateException class OpenEuiccService : EuiccService(), OpenEuiccContextMarker { @@ -200,15 +202,15 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker { setServiceProviderName(it.providerName) setState( when (it.state) { - LocalProfileInfo.State.Enabled -> EuiccProfileInfo.PROFILE_STATE_ENABLED - LocalProfileInfo.State.Disabled -> EuiccProfileInfo.PROFILE_STATE_DISABLED + ProfileState.Enabled -> EuiccProfileInfo.PROFILE_STATE_ENABLED + ProfileState.Disabled -> EuiccProfileInfo.PROFILE_STATE_DISABLED } ) setProfileClass( when (it.profileClass) { - LocalProfileInfo.Clazz.Testing -> EuiccProfileInfo.PROFILE_CLASS_TESTING - LocalProfileInfo.Clazz.Provisioning -> EuiccProfileInfo.PROFILE_CLASS_PROVISIONING - LocalProfileInfo.Clazz.Operational -> EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL + ProfileClass.Testing -> EuiccProfileInfo.PROFILE_CLASS_TESTING + ProfileClass.Provisioning -> EuiccProfileInfo.PROFILE_CLASS_PROVISIONING + ProfileClass.Operational -> EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL } ) }.build() diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileInfo.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileInfo.kt index a7e296f..96e16ef 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileInfo.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileInfo.kt @@ -2,42 +2,14 @@ package net.typeblog.lpac_jni data class LocalProfileInfo( val iccid: String, - val state: State, + val state: ProfileState, val name: String, val nickName: String, val providerName: String, val isdpAID: String, - val profileClass: Clazz -) { - enum class State { - Enabled, - Disabled; + val profileClass: ProfileClass +) - companion object { - @JvmStatic - fun fromString(str: String?) = - when (str?.lowercase()) { - "enabled" -> Enabled - "disabled" -> Disabled - else -> Disabled - } - } - } +enum class ProfileState { Enabled, Disabled } - enum class Clazz { - Testing, - Provisioning, - Operational; - - companion object { - @JvmStatic - fun fromString(str: String?) = - when (str?.lowercase()) { - "test" -> Testing - "provisioning" -> Provisioning - "operational" -> Operational - else -> Operational - } - } - } -} \ No newline at end of file +enum class ProfileClass { Testing, Provisioning, Operational } diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt index fa9474f..062d218 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt @@ -19,7 +19,7 @@ internal object LpacJni { // es10c // null returns signify errors external fun es10cGetEid(handle: Long): String? - external fun es10cGetProfilesInfo(handle: Long): Long + external fun es10cGetProfilesInfo(handle: Long, profiles: List): Long external fun es10cEnableProfile(handle: Long, iccid: String, refresh: Boolean): Int external fun es10cDisableProfile(handle: Long, iccid: String, refresh: Boolean): Int external fun es10cDeleteProfile(handle: Long, iccid: String): Int @@ -47,16 +47,6 @@ internal object LpacJni { // C String arrays external fun stringArrNext(curr: Long): Long external fun stringDeref(curr: Long): String - // Profiles - external fun profilesNext(curr: Long): Long - external fun profilesFree(head: Long): Long - external fun profileGetIccid(curr: Long): String - external fun profileGetIsdpAid(curr: Long): String - external fun profileGetName(curr: Long): String - external fun profileGetNickname(curr: Long): String - external fun profileGetServiceProvider(curr: Long): String - external fun profileGetStateString(curr: Long): String - external fun profileGetClassString(curr: Long): String // Notifications external fun notificationsNext(curr: Long): Long external fun notificationGetSeq(curr: Long): Long diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 3674f4f..29aea22 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -107,26 +107,10 @@ class LocalProfileAssistantImpl( override val profiles: List @Synchronized get() { - val head = LpacJni.es10cGetProfilesInfo(contextHandle) - var curr = head - val ret = mutableListOf() - while (curr != 0L) { - val state = LocalProfileInfo.State.fromString(LpacJni.profileGetStateString(curr)) - val clazz = LocalProfileInfo.Clazz.fromString(LpacJni.profileGetClassString(curr)) - ret.add(LocalProfileInfo( - LpacJni.profileGetIccid(curr), - state, - LpacJni.profileGetName(curr), - LpacJni.profileGetNickname(curr), - LpacJni.profileGetServiceProvider(curr), - LpacJni.profileGetIsdpAid(curr), - clazz - )) - curr = LpacJni.profilesNext(curr) - } - - LpacJni.profilesFree(curr) - return ret + val profiles = mutableListOf() + val ret = LpacJni.es10cGetProfilesInfo(contextHandle, profiles) + if (ret < 0) throw IllegalStateException("Failed to get profiles") + return profiles } override val notifications: List diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.c new file mode 100644 index 0000000..76cd4c4 --- /dev/null +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.c @@ -0,0 +1,57 @@ +#include "lpac-convertor.h" + +static jobject profile_state_enabled; +static jobject profile_state_disabled; +static jobject profile_class_operational; +static jobject profile_class_provisioning; +static jobject profile_class_testing; + +static jobject bind_static_field(JNIEnv *env, jclass clazz, const char *name, const char *sig) { + jfieldID field = (*env)->GetStaticFieldID(env, clazz, name, sig); + jobject bound = (*env)->GetStaticObjectField(env, clazz, field); + return (*env)->NewGlobalRef(env, bound); +} + +#define BIND_PROFILE_STATE_STATIC_FIELD(NAME, FIELD) \ + profile_state_##NAME = bind_static_field(env, profile_state_class, FIELD, "L" PROFILE_STATE_CLASS ";") + +#define BIND_PROFILE_CLASS_STATIC_FIELD(NAME, FIELD) \ + profile_class_##NAME = bind_static_field(env, profile_class_class, FIELD, "L" PROFILE_CLASS_CLASS ";") + +void lpac_convertor_init(JNIEnv *env) { + jclass profile_state_class = (*env)->FindClass(env, PROFILE_STATE_CLASS); + BIND_PROFILE_STATE_STATIC_FIELD(enabled, "Enabled"); + BIND_PROFILE_STATE_STATIC_FIELD(disabled, "Disabled"); + + jclass profile_class_class = (*env)->FindClass(env, PROFILE_CLASS_CLASS); + BIND_PROFILE_CLASS_STATIC_FIELD(operational, "Operational"); + BIND_PROFILE_CLASS_STATIC_FIELD(provisioning, "Provisioning"); + BIND_PROFILE_CLASS_STATIC_FIELD(testing, "Testing"); +} + +#undef BIND_PROFILE_STATE_STATIC_FIELD +#undef BIND_PROFILE_CLASS_STATIC_FIELD + +jobject to_profile_state(enum es10c_profile_state profile_state) { + switch (profile_state) { + case ES10C_PROFILE_STATE_ENABLED: + return profile_state_enabled; + case ES10C_PROFILE_STATE_DISABLED: + return profile_state_disabled; + default: + return NULL; + } +} + +jobject to_profile_class(enum es10c_profile_class profile_class) { + switch (profile_class) { + case ES10C_PROFILE_CLASS_OPERATIONAL: + return profile_class_operational; + case ES10C_PROFILE_CLASS_PROVISIONING: + return profile_class_provisioning; + case ES10C_PROFILE_CLASS_TEST: + return profile_class_testing; + default: + return NULL; + } +} \ No newline at end of file diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.h new file mode 100644 index 0000000..bfbc1af --- /dev/null +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +#define PROFILE_STATE_CLASS "net/typeblog/lpac_jni/ProfileState" +#define PROFILE_CLASS_CLASS "net/typeblog/lpac_jni/ProfileClass" + +void lpac_convertor_init(JNIEnv *env); + +jobject to_profile_state(enum es10c_profile_state profile_state); + +jobject to_profile_class(enum es10c_profile_class profile_class); diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c index ca319db..0535e61 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c @@ -9,6 +9,7 @@ #include "lpac-download.h" #include "lpac-notifications.h" #include "interface-wrapper.h" +#include "lpac-convertor.h" JavaVM *jvm = NULL; @@ -17,12 +18,16 @@ jstring empty_string; jclass string_class; jmethodID string_constructor; +#define LOCAL_PROFILE_INFO_CLASS "net/typeblog/lpac_jni/LocalProfileInfo" + jint JNI_OnLoad(JavaVM *vm, void *reserved) { jvm = vm; + LPAC_JNI_SETUP_ENV; + interface_wrapper_init(); + lpac_convertor_init(env); lpac_download_init(); - LPAC_JNI_SETUP_ENV; string_class = (*env)->FindClass(env, "java/lang/String"); string_class = (*env)->NewGlobalRef(env, string_class); string_constructor = (*env)->GetMethodID(env, string_class, "", @@ -100,12 +105,12 @@ jstring toJString(JNIEnv *env, const char *pat) { jbyteArray bytes = NULL; jstring encoding = NULL; jstring jstr = NULL; - int len; + jsize len; if (pat == NULL) return (*env)->NewLocalRef(env, empty_string); - len = strlen(pat); + len = (jsize) strlen(pat); bytes = (*env)->NewByteArray(env, len); (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) pat); encoding = (*env)->NewStringUTF(env, "utf-8"); @@ -130,67 +135,56 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cGetEid(JNIEnv *env, jobject thiz, jlong } JNIEXPORT jlong JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_es10cGetProfilesInfo(JNIEnv *env, jobject thiz, jlong handle) { +Java_net_typeblog_lpac_1jni_LpacJni_es10cGetProfilesInfo( + JNIEnv *env, + __attribute__((unused)) jobject thiz, + jlong handle, + jobject profiles +) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; struct es10c_profile_info_list *info = NULL; + int ret = es10c_get_profiles_info(ctx, &info); + if (ret < 0) return ret; - if (es10c_get_profiles_info(ctx, &info) < 0) { - return 0; + jclass profile_list_class = (*env)->GetObjectClass(env, profiles); + jmethodID add_profile = (*env)->GetMethodID(env, profile_list_class, "add", + "(Ljava/lang/Object;)Z"); + + jclass profile_info_class = (*env)->FindClass(env, LOCAL_PROFILE_INFO_CLASS); + jmethodID profile_info_class_constructor = (*env)->GetMethodID( + env, profile_info_class, "", + "(" + "Ljava/lang/String;" // iccid + "Lnet/typeblog/lpac_jni/ProfileState;" + "Ljava/lang/String;" // name + "Ljava/lang/String;" // nickname + "Ljava/lang/String;" // provider name + "Ljava/lang/String;" // ISD-P AID + "Lnet/typeblog/lpac_jni/ProfileClass;" + ")" + "V" // (returns) void + ); + + jobject element = NULL; + while (info) { + element = (*env)->NewObject( + env, profile_info_class, profile_info_class_constructor, + toJString(env, info->iccid), + to_profile_state(info->profileState), + toJString(env, info->profileName), + toJString(env, info->profileNickname), + toJString(env, info->serviceProviderName), + toJString(env, info->isdpAid), + to_profile_class(info->profileClass) + ); + (*env)->CallBooleanMethod(env, profiles, add_profile, element); + info = info->next; } - return (jlong) info; + es10c_profile_info_list_free_all(info); + return ret; } -JNIEXPORT jstring JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_profileGetStateString(JNIEnv *env, jobject thiz, jlong curr) { - struct es10c_profile_info_list *info = (struct es10c_profile_info_list *) curr; - const char *profileStateStr = NULL; - - switch (info->profileState) { - case ES10C_PROFILE_STATE_ENABLED: - profileStateStr = "enabled"; - break; - case ES10C_PROFILE_STATE_DISABLED: - profileStateStr = "disabled"; - break; - default: - profileStateStr = "unknown"; - } - - return toJString(env, profileStateStr); -} - -JNIEXPORT jstring JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_profileGetClassString(JNIEnv *env, jobject thiz, jlong curr) { - struct es10c_profile_info_list *info = (struct es10c_profile_info_list *) curr; - const char *profileClassStr = NULL; - - switch (info->profileClass) { - case ES10C_PROFILE_CLASS_TEST: - profileClassStr = "test"; - break; - case ES10C_PROFILE_CLASS_PROVISIONING: - profileClassStr = "provisioning"; - break; - case ES10C_PROFILE_CLASS_OPERATIONAL: - profileClassStr = "operational"; - break; - default: - profileClassStr = "unknown"; - break; - } - - return toJString(env, profileClassStr); -} - -LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(struct es10c_profile_info_list, profiles) -LPAC_JNI_STRUCT_FREE(struct es10c_profile_info_list, profiles, es10c_profile_info_list_free_all) -LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, iccid, Iccid) -LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, isdpAid, IsdpAid) -LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, profileName, Name) -LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, profileNickname, Nickname) -LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, serviceProviderName, ServiceProvider) - JNIEXPORT jint JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10cEnableProfile(JNIEnv *env, jobject thiz, jlong handle, jstring iccid, jboolean refresh) { @@ -259,7 +253,6 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject th return (jlong) info; } - JNIEXPORT jint JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10cEuiccMemoryReset(JNIEnv *env, jobject thiz, jlong handle) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; -- 2.45.3