diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt
index 18cdb0b..b4937db 100644
--- a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt
+++ b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt
@@ -3,9 +3,11 @@ package im.angry.openeuicc.ui
import android.app.Dialog
import android.os.Bundle
import android.text.Editable
+import android.text.format.Formatter
import android.util.Log
import android.view.*
import android.widget.ProgressBar
+import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.DialogFragment
@@ -34,8 +36,11 @@ class ProfileDownloadFragment : DialogFragment(), EuiccFragmentMarker, Toolbar.O
private lateinit var profileDownloadCode: TextInputLayout
private lateinit var profileDownloadConfirmationCode: TextInputLayout
private lateinit var profileDownloadIMEI: TextInputLayout
+ private lateinit var profileDownloadFreeSpace: TextView
private lateinit var progress: ProgressBar
+ private var freeNvram: Int = -1
+
private var downloading = false
private val barcodeScannerLauncher = registerForActivityResult(ScanContract()) { result ->
@@ -60,6 +65,7 @@ class ProfileDownloadFragment : DialogFragment(), EuiccFragmentMarker, Toolbar.O
profileDownloadCode = view.findViewById(R.id.profile_download_code)
profileDownloadConfirmationCode = view.findViewById(R.id.profile_download_confirmation_code)
profileDownloadIMEI = view.findViewById(R.id.profile_download_imei)
+ profileDownloadFreeSpace = view.findViewById(R.id.profile_download_free_space)
progress = view.findViewById(R.id.progress)
toolbar.inflateMenu(R.menu.fragment_profile_download)
@@ -102,6 +108,18 @@ class ProfileDownloadFragment : DialogFragment(), EuiccFragmentMarker, Toolbar.O
override fun onStart() {
super.onStart()
profileDownloadIMEI.editText!!.text = Editable.Factory.getInstance().newEditable(channel.imei)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ // Fetch remaining NVRAM
+ val str = channel.lpa.euiccInfo2?.freeNvram?.also {
+ freeNvram = it
+ }?.let { Formatter.formatShortFileSize(requireContext(), it.toLong()) }
+
+ withContext(Dispatchers.Main) {
+ profileDownloadFreeSpace.text = getString(R.string.profile_download_free_space,
+ str ?: getText(R.string.unknown))
+ }
+ }
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
diff --git a/app-common/src/main/res/layout/fragment_profile_download.xml b/app-common/src/main/res/layout/fragment_profile_download.xml
index 868cb9d..57ee8a1 100644
--- a/app-common/src/main/res/layout/fragment_profile_download.xml
+++ b/app-common/src/main/res/layout/fragment_profile_download.xml
@@ -102,13 +102,14 @@
android:id="@+id/profile_download_imei"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginVertical="15dp"
+ android:layout_marginTop="15dp"
+ android:layout_marginBottom="6dp"
android:hint="@string/profile_download_imei"
style="@style/Widget.OpenEUICC.Input"
app:layout_constraintTop_toBottomOf="@id/profile_download_confirmation_code"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/profile_download_free_space"
app:layout_constraintWidth_percent=".8"
app:passwordToggleEnabled="true">
@@ -120,4 +121,16 @@
+
+
\ No newline at end of file
diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml
index ae6931f..c6b9c7b 100644
--- a/app-common/src/main/res/values/strings.xml
+++ b/app-common/src/main/res/values/strings.xml
@@ -1,6 +1,7 @@
No eUICC card on this device is accessible by this app.\nInsert a supported eUICC card, or try out the privileged OpenEUICC app instead.
+ Unknown
Enabled
Disabled
@@ -21,6 +22,7 @@
Activation Code
Confirmation Code (Optional)
IMEI (Optional)
+ Space remaining: %s
Scan QR Code
Download
Failed to download eSIM. Check your activation / QR code.
diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt
new file mode 100644
index 0000000..ecaf40d
--- /dev/null
+++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt
@@ -0,0 +1,15 @@
+package net.typeblog.lpac_jni
+
+/* Corresponds to EuiccInfo2 in SGP.22 */
+data class EuiccInfo2(
+ val profileVersion: String,
+ val sgp22Version: String,
+ val euiccFirmwareVersion: String,
+ val uiccFirmwareVersion: String,
+ val globalPlatformVersion: String,
+ val sasAccreditationNumber: String,
+ val ppVersion: String,
+ val installedApp: Int,
+ val freeNvram: Int,
+ val freeRam: Int,
+)
\ No newline at end of file
diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt
index 07fca0f..9a34920 100644
--- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt
+++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt
@@ -3,6 +3,8 @@ package net.typeblog.lpac_jni
interface LocalProfileAssistant {
val profiles: List
val eID: String
+ // Extended EuiccInfo for use with LUIs, containing information such as firmware version
+ val euiccInfo2: EuiccInfo2?
fun enableProfile(iccid: String): Boolean
fun disableProfile(iccid: String): Boolean
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 607127b..4f18ca9 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
@@ -25,4 +25,7 @@ internal object LpacJni {
// We do not expose all of the functions because of tediousness :)
external fun downloadProfile(handle: Long, smdp: String, matchingId: String?, imei: String?,
confirmationCode: String?, callback: ProfileDownloadCallback): Int
+
+ // es10cex (actually part of es10b)
+ external fun es10cexGetEuiccInfo2(handle: Long): EuiccInfo2?
}
\ No newline at end of file
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 751b9ec..c62e3af 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
@@ -2,6 +2,7 @@ package net.typeblog.lpac_jni.impl
import net.typeblog.lpac_jni.LpacJni
import net.typeblog.lpac_jni.ApduInterface
+import net.typeblog.lpac_jni.EuiccInfo2
import net.typeblog.lpac_jni.HttpInterface
import net.typeblog.lpac_jni.LocalProfileAssistant
import net.typeblog.lpac_jni.LocalProfileInfo
@@ -25,6 +26,9 @@ class LocalProfileAssistantImpl(
LpacJni.es10cGetEid(contextHandle)!!
}
+ override val euiccInfo2: EuiccInfo2?
+ get() = LpacJni.es10cexGetEuiccInfo2(contextHandle)
+
override fun enableProfile(iccid: String): Boolean {
return LpacJni.es10cEnableProfile(contextHandle, iccid) == 0
}
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 14db016..58a84b5 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
@@ -24,6 +24,9 @@ jstring empty_string;
jclass string_class;
jmethodID string_constructor;
+jclass euicc_info2_class;
+jmethodID euicc_info2_constructor;
+
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
jvm = vm;
interface_wrapper_init();
@@ -58,6 +61,10 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
local_profile_class_operational = (*env)->GetStaticObjectField(env, local_profile_class_class, field_operational);
local_profile_class_operational = (*env)->NewGlobalRef(env, local_profile_class_operational);
+ euicc_info2_class = (*env)->FindClass(env, "net/typeblog/lpac_jni/EuiccInfo2");
+ euicc_info2_class = (*env)->NewGlobalRef(env, euicc_info2_class);
+ euicc_info2_constructor = (*env)->GetMethodID(env, euicc_info2_class, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;III)V");
+
const char _unused[1];
empty_string = (*env)->NewString(env, _unused, 0);
empty_string = (*env)->NewGlobalRef(env, empty_string);
@@ -229,4 +236,45 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cDeleteProfile(JNIEnv *env, jobject thiz
int ret = es10c_delete_profile_iccid(ctx, _iccid);
(*env)->ReleaseStringUTFChars(env, iccid, _iccid);
return ret;
+}
+
+JNIEXPORT jobject JNICALL
+Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject thiz, jlong handle) {
+ struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
+ struct es10cex_euiccinfo2 info;
+ jstring sas_accreditation_number = NULL;
+ jstring global_platform_version = NULL;
+ jstring euicc_firmware_version = NULL;
+ jstring uicc_firmware_version = NULL;
+ jstring profile_version = NULL;
+ jstring sgp22_version = NULL;
+ jstring pp_version = NULL;
+ jobject ret = NULL;
+
+ if (es10cex_get_euiccinfo2(ctx, &info) < 0)
+ goto out;
+
+ profile_version = toJString(env, info.profile_version);
+ sgp22_version = toJString(env, info.sgp22_version);
+ euicc_firmware_version = toJString(env, info.euicc_firmware_version);
+ uicc_firmware_version = toJString(env, info.uicc_firmware_version);
+ global_platform_version = toJString(env, info.global_platform_version);
+ sas_accreditation_number = toJString(env, info.sas_accreditation_number);
+ pp_version = toJString(env, info.pp_version);
+
+ ret = (*env)->NewObject(env, euicc_info2_class, euicc_info2_constructor,
+ profile_version, sgp22_version, euicc_firmware_version,
+ uicc_firmware_version, global_platform_version,
+ sas_accreditation_number, pp_version,
+ info.installed_app, info.free_nvram, info.free_ram);
+
+ out:
+ (*env)->DeleteLocalRef(env, profile_version);
+ (*env)->DeleteLocalRef(env, sgp22_version);
+ (*env)->DeleteLocalRef(env, euicc_firmware_version);
+ (*env)->DeleteLocalRef(env, uicc_firmware_version);
+ (*env)->DeleteLocalRef(env, global_platform_version);
+ (*env)->DeleteLocalRef(env, sas_accreditation_number);
+ (*env)->DeleteLocalRef(env, pp_version);
+ return ret;
}
\ No newline at end of file