Compare commits
1 commit
378380fe45
...
92a85771a2
Author | SHA1 | Date | |
---|---|---|---|
92a85771a2 |
3 changed files with 109 additions and 17 deletions
|
@ -380,6 +380,16 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
|
||||||
getString(R.string.task_profile_download_failure),
|
getString(R.string.task_profile_download_failure),
|
||||||
R.drawable.ic_task_sim_card_download
|
R.drawable.ic_task_sim_card_download
|
||||||
) {
|
) {
|
||||||
|
val callback = object : ProfileDownloadCallback {
|
||||||
|
override fun onStateUpdate(state: ProfileDownloadCallback.DownloadState) {
|
||||||
|
if (state.progress == 0) return
|
||||||
|
foregroundTaskState.value = ForegroundTaskState.InProgress(state.progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProfileMetadata(metadata: ProfileDownloadCallback.ProfileMetadata) {
|
||||||
|
Log.d(TAG, "Received profile metadata: $metadata")
|
||||||
|
}
|
||||||
|
}
|
||||||
euiccChannelManager.beginTrackedOperation(slotId, portId) {
|
euiccChannelManager.beginTrackedOperation(slotId, portId) {
|
||||||
euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
|
euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
|
||||||
channel.lpa.downloadProfile(
|
channel.lpa.downloadProfile(
|
||||||
|
@ -387,13 +397,8 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
|
||||||
matchingId,
|
matchingId,
|
||||||
imei,
|
imei,
|
||||||
confirmationCode,
|
confirmationCode,
|
||||||
object : ProfileDownloadCallback {
|
callback
|
||||||
override fun onStateUpdate(state: ProfileDownloadCallback.DownloadState) {
|
)
|
||||||
if (state.progress == 0) return
|
|
||||||
foregroundTaskState.value =
|
|
||||||
ForegroundTaskState.InProgress(state.progress)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
preferenceRepository.notificationDownloadFlow.first()
|
preferenceRepository.notificationDownloadFlow.first()
|
||||||
|
|
|
@ -2,15 +2,14 @@ package net.typeblog.lpac_jni
|
||||||
|
|
||||||
interface ProfileDownloadCallback {
|
interface ProfileDownloadCallback {
|
||||||
companion object {
|
companion object {
|
||||||
fun lookupStateFromProgress(progress: Int): DownloadState =
|
fun lookupStateFromProgress(progress: Int): DownloadState = when (progress) {
|
||||||
when (progress) {
|
0 -> DownloadState.Preparing
|
||||||
0 -> DownloadState.Preparing
|
20 -> DownloadState.Connecting
|
||||||
20 -> DownloadState.Connecting
|
40 -> DownloadState.Authenticating
|
||||||
40 -> DownloadState.Authenticating
|
60 -> DownloadState.Downloading
|
||||||
60 -> DownloadState.Downloading
|
80 -> DownloadState.Finalizing
|
||||||
80 -> DownloadState.Finalizing
|
else -> throw IllegalArgumentException("Unknown state")
|
||||||
else -> throw IllegalArgumentException("Unknown state")
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class DownloadState(val progress: Int) {
|
enum class DownloadState(val progress: Int) {
|
||||||
|
@ -21,5 +20,16 @@ interface ProfileDownloadCallback {
|
||||||
Finalizing(80), // load bpp
|
Finalizing(80), // load bpp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ProfileMetadata(
|
||||||
|
val iccid: String,
|
||||||
|
val serviceProviderName: String?,
|
||||||
|
val profileName: String?,
|
||||||
|
val iconType: String?,
|
||||||
|
val icon: String?,
|
||||||
|
val profileClass: String?,
|
||||||
|
)
|
||||||
|
|
||||||
fun onStateUpdate(state: DownloadState)
|
fun onStateUpdate(state: DownloadState)
|
||||||
|
|
||||||
|
fun onProfileMetadata(metadata: ProfileMetadata)
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <euicc/es8p.h>
|
||||||
#include <euicc/es9p.h>
|
#include <euicc/es9p.h>
|
||||||
#include <euicc/es10b.h>
|
#include <euicc/es10b.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -12,6 +13,9 @@ jobject download_state_downloading;
|
||||||
jobject download_state_finalizing;
|
jobject download_state_finalizing;
|
||||||
|
|
||||||
jmethodID on_state_update;
|
jmethodID on_state_update;
|
||||||
|
jmethodID on_profile_metadata;
|
||||||
|
|
||||||
|
#define PROFILE_METADATA_CLASS "net/typeblog/lpac_jni/ProfileDownloadCallback$ProfileMetadata"
|
||||||
|
|
||||||
void lpac_download_init() {
|
void lpac_download_init() {
|
||||||
LPAC_JNI_SETUP_ENV;
|
LPAC_JNI_SETUP_ENV;
|
||||||
|
@ -54,6 +58,65 @@ void lpac_download_init() {
|
||||||
"net/typeblog/lpac_jni/ProfileDownloadCallback");
|
"net/typeblog/lpac_jni/ProfileDownloadCallback");
|
||||||
on_state_update = (*env)->GetMethodID(env, download_callback_class, "onStateUpdate",
|
on_state_update = (*env)->GetMethodID(env, download_callback_class, "onStateUpdate",
|
||||||
"(Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;)V");
|
"(Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;)V");
|
||||||
|
on_profile_metadata = (*env)->GetMethodID(env, download_callback_class, "onProfileMetadata",
|
||||||
|
"(L" PROFILE_METADATA_CLASS ";)V");
|
||||||
|
}
|
||||||
|
|
||||||
|
static jobject build_profile_metadata(JNIEnv *env, struct es8p_metadata *metadata) {
|
||||||
|
if (metadata == NULL) return NULL;
|
||||||
|
|
||||||
|
jclass profile_metadata_class = (*env)->FindClass(env, PROFILE_METADATA_CLASS);
|
||||||
|
jmethodID profile_metadata_constructor = (*env)->GetMethodID(
|
||||||
|
env, profile_metadata_class, "<init>",
|
||||||
|
"("
|
||||||
|
"Ljava/lang/String;" // iccid
|
||||||
|
"Ljava/lang/String;" // serviceProviderName
|
||||||
|
"Ljava/lang/String;" // profileName
|
||||||
|
"Ljava/lang/String;" // iconType
|
||||||
|
"Ljava/lang/String;" // icon (base64)
|
||||||
|
"Ljava/lang/String;" // profileClass
|
||||||
|
")V"
|
||||||
|
);
|
||||||
|
|
||||||
|
const char *icon_type;
|
||||||
|
const char *profile_class;
|
||||||
|
|
||||||
|
switch (metadata->iconType) {
|
||||||
|
case ES10C_ICON_TYPE_JPEG:
|
||||||
|
icon_type = "jpeg";
|
||||||
|
break;
|
||||||
|
case ES10C_ICON_TYPE_PNG:
|
||||||
|
icon_type = "png";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
icon_type = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (metadata->profileClass) {
|
||||||
|
case ES10C_PROFILE_CLASS_TEST:
|
||||||
|
profile_class = "test";
|
||||||
|
break;
|
||||||
|
case ES10C_PROFILE_CLASS_PROVISIONING:
|
||||||
|
profile_class = "provisioning";
|
||||||
|
break;
|
||||||
|
case ES10C_PROFILE_CLASS_OPERATIONAL:
|
||||||
|
profile_class = "operational";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
profile_class = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*env)->NewObject(
|
||||||
|
env, profile_metadata_class, profile_metadata_constructor,
|
||||||
|
toJString(env, metadata->iccid),
|
||||||
|
toJString(env, metadata->serviceProviderName),
|
||||||
|
toJString(env, metadata->profileName),
|
||||||
|
toJString(env, icon_type),
|
||||||
|
toJString(env, metadata->icon),
|
||||||
|
toJString(env, profile_class)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
|
@ -63,6 +126,7 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
|
||||||
jobject callback) {
|
jobject callback) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
struct es10b_load_bound_profile_package_result es10b_load_bound_profile_package_result;
|
struct es10b_load_bound_profile_package_result es10b_load_bound_profile_package_result;
|
||||||
|
struct es8p_metadata *profile_metadata = NULL;
|
||||||
const char *_confirmation_code = NULL;
|
const char *_confirmation_code = NULL;
|
||||||
const char *_matching_id = NULL;
|
const char *_matching_id = NULL;
|
||||||
const char *_smdp = NULL;
|
const char *_smdp = NULL;
|
||||||
|
@ -109,6 +173,17 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *b64_profileMetadata = ctx->http._internal.prepare_download_param->b64_profileMetadata;
|
||||||
|
if (b64_profileMetadata != NULL) {
|
||||||
|
ret = es8p_metadata_parse(&profile_metadata, b64_profileMetadata);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
(*env)->CallVoidMethod(env, callback, on_profile_metadata,
|
||||||
|
build_profile_metadata(env, profile_metadata));
|
||||||
|
}
|
||||||
|
|
||||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_downloading);
|
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_downloading);
|
||||||
ret = es10b_prepare_download(ctx, _confirmation_code);
|
ret = es10b_prepare_download(ctx, _confirmation_code);
|
||||||
syslog(LOG_INFO, "es10b_prepare_download %d", ret);
|
syslog(LOG_INFO, "es10b_prepare_download %d", ret);
|
||||||
|
@ -134,6 +209,8 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
|
||||||
out:
|
out:
|
||||||
// We expect Java side to call cancelSessions after any error -- thus, `euicc_http_cleanup` is done there
|
// We expect Java side to call cancelSessions after any error -- thus, `euicc_http_cleanup` is done there
|
||||||
// This is so that Java side can access the last HTTP and/or APDU errors when we return.
|
// This is so that Java side can access the last HTTP and/or APDU errors when we return.
|
||||||
|
if (profile_metadata != NULL)
|
||||||
|
es8p_metadata_free(&profile_metadata);
|
||||||
if (_confirmation_code != NULL)
|
if (_confirmation_code != NULL)
|
||||||
(*env)->ReleaseStringUTFChars(env, confirmation_code, _confirmation_code);
|
(*env)->ReleaseStringUTFChars(env, confirmation_code, _confirmation_code);
|
||||||
if (_matching_id != NULL)
|
if (_matching_id != NULL)
|
||||||
|
@ -181,4 +258,4 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadErrCodeToString(JNIEnv *env, jobject
|
||||||
default:
|
default:
|
||||||
return toJString(env, "ES10B_ERROR_REASON_UNDEFINED");
|
return toJString(env, "ES10B_ERROR_REASON_UNDEFINED");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue