浏览代码

refactor: Pass RemoteProfileInfo into ProfileDownloadState

...instead of using a different callback. This will help us hook this up
into EuiccService properly later (we still need a way for EuiccService
to send events back to EuiccChannelManagerService)
Peter Cai 2 周之前
父节点
当前提交
ba45a7eb7f

+ 2 - 1
.idea/vcs.xml

@@ -2,6 +2,7 @@
 <project version="4">
   <component name="VcsDirectoryMappings">
     <mapping directory="$PROJECT_DIR$" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/libs/lpac-jni/src/main/jni/cjson/cjson" vcs="Git" />
     <mapping directory="$PROJECT_DIR$/libs/lpac-jni/src/main/jni/lpac" vcs="Git" />
   </component>
-</project>
+</project>

+ 14 - 14
app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt

@@ -37,10 +37,8 @@ import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import kotlinx.coroutines.withTimeoutOrNull
 import kotlinx.coroutines.yield
-import net.typeblog.lpac_jni.ProfileDownloadCallback
 import net.typeblog.lpac_jni.ProfileDownloadInput
 import net.typeblog.lpac_jni.ProfileDownloadState
-import net.typeblog.lpac_jni.RemoteProfileInfo
 
 /**
  * An Android Service wrapper for EuiccChannelManager.
@@ -107,7 +105,7 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
      */
     sealed interface ForegroundTaskState {
         data object Idle : ForegroundTaskState
-        data class InProgress(val progress: Int) : ForegroundTaskState
+        data class InProgress(val progress: Int, val context: Any? = null) : ForegroundTaskState
         data class Done(val error: Throwable?) : ForegroundTaskState
     }
 
@@ -392,23 +390,25 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
         ) {
             euiccChannelManager.beginTrackedOperation(slotId, portId, seId) {
                 euiccChannelManager.withEuiccChannel(slotId, portId, seId) { channel ->
-                    channel.lpa.downloadProfile(input, object : ProfileDownloadCallback {
-                        override fun onStateUpdate(state: ProfileDownloadState) {
-                            if (state.progress == 0) return
-                            foregroundTaskState.value = ForegroundTaskState.InProgress(state.progress)
-                        }
-
-                        override fun onConfirmMetadata(metadata: RemoteProfileInfo?): Boolean {
-                            // TODO: Actually do something here and not just logging?
-                            if (metadata != null) {
+                    channel.lpa.downloadProfile(input) { state ->
+                        val progress = state.downloadProgress
+                        foregroundTaskState.value = ForegroundTaskState.InProgress(
+                            progress,
+                            state
+                        )
+
+                        if (state is ProfileDownloadState.ConfirmingDownload) {
+                            state.metadata?.let { metadata ->
+                                // TODO: Actually do something here and not just logging?
                                 Log.i(
                                     TAG,
                                     "Downloading profile provider=${metadata.providerName} name=${metadata.name}"
                                 )
                             }
-                            return true
                         }
-                    })
+
+                        true
+                    }
                 }
 
                 preferenceRepository.notificationDownloadFlow.first()

+ 12 - 17
app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardProgressFragment.kt

@@ -23,19 +23,6 @@ import net.typeblog.lpac_jni.ProfileDownloadState
 import net.typeblog.lpac_jni.LocalProfileAssistant
 
 class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStepFragment() {
-    companion object {
-        /**
-         * An array of LPA-side state types, mapping 1:1 to progressItems
-         */
-        val LPA_PROGRESS_STATES = arrayOf(
-            ProfileDownloadState.Preparing,
-            ProfileDownloadState.Connecting,
-            ProfileDownloadState.Authenticating,
-            ProfileDownloadState.Downloading,
-            ProfileDownloadState.Finalizing,
-        )
-    }
-
     private enum class ProgressState {
         NotStarted,
         InProgress,
@@ -139,7 +126,7 @@ class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStep
                     }
 
                     is EuiccChannelManagerService.ForegroundTaskState.InProgress ->
-                        updateProgress(it.progress)
+                        updateProgress(it.context as? ProfileDownloadState ?: return@onEach)
 
                     else -> {}
                 }
@@ -176,11 +163,19 @@ class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStep
             ret
         }
 
-    private fun updateProgress(progress: Int) {
+    private fun updateProgress(state: ProfileDownloadState) {
+        val progress = state.downloadProgress
         showProgressBar(progress)
 
-        val lpaState = ProfileDownloadState.lookupStateFromProgress(progress)
-        val stateIndex = LPA_PROGRESS_STATES.indexOf(lpaState)
+        val stateIndex = when (state) {
+            is ProfileDownloadState.Preparing -> 0
+            is ProfileDownloadState.Connecting -> 1
+            is ProfileDownloadState.Authenticating -> 2
+            // TODO: Actually implement metadata confirmation (a dialog or something else)
+            is ProfileDownloadState.ConfirmingDownload -> 2
+            is ProfileDownloadState.Downloading -> 3
+            is ProfileDownloadState.Finalizing -> 4
+        }
 
         if (stateIndex > 0) {
             for (i in (0..<stateIndex)) {

+ 11 - 0
app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt

@@ -6,6 +6,7 @@ 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.ProfileDownloadState
 
 const val TAG = "LPAUtils"
 
@@ -22,6 +23,16 @@ val List<LocalProfileInfo>.operational: List<LocalProfileInfo>
 val List<LocalProfileInfo>.enabled: LocalProfileInfo?
     get() = find { it.isEnabled }
 
+val ProfileDownloadState.downloadProgress: Int
+    get() = when (this) {
+        is ProfileDownloadState.Preparing -> 0
+        is ProfileDownloadState.Connecting -> 20
+        is ProfileDownloadState.Authenticating -> 40
+        is ProfileDownloadState.ConfirmingDownload -> 50
+        is ProfileDownloadState.Downloading -> 60
+        is ProfileDownloadState.Finalizing -> 80
+    }
+
 val List<EuiccChannel>.hasMultipleChips: Boolean
     get() = distinctBy { it.slotId }.size > 1
 

+ 1 - 7
libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ProfileDownloadCallback.kt

@@ -1,11 +1,5 @@
 package net.typeblog.lpac_jni
 
 fun interface ProfileDownloadCallback {
-    fun onStateUpdate(state: ProfileDownloadState)
-
-    /**
-     * Optionally override this to abort / continue a download based on metadata acquired in the process
-     * Note that not all ES9P servers may return metadata.
-     */
-    fun onConfirmMetadata(metadata: RemoteProfileInfo?): Boolean = true
+    fun onStatusUpdate(state: ProfileDownloadState): Boolean
 }

+ 7 - 11
libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ProfileDownloadState.kt

@@ -1,14 +1,10 @@
 package net.typeblog.lpac_jni
 
-enum class ProfileDownloadState(val progress: Int) {
-    Preparing(0),
-    Connecting(20),  // Before {server,client} authentication
-    Authenticating(40),  // {server,client} authentication
-    Downloading(60),  // prepare download, get bpp from es9p
-    Finalizing(80); // load bpp
-
-    companion object {
-        fun lookupStateFromProgress(progress: Int) =
-            entries.first { it.progress == progress }
-    }
+sealed class ProfileDownloadState {
+    class Preparing : ProfileDownloadState()
+    class Connecting : ProfileDownloadState()
+    class Authenticating : ProfileDownloadState()
+    class ConfirmingDownload(val metadata: RemoteProfileInfo?) : ProfileDownloadState()
+    class Downloading : ProfileDownloadState()
+    class Finalizing : ProfileDownloadState()
 }

+ 109 - 45
libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c

@@ -13,7 +13,8 @@ jobject download_state_downloading;
 jobject download_state_finalizing;
 
 jmethodID on_state_update;
-jmethodID on_confirm_metadata;
+jclass confirming_download_class;
+jmethodID confirming_download_constructor;
 jclass remote_profile_info_class;
 jmethodID remote_profile_info_constructor;
 jobject profile_class_testing;
@@ -23,46 +24,68 @@ jobject profile_class_operational;
 void lpac_download_init() {
     LPAC_JNI_SETUP_ENV;
 
-    jclass download_state_class = (*env)->FindClass(env,
-                                                    "net/typeblog/lpac_jni/ProfileDownloadState");
-    jfieldID download_state_preparing_field = (*env)->GetStaticFieldID(env, download_state_class,
-                                                                       "Preparing",
-                                                                       "Lnet/typeblog/lpac_jni/ProfileDownloadState;");
-    download_state_preparing = (*env)->GetStaticObjectField(env, download_state_class,
-                                                            download_state_preparing_field);
-    download_state_preparing = (*env)->NewGlobalRef(env, download_state_preparing);
-    jfieldID download_state_connecting_field = (*env)->GetStaticFieldID(env, download_state_class,
-                                                                        "Connecting",
-                                                                        "Lnet/typeblog/lpac_jni/ProfileDownloadState;");
-    download_state_connecting = (*env)->GetStaticObjectField(env, download_state_class,
-                                                             download_state_connecting_field);
-    download_state_connecting = (*env)->NewGlobalRef(env, download_state_connecting);
-    jfieldID download_state_authenticating_field = (*env)->GetStaticFieldID(env,
-                                                                            download_state_class,
-                                                                            "Authenticating",
-                                                                            "Lnet/typeblog/lpac_jni/ProfileDownloadState;");
-    download_state_authenticating = (*env)->GetStaticObjectField(env, download_state_class,
-                                                                 download_state_authenticating_field);
-    download_state_authenticating = (*env)->NewGlobalRef(env, download_state_authenticating);
-    jfieldID download_state_downloading_field = (*env)->GetStaticFieldID(env, download_state_class,
-                                                                         "Downloading",
-                                                                         "Lnet/typeblog/lpac_jni/ProfileDownloadState;");
-    download_state_downloading = (*env)->GetStaticObjectField(env, download_state_class,
-                                                              download_state_downloading_field);
-    download_state_downloading = (*env)->NewGlobalRef(env, download_state_downloading);
-    jfieldID download_state_finalizng_field = (*env)->GetStaticFieldID(env, download_state_class,
-                                                                       "Finalizing",
-                                                                       "Lnet/typeblog/lpac_jni/ProfileDownloadState;");
-    download_state_finalizing = (*env)->GetStaticObjectField(env, download_state_class,
-                                                             download_state_finalizng_field);
-    download_state_finalizing = (*env)->NewGlobalRef(env, download_state_finalizing);
+    jclass preparing_class = (*env)->FindClass(env,
+                                               "net/typeblog/lpac_jni/ProfileDownloadState$Preparing");
+    jmethodID preparing_constructor = (*env)->GetMethodID(env, preparing_class,
+                                                          "<init>",
+                                                          "()V");
+    jobject _download_state_preparing = (*env)->NewObject(env, preparing_class,
+                                                          preparing_constructor);
+    download_state_preparing = (*env)->NewGlobalRef(env, _download_state_preparing);
+    (*env)->DeleteLocalRef(env, _download_state_preparing);
+
+    jclass connecting_class = (*env)->FindClass(env,
+                                                "net/typeblog/lpac_jni/ProfileDownloadState$Connecting");
+    jmethodID connecting_constructor = (*env)->GetMethodID(env, connecting_class,
+                                                           "<init>",
+                                                           "()V");
+    jobject _download_state_connecting = (*env)->NewObject(env, connecting_class,
+                                                           connecting_constructor);
+    download_state_connecting = (*env)->NewGlobalRef(env, _download_state_connecting);
+    (*env)->DeleteLocalRef(env, _download_state_connecting);
+
+    jclass authenticating_class = (*env)->FindClass(env,
+                                                    "net/typeblog/lpac_jni/ProfileDownloadState$Authenticating");
+    jmethodID authenticating_constructor = (*env)->GetMethodID(env, authenticating_class,
+                                                               "<init>",
+                                                               "()V");
+    jobject _download_state_authenticating = (*env)->NewObject(env, authenticating_class,
+                                                               authenticating_constructor);
+    download_state_authenticating = (*env)->NewGlobalRef(env, _download_state_authenticating);
+    (*env)->DeleteLocalRef(env, _download_state_authenticating);
+
+    jclass downloading_class = (*env)->FindClass(env,
+                                                 "net/typeblog/lpac_jni/ProfileDownloadState$Downloading");
+    jmethodID downloading_constructor = (*env)->GetMethodID(env, downloading_class,
+                                                            "<init>",
+                                                            "()V");
+    jobject _download_state_downloading = (*env)->NewObject(env, downloading_class,
+                                                            downloading_constructor);
+    download_state_downloading = (*env)->NewGlobalRef(env, _download_state_downloading);
+    (*env)->DeleteLocalRef(env, _download_state_downloading);
+
+    jclass finalizing_class = (*env)->FindClass(env,
+                                                "net/typeblog/lpac_jni/ProfileDownloadState$Finalizing");
+    jmethodID finalizing_constructor = (*env)->GetMethodID(env, finalizing_class,
+                                                           "<init>",
+                                                           "()V");
+    jobject _download_state_finalizing = (*env)->NewObject(env, finalizing_class,
+                                                           finalizing_constructor);
+    download_state_finalizing = (*env)->NewGlobalRef(env, _download_state_finalizing);
+    (*env)->DeleteLocalRef(env, _download_state_finalizing);
 
     jclass download_callback_class = (*env)->FindClass(env,
                                                        "net/typeblog/lpac_jni/ProfileDownloadCallback");
-    on_state_update = (*env)->GetMethodID(env, download_callback_class, "onStateUpdate",
-                                          "(Lnet/typeblog/lpac_jni/ProfileDownloadState;)V");
-    on_confirm_metadata = (*env)->GetMethodID(env, download_callback_class, "onConfirmMetadata",
-                                              "(Lnet/typeblog/lpac_jni/RemoteProfileInfo;)Z");
+    on_state_update = (*env)->GetMethodID(env, download_callback_class, "onStatusUpdate",
+                                          "(Lnet/typeblog/lpac_jni/ProfileDownloadState;)Z");
+
+    jclass _confirming_download_class = (*env)->FindClass(env,
+                                                          "net/typeblog/lpac_jni/ProfileDownloadState$ConfirmingDownload");
+    confirming_download_class = (*env)->NewGlobalRef(env, _confirming_download_class);
+    confirming_download_constructor = (*env)->GetMethodID(env,
+                                                          confirming_download_class,
+                                                          "<init>",
+                                                          "(Lnet/typeblog/lpac_jni/RemoteProfileInfo;)V");
 
     jclass profile_class_class = (*env)->FindClass(env, "net/typeblog/lpac_jni/ProfileClass");
     jfieldID profile_class_testing_field = (*env)->GetStaticFieldID(env, profile_class_class,
@@ -147,7 +170,8 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
     const char *_smdp = NULL;
     const char *_imei = NULL;
     jobject remote_profile_info = NULL;
-    jboolean confirmed = JNI_FALSE;
+    jobject confirming_download_state = NULL;
+    jboolean confirmed = JNI_TRUE;
     int ret;
 
     if (confirmation_code != NULL)
@@ -160,7 +184,12 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
 
     ctx->http.server_address = _smdp;
 
-    (*env)->CallVoidMethod(env, callback, on_state_update, download_state_preparing);
+    confirmed = (*env)->CallBooleanMethod(env, callback, on_state_update, download_state_preparing);
+    if (!confirmed) {
+        ret = -ES10B_ERROR_REASON_UNDEFINED;
+        goto out;
+    }
+
     ret = es10b_get_euicc_challenge_and_info(ctx);
     syslog(LOG_INFO, "es10b_get_euicc_challenge_and_info %d", ret);
     if (ret < 0) {
@@ -168,7 +197,12 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
         goto out;
     }
 
-    (*env)->CallVoidMethod(env, callback, on_state_update, download_state_connecting);
+    confirmed = (*env)->CallBooleanMethod(env, callback, on_state_update, download_state_connecting);
+    if (!confirmed) {
+        ret = -ES10B_ERROR_REASON_UNDEFINED;
+        goto out;
+    }
+
     ret = es9p_initiate_authentication(ctx);
     syslog(LOG_INFO, "es9p_initiate_authentication %d", ret);
     if (ret < 0) {
@@ -176,7 +210,12 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
         goto out;
     }
 
-    (*env)->CallVoidMethod(env, callback, on_state_update, download_state_authenticating);
+    confirmed = (*env)->CallBooleanMethod(env, callback, on_state_update, download_state_authenticating);
+    if (!confirmed) {
+        ret = -ES10B_ERROR_REASON_UNDEFINED;
+        goto out;
+    }
+
     ret = es10b_authenticate_server(ctx, _matching_id, _imei);
     syslog(LOG_INFO, "es10b_authenticate_server %d", ret);
     if (ret < 0) {
@@ -206,19 +245,37 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
         }
     }
 
-    confirmed = (*env)->CallBooleanMethod(env, callback, on_confirm_metadata, remote_profile_info);
+    confirming_download_state = (*env)->NewObject(env,
+                                                  confirming_download_class,
+                                                  confirming_download_constructor,
+                                                  remote_profile_info);
+    if (confirming_download_state == NULL) {
+        ret = -ES10B_ERROR_REASON_UNDEFINED;
+        goto out;
+    }
+
+    confirmed = (*env)->CallBooleanMethod(env, callback, on_state_update, confirming_download_state);
 
     if (remote_profile_info != NULL) {
         (*env)->DeleteLocalRef(env, remote_profile_info);
         remote_profile_info = NULL;
     }
+    if (confirming_download_state != NULL) {
+        (*env)->DeleteLocalRef(env, confirming_download_state);
+        confirming_download_state = NULL;
+    }
 
     if (!confirmed) {
         ret = -ES10B_ERROR_REASON_UNDEFINED;
         goto out;
     }
 
-    (*env)->CallVoidMethod(env, callback, on_state_update, download_state_downloading);
+    confirmed = (*env)->CallBooleanMethod(env, callback, on_state_update, download_state_downloading);
+    if (!confirmed) {
+        ret = -ES10B_ERROR_REASON_UNDEFINED;
+        goto out;
+    }
+
     ret = es10b_prepare_download(ctx, _confirmation_code);
     syslog(LOG_INFO, "es10b_prepare_download %d", ret);
     if (ret < 0) {
@@ -230,7 +287,12 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
     if (ret < 0)
         goto out;
 
-    (*env)->CallVoidMethod(env, callback, on_state_update, download_state_finalizing);
+    confirmed = (*env)->CallBooleanMethod(env, callback, on_state_update, download_state_finalizing);
+    if (!confirmed) {
+        ret = -ES10B_ERROR_REASON_UNDEFINED;
+        goto out;
+    }
+
     ret = es10b_load_bound_profile_package(ctx, &es10b_load_bound_profile_package_result);
     syslog(LOG_INFO, "es10b_load_bound_profile_package %d, reason %d", ret, es10b_load_bound_profile_package_result.errorReason);
     if (ret < 0) {
@@ -252,6 +314,8 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
         (*env)->ReleaseStringUTFChars(env, imei, _imei);
     if (remote_profile_info != NULL)
         (*env)->DeleteLocalRef(env, remote_profile_info);
+    if (confirming_download_state != NULL)
+        (*env)->DeleteLocalRef(env, confirming_download_state);
     if (profile_metadata != NULL)
         es8p_metadata_free(&profile_metadata);
     return ret;