From a56c2b6d89aa60e4d666d1f32526d6a38e2083f1 Mon Sep 17 00:00:00 2001 From: septs Date: Mon, 10 Mar 2025 13:54:34 +0800 Subject: [PATCH] refactor: notification (lpac-jni) --- .../openeuicc/ui/NotificationsActivity.kt | 17 +-- .../lpac_jni/LocalProfileNotification.kt | 29 ++-- .../java/net/typeblog/lpac_jni/LpacJni.kt | 9 +- .../impl/LocalProfileAssistantImpl.kt | 18 +-- .../lpac-jni/src/main/jni/lpac-jni/lpac-jni.c | 4 +- .../main/jni/lpac-jni/lpac-notifications.c | 136 +++++++++++++----- .../main/jni/lpac-jni/lpac-notifications.h | 2 + 7 files changed, 126 insertions(+), 89 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt index 21a2d40..f40340d 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt @@ -26,6 +26,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import net.typeblog.lpac_jni.LocalProfileNotification +import net.typeblog.lpac_jni.ProfileManagementOperation class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker { private lateinit var swipeRefresh: SwipeRefreshLayout @@ -163,14 +164,14 @@ class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker { } - private fun operationToLocalizedText(operation: LocalProfileNotification.Operation) = - root.context.getText( - when (operation) { - LocalProfileNotification.Operation.Install -> R.string.profile_notification_operation_download - LocalProfileNotification.Operation.Delete -> R.string.profile_notification_operation_delete - LocalProfileNotification.Operation.Enable -> R.string.profile_notification_operation_enable - LocalProfileNotification.Operation.Disable -> R.string.profile_notification_operation_disable - }) + private fun operationToLocalizedText(operation: ProfileManagementOperation) = + root.context.getText(when (operation) { + ProfileManagementOperation.Install -> R.string.profile_notification_operation_download + ProfileManagementOperation.Delete -> R.string.profile_notification_operation_delete + ProfileManagementOperation.Enable -> R.string.profile_notification_operation_enable + ProfileManagementOperation.Disable -> R.string.profile_notification_operation_disable + else -> throw IllegalStateException("Unknown operation") + }) fun updateNotification(value: LocalProfileNotificationWrapper) { notification = value diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileNotification.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileNotification.kt index 57cc8cf..1432066 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileNotification.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileNotification.kt @@ -2,26 +2,15 @@ package net.typeblog.lpac_jni data class LocalProfileNotification( val seqNumber: Long, - val profileManagementOperation: Operation, + val profileManagementOperation: ProfileManagementOperation, val notificationAddress: String, val iccid: String, -) { - enum class Operation { - Install, - Enable, - Disable, - Delete; +) - companion object { - @JvmStatic - fun fromString(str: String?) = - when (str?.lowercase()) { - "install" -> Install - "enable" -> Enable - "disable" -> Disable - "delete" -> Delete - else -> throw IllegalArgumentException("Unknown operation $str") - } - } - } -} \ No newline at end of file +enum class ProfileManagementOperation { + Install, + Enable, + Disable, + Delete, + Unknown, +} 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..878ab1d 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 @@ -26,7 +26,7 @@ internal object LpacJni { external fun es10cSetNickname(handle: Long, iccid: String, nickNullTerminated: ByteArray): Int // es10b - external fun es10bListNotification(handle: Long): Long // A native pointer to a linked list. Handle with linked list-related methods below. May be 0 (null) + external fun es10bListNotification(handle: Long, elements: List): Int external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int // es9p + es10b @@ -57,13 +57,6 @@ internal object LpacJni { 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 - external fun notificationGetOperationString(curr: Long): String - external fun notificationGetAddress(curr: Long): String - external fun notificationGetIccid(curr: Long): String - external fun notificationsFree(head: Long) // EuiccInfo2 external fun euiccInfo2Free(info: Long) external fun euiccInfo2GetSGP22Version(info: Long): String 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..d23fd31 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 @@ -132,20 +132,10 @@ class LocalProfileAssistantImpl( override val notifications: List @Synchronized get() { - val head = LpacJni.es10bListNotification(contextHandle) - var curr = head - val ret = mutableListOf() - while (curr != 0L) { - ret.add(LocalProfileNotification( - LpacJni.notificationGetSeq(curr), - LocalProfileNotification.Operation.fromString(LpacJni.notificationGetOperationString(curr)), - LpacJni.notificationGetAddress(curr), - LpacJni.notificationGetIccid(curr), - )) - curr = LpacJni.notificationsNext(curr) - } - LpacJni.notificationsFree(head) - return ret.sortedBy { it.seqNumber }.reversed() + val notifications = mutableListOf() + val ret = LpacJni.es10bListNotification(contextHandle, notifications) + if (ret < 0) throw IllegalStateException("Failed to list notifications") + return notifications.sortedBy(LocalProfileNotification::seqNumber).reversed() } override val eID: String 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..066aed0 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 @@ -19,10 +19,12 @@ jmethodID string_constructor; jint JNI_OnLoad(JavaVM *vm, void *reserved) { jvm = vm; + LPAC_JNI_SETUP_ENV; + interface_wrapper_init(); lpac_download_init(); + lpac_notifications_init(env); - 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, "", diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c index cf402cf..7baa673 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c @@ -4,15 +4,107 @@ #include #include -JNIEXPORT jlong JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_es10bListNotification(JNIEnv *env, jobject thiz, jlong handle) { +jclass local_profile_notification_class; + +jobject profile_management_operation_install; +jobject profile_management_operation_enable; +jobject profile_management_operation_disable; +jobject profile_management_operation_delete; +jobject profile_management_operation_unknown; + +jmethodID local_profile_notification_constructor; + +#define LOCAL_PROFILE_NOTIFICATION_CLASS "net/typeblog/lpac_jni/LocalProfileNotification" +#define PROFILE_MANAGEMENT_OPERATION_CLASS "net/typeblog/lpac_jni/ProfileManagementOperation" + +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_NOTIFICATION_OPERATION_FIELD(NAME, FIELD) \ + profile_management_operation_##NAME = bind_static_field( \ + env, profile_management_operation_class, FIELD, "L" PROFILE_MANAGEMENT_OPERATION_CLASS ";") + +void lpac_notifications_init(JNIEnv *env) { + local_profile_notification_class = (*env)->FindClass(env, LOCAL_PROFILE_NOTIFICATION_CLASS); + local_profile_notification_class = (*env)->NewGlobalRef(env, local_profile_notification_class); + local_profile_notification_constructor = (*env)->GetMethodID( + env, local_profile_notification_class, "", + "(" + "J" // seqNumber + "L" PROFILE_MANAGEMENT_OPERATION_CLASS ";" // profileManagementOperation + "Ljava/lang/String;" // notificationAddress + "Ljava/lang/String;" // iccid + ")" + "V" // (returns) void + ); + + jclass profile_management_operation_class = (*env)->FindClass( + env, PROFILE_MANAGEMENT_OPERATION_CLASS); + profile_management_operation_class = (*env)->NewGlobalRef( + env, profile_management_operation_class); + + BIND_NOTIFICATION_OPERATION_FIELD(install, "Install"); + BIND_NOTIFICATION_OPERATION_FIELD(delete, "Delete"); + BIND_NOTIFICATION_OPERATION_FIELD(enable, "Enable"); + BIND_NOTIFICATION_OPERATION_FIELD(disable, "Disable"); + BIND_NOTIFICATION_OPERATION_FIELD(unknown, "Unknown"); +} + +#undef BIND_NOTIFICATION_OPERATION_FIELD + +static jobject to_profile_management_operation(enum es10b_profile_management_operation operation) { + switch (operation) { + case ES10B_PROFILE_MANAGEMENT_OPERATION_INSTALL: + return profile_management_operation_install; + case ES10B_PROFILE_MANAGEMENT_OPERATION_DELETE: + return profile_management_operation_delete; + case ES10B_PROFILE_MANAGEMENT_OPERATION_ENABLE: + return profile_management_operation_enable; + case ES10B_PROFILE_MANAGEMENT_OPERATION_DISABLE: + return profile_management_operation_disable; + default: + return profile_management_operation_unknown; + } +} + +JNIEXPORT jint JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_es10bListNotification( + JNIEnv *env, + __attribute__((unused)) jobject thiz, + jlong handle, + jobject notifications +) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; - struct es10b_notification_metadata_list *info = NULL; + struct es10b_notification_metadata_list *metadata = NULL; + int ret = es10b_list_notification(ctx, &metadata); + if (ret < 0) { + goto out; + } - if (es10b_list_notification(ctx, &info) < 0) - return 0; + jmethodID add_notification = (*env)->GetMethodID( + env, + (*env)->GetObjectClass(env, notifications), + "add", "(Ljava/lang/Object;)Z" + ); - return (jlong) info; + jobject element; + while (metadata) { + jlong sequence_number = metadata->seqNumber; + jobject operation = to_profile_management_operation(metadata->profileManagementOperation); + jstring address = toJString(env, metadata->notificationAddress); + jstring iccid = toJString(env, metadata->iccid); + element = (*env)->NewObject( + env, local_profile_notification_class, local_profile_notification_constructor, + sequence_number, operation, address, iccid); + (*env)->CallBooleanMethod(env, notifications, add_notification, element); + metadata = metadata->next; + } + out: + es10b_notification_metadata_list_free_all(metadata); + return ret; } JNIEXPORT jint JNICALL @@ -45,35 +137,3 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10bDeleteNotification(JNIEnv *env, jobject struct euicc_ctx *ctx = (struct euicc_ctx *) handle; return es10b_remove_notification_from_list(ctx, (unsigned long) seq_number); } - -JNIEXPORT jstring JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_notificationGetOperationString(JNIEnv *env, jobject thiz, - jlong curr) { - struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr; - const char *profileManagementOperationStr = NULL; - switch (info->profileManagementOperation) { - case ES10B_PROFILE_MANAGEMENT_OPERATION_INSTALL: - profileManagementOperationStr = "install"; - break; - case ES10B_PROFILE_MANAGEMENT_OPERATION_DELETE: - profileManagementOperationStr = "delete"; - break; - case ES10B_PROFILE_MANAGEMENT_OPERATION_ENABLE: - profileManagementOperationStr = "enable"; - break; - case ES10B_PROFILE_MANAGEMENT_OPERATION_DISABLE: - profileManagementOperationStr = "disable"; - break; - default: - profileManagementOperationStr = "unknown"; - break; - } - - return toJString(env, profileManagementOperationStr); -} - -LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(struct es10b_notification_metadata_list, notifications) -LPAC_JNI_STRUCT_FREE(struct es10b_notification_metadata_list, notifications, es10b_notification_metadata_list_free_all) -LPAC_JNI_STRUCT_GETTER_LONG(struct es10b_notification_metadata_list, notification, seqNumber, Seq) -LPAC_JNI_STRUCT_GETTER_STRING(struct es10b_notification_metadata_list, notification, notificationAddress, Address) -LPAC_JNI_STRUCT_GETTER_STRING(struct es10b_notification_metadata_list, notification, iccid, Iccid) diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.h index 511de2f..0f13e6e 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.h @@ -2,3 +2,5 @@ #include #include "lpac-jni.h" + +void lpac_notifications_init(JNIEnv *env); -- 2.45.3