Compare commits

...

1 commit

Author SHA1 Message Date
5d22fb5b2a
refactor: notification (lpac-jni) 2025-03-10 14:07:14 +08:00
7 changed files with 119 additions and 89 deletions

View file

@ -26,6 +26,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import net.typeblog.lpac_jni.LocalProfileNotification import net.typeblog.lpac_jni.LocalProfileNotification
import net.typeblog.lpac_jni.ProfileManagementOperation
class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker { class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker {
private lateinit var swipeRefresh: SwipeRefreshLayout private lateinit var swipeRefresh: SwipeRefreshLayout
@ -163,14 +164,14 @@ class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker {
} }
private fun operationToLocalizedText(operation: LocalProfileNotification.Operation) = private fun operationToLocalizedText(operation: ProfileManagementOperation) =
root.context.getText( root.context.getText(when (operation) {
when (operation) { ProfileManagementOperation.Install -> R.string.profile_notification_operation_download
LocalProfileNotification.Operation.Install -> R.string.profile_notification_operation_download ProfileManagementOperation.Delete -> R.string.profile_notification_operation_delete
LocalProfileNotification.Operation.Delete -> R.string.profile_notification_operation_delete ProfileManagementOperation.Enable -> R.string.profile_notification_operation_enable
LocalProfileNotification.Operation.Enable -> R.string.profile_notification_operation_enable ProfileManagementOperation.Disable -> R.string.profile_notification_operation_disable
LocalProfileNotification.Operation.Disable -> R.string.profile_notification_operation_disable else -> throw IllegalStateException("Unknown operation")
}) })
fun updateNotification(value: LocalProfileNotificationWrapper) { fun updateNotification(value: LocalProfileNotificationWrapper) {
notification = value notification = value

View file

@ -2,26 +2,15 @@ package net.typeblog.lpac_jni
data class LocalProfileNotification( data class LocalProfileNotification(
val seqNumber: Long, val seqNumber: Long,
val profileManagementOperation: Operation, val profileManagementOperation: ProfileManagementOperation,
val notificationAddress: String, val notificationAddress: String,
val iccid: String, val iccid: String,
) { )
enum class Operation {
Install,
Enable,
Disable,
Delete;
companion object { enum class ProfileManagementOperation {
@JvmStatic Install,
fun fromString(str: String?) = Enable,
when (str?.lowercase()) { Disable,
"install" -> Install Delete,
"enable" -> Enable Unknown,
"disable" -> Disable }
"delete" -> Delete
else -> throw IllegalArgumentException("Unknown operation $str")
}
}
}
}

View file

@ -26,7 +26,7 @@ internal object LpacJni {
external fun es10cSetNickname(handle: Long, iccid: String, nickNullTerminated: ByteArray): Int external fun es10cSetNickname(handle: Long, iccid: String, nickNullTerminated: ByteArray): Int
// es10b // 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<LocalProfileNotification>): Int
external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int
// es9p + es10b // es9p + es10b
@ -57,13 +57,6 @@ internal object LpacJni {
external fun profileGetServiceProvider(curr: Long): String external fun profileGetServiceProvider(curr: Long): String
external fun profileGetStateString(curr: Long): String external fun profileGetStateString(curr: Long): String
external fun profileGetClassString(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 // EuiccInfo2
external fun euiccInfo2Free(info: Long) external fun euiccInfo2Free(info: Long)
external fun euiccInfo2GetSGP22Version(info: Long): String external fun euiccInfo2GetSGP22Version(info: Long): String

View file

@ -132,20 +132,10 @@ class LocalProfileAssistantImpl(
override val notifications: List<LocalProfileNotification> override val notifications: List<LocalProfileNotification>
@Synchronized @Synchronized
get() { get() {
val head = LpacJni.es10bListNotification(contextHandle) val notifications = mutableListOf<LocalProfileNotification>()
var curr = head val ret = LpacJni.es10bListNotification(contextHandle, notifications)
val ret = mutableListOf<LocalProfileNotification>() if (ret < 0) throw IllegalStateException("Failed to list notifications")
while (curr != 0L) { return notifications.sortedBy(LocalProfileNotification::seqNumber).reversed()
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()
} }
override val eID: String override val eID: String

View file

@ -19,10 +19,12 @@ jmethodID string_constructor;
jint JNI_OnLoad(JavaVM *vm, void *reserved) { jint JNI_OnLoad(JavaVM *vm, void *reserved) {
jvm = vm; jvm = vm;
LPAC_JNI_SETUP_ENV;
interface_wrapper_init(); interface_wrapper_init();
lpac_download_init(); lpac_download_init();
lpac_notifications_init(env);
LPAC_JNI_SETUP_ENV;
string_class = (*env)->FindClass(env, "java/lang/String"); string_class = (*env)->FindClass(env, "java/lang/String");
string_class = (*env)->NewGlobalRef(env, string_class); string_class = (*env)->NewGlobalRef(env, string_class);
string_constructor = (*env)->GetMethodID(env, string_class, "<init>", string_constructor = (*env)->GetMethodID(env, string_class, "<init>",

View file

@ -4,15 +4,100 @@
#include <malloc.h> #include <malloc.h>
#include <syslog.h> #include <syslog.h>
JNIEXPORT jlong JNICALL jclass local_profile_notification_class;
Java_net_typeblog_lpac_1jni_LpacJni_es10bListNotification(JNIEnv *env, jobject thiz, jlong handle) {
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, "<init>",
"(JL" PROFILE_MANAGEMENT_OPERATION_CLASS ";Ljava/lang/String;Ljava/lang/String;)V");
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 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) jmethodID add_notification = (*env)->GetMethodID(
return 0; 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 JNIEXPORT jint JNICALL
@ -45,35 +130,3 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10bDeleteNotification(JNIEnv *env, jobject
struct euicc_ctx *ctx = (struct euicc_ctx *) handle; struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
return es10b_remove_notification_from_list(ctx, (unsigned long) seq_number); 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)

View file

@ -2,3 +2,5 @@
#include <jni.h> #include <jni.h>
#include "lpac-jni.h" #include "lpac-jni.h"
void lpac_notifications_init(JNIEnv *env);