forked from PeterCxy/OpenEUICC
Compare commits
8 commits
4e5bb5b11e
...
1140ddb249
Author | SHA1 | Date | |
---|---|---|---|
1140ddb249 | |||
9be1ae7cd1 | |||
a7e97378fc | |||
790cbb5a58 | |||
2247749b37 | |||
249aea482b | |||
dc0489a693 | |||
d3e54ece58 |
13 changed files with 116 additions and 112 deletions
|
@ -15,12 +15,18 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import im.angry.openeuicc.common.R
|
||||
import im.angry.openeuicc.core.EuiccChannel
|
||||
import im.angry.openeuicc.util.*
|
||||
import kotlinx.coroutines.launch
|
||||
import net.typeblog.lpac_jni.impl.DEFAULT_PKID_GSMA_RSP2_ROOT_CI1
|
||||
import net.typeblog.lpac_jni.impl.PKID_GSMA_TEST_CI
|
||||
|
||||
class EuiccInfoActivity : BaseEuiccAccessActivity() {
|
||||
companion object {
|
||||
private val YES_NO = Pair(R.string.yes, R.string.no)
|
||||
private val SUPPORTED_UNSUPPORTED = Pair(R.string.supported, R.string.unsupported)
|
||||
}
|
||||
|
||||
private lateinit var swipeRefresh: SwipeRefreshLayout
|
||||
private lateinit var infoList: RecyclerView
|
||||
|
||||
|
@ -71,104 +77,59 @@ class EuiccInfoActivity : BaseEuiccAccessActivity() {
|
|||
swipeRefresh.isRefreshing = true
|
||||
|
||||
lifecycleScope.launch {
|
||||
val unknownStr = getString(R.string.unknown)
|
||||
|
||||
val newItems = mutableListOf<Pair<String, String>>()
|
||||
|
||||
newItems.add(
|
||||
Pair(
|
||||
getString(R.string.euicc_info_access_mode),
|
||||
euiccChannelManager.withEuiccChannel(logicalSlotId) { channel -> channel.type }
|
||||
)
|
||||
)
|
||||
|
||||
newItems.add(
|
||||
Pair(
|
||||
getString(R.string.euicc_info_removable),
|
||||
if (euiccChannelManager.withEuiccChannel(logicalSlotId) { channel -> channel.port.card.isRemovable }) {
|
||||
getString(R.string.yes)
|
||||
} else {
|
||||
getString(R.string.no)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
newItems.add(
|
||||
Pair(
|
||||
getString(R.string.euicc_info_eid),
|
||||
euiccChannelManager.withEuiccChannel(logicalSlotId) { channel -> channel.lpa.eID }
|
||||
)
|
||||
)
|
||||
|
||||
val euiccInfo2 = euiccChannelManager.withEuiccChannel(logicalSlotId) { channel ->
|
||||
channel.lpa.euiccInfo2
|
||||
}
|
||||
|
||||
newItems.add(
|
||||
Pair(
|
||||
getString(R.string.euicc_info_firmware_version),
|
||||
euiccInfo2?.euiccFirmwareVersion ?: unknownStr
|
||||
)
|
||||
)
|
||||
|
||||
newItems.add(
|
||||
Pair(
|
||||
getString(R.string.euicc_info_globalplatform_version),
|
||||
euiccInfo2?.globalPlatformVersion ?: unknownStr
|
||||
)
|
||||
)
|
||||
|
||||
newItems.add(
|
||||
Pair(
|
||||
getString(R.string.euicc_info_pp_version),
|
||||
euiccInfo2?.ppVersion ?: unknownStr
|
||||
)
|
||||
)
|
||||
|
||||
newItems.add(
|
||||
Pair(
|
||||
getString(R.string.euicc_info_sas_accreditation_number),
|
||||
euiccInfo2?.sasAccreditationNumber ?: unknownStr
|
||||
)
|
||||
)
|
||||
|
||||
newItems.add(
|
||||
Pair(
|
||||
getString(R.string.euicc_info_free_nvram),
|
||||
euiccInfo2?.freeNvram?.let { formatFreeSpace(it) } ?: unknownStr
|
||||
))
|
||||
|
||||
newItems.add(
|
||||
Pair(
|
||||
getString(R.string.euicc_info_gsma_prod),
|
||||
if (euiccInfo2?.euiccCiPKIdListForSigning?.contains(
|
||||
DEFAULT_PKID_GSMA_RSP2_ROOT_CI1
|
||||
) == true
|
||||
) {
|
||||
getString(R.string.supported)
|
||||
} else {
|
||||
getString(R.string.unsupported)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
newItems.add(
|
||||
Pair(
|
||||
getString(R.string.euicc_info_gsma_test),
|
||||
if (PKID_GSMA_TEST_CI.any { euiccInfo2?.euiccCiPKIdListForSigning?.contains(it) == true }) {
|
||||
getString(R.string.supported)
|
||||
} else {
|
||||
getString(R.string.unsupported)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
(infoList.adapter!! as EuiccInfoAdapter).euiccInfoItems = newItems
|
||||
(infoList.adapter!! as EuiccInfoAdapter).euiccInfoItems =
|
||||
euiccChannelManager.withEuiccChannel(logicalSlotId, ::buildPairs).map {
|
||||
Pair(getString(it.first), it.second ?: getString(R.string.unknown))
|
||||
}
|
||||
|
||||
swipeRefresh.isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildPairs(channel: EuiccChannel) = buildList {
|
||||
add(Pair(R.string.euicc_info_access_mode, channel.type))
|
||||
add(
|
||||
Pair(
|
||||
R.string.euicc_info_removable,
|
||||
formatByBoolean(channel.port.card.isRemovable, YES_NO)
|
||||
)
|
||||
)
|
||||
add(Pair(R.string.euicc_info_eid, channel.lpa.eID))
|
||||
channel.lpa.euiccInfo2.let { info ->
|
||||
add(Pair(R.string.euicc_info_firmware_version, info?.euiccFirmwareVersion))
|
||||
add(Pair(R.string.euicc_info_globalplatform_version, info?.globalPlatformVersion))
|
||||
add(Pair(R.string.euicc_info_pp_version, info?.ppVersion))
|
||||
add(Pair(R.string.euicc_info_sas_accreditation_number, info?.sasAccreditationNumber))
|
||||
add(Pair(R.string.euicc_info_free_nvram, info?.freeNvram?.let(::formatFreeSpace)))
|
||||
}
|
||||
channel.lpa.euiccInfo2?.euiccCiPKIdListForSigning.orEmpty().let { signers ->
|
||||
add(
|
||||
Pair(
|
||||
R.string.euicc_info_gsma_prod,
|
||||
formatByBoolean(
|
||||
signers.contains(DEFAULT_PKID_GSMA_RSP2_ROOT_CI1),
|
||||
SUPPORTED_UNSUPPORTED
|
||||
)
|
||||
)
|
||||
)
|
||||
add(
|
||||
Pair(
|
||||
R.string.euicc_info_gsma_test,
|
||||
formatByBoolean(PKID_GSMA_TEST_CI.any(signers::contains), SUPPORTED_UNSUPPORTED)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatByBoolean(b: Boolean, res: Pair<Int, Int>): String =
|
||||
getString(
|
||||
if (b) {
|
||||
res.first
|
||||
} else {
|
||||
res.second
|
||||
}
|
||||
)
|
||||
|
||||
inner class EuiccInfoViewHolder(root: View) : ViewHolder(root) {
|
||||
private val title: TextView = root.requireViewById(R.id.euicc_info_title)
|
||||
private val content: TextView = root.requireViewById(R.id.euicc_info_content)
|
||||
|
|
|
@ -47,10 +47,6 @@ class SettingsFragment: PreferenceFragmentCompat() {
|
|||
setOnPreferenceClickListener(::onAppVersionClicked)
|
||||
}
|
||||
|
||||
findPreference<Preference>("pref_info_source_code")?.apply {
|
||||
intent = Intent(Intent.ACTION_VIEW, Uri.parse(summary.toString()))
|
||||
}
|
||||
|
||||
findPreference<Preference>("pref_language")?.apply {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return@apply
|
||||
isVisible = true
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
app:layout_constraintRight_toLeftOf="@+id/profile_menu"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/state"
|
||||
app:layout_constraintHorizontal_bias="0" />
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constrainedWidth="true" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/profile_menu"
|
||||
|
|
|
@ -136,4 +136,8 @@
|
|||
<string name="pref_language_desc">アプリの言語を選択</string>
|
||||
<string name="pref_developer_unfiltered_profile_list">すべてのプロファイルを表示</string>
|
||||
<string name="pref_developer_unfiltered_profile_list_desc">プロダクション以外のプロファイルも表示する</string>
|
||||
<string name="profile_class">タイプ:</string>
|
||||
<string name="profile_class_testing">テスティング</string>
|
||||
<string name="profile_class_provisioning">準備中</string>
|
||||
<string name="profile_class_operational">動作中</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<im.angry.openeuicc.ui.preference.LongSummaryPreferenceCategory
|
||||
app:title="@string/pref_notifications"
|
||||
app:summary="@string/pref_notifications_desc"
|
||||
|
@ -88,6 +89,10 @@
|
|||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref_info_source_code"
|
||||
app:summary="@string/pref_info_source_code_url"
|
||||
app:key="pref_info_source_code"/>
|
||||
app:key="pref_info_source_code">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="@string/pref_info_source_code_url" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
|
@ -1,6 +1,8 @@
|
|||
package im.angry.openeuicc.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -8,6 +10,7 @@ import android.widget.TextView
|
|||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
|
@ -29,15 +32,16 @@ class CompatibilityCheckActivity: AppCompatActivity() {
|
|||
setupToolbarInsets()
|
||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
compatibilityCheckList = requireViewById(R.id.recycler_view)
|
||||
compatibilityCheckList.layoutManager =
|
||||
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
|
||||
compatibilityCheckList.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
|
||||
compatibilityCheckList.adapter = adapter
|
||||
compatibilityCheckList = requireViewById<RecyclerView>(R.id.recycler_view).also {
|
||||
it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
|
||||
it.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
|
||||
it.adapter = adapter
|
||||
}
|
||||
|
||||
setupRootViewInsets(compatibilityCheckList)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
lifecycleScope.launch {
|
||||
|
@ -61,10 +65,10 @@ class CompatibilityCheckActivity: AppCompatActivity() {
|
|||
|
||||
fun bindItem(item: CompatibilityCheck) {
|
||||
titleView.text = item.title
|
||||
descView.text = item.description
|
||||
descView.text = Html.fromHtml(item.description, Html.FROM_HTML_MODE_COMPACT)
|
||||
|
||||
statusContainer.children.forEach {
|
||||
it.visibility = View.GONE
|
||||
it.isVisible = false
|
||||
}
|
||||
|
||||
val viewId = when (item.state) {
|
||||
|
@ -73,7 +77,7 @@ class CompatibilityCheckActivity: AppCompatActivity() {
|
|||
CompatibilityCheck.State.FAILURE_UNKNOWN -> R.id.compatibility_check_unknown
|
||||
else -> R.id.compatibility_check_progress_bar
|
||||
}
|
||||
root.requireViewById<View>(viewId).visibility = View.VISIBLE
|
||||
root.requireViewById<View>(viewId).isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
<string name="compatibility_check_omapi_connectivity">OMAPI Connectivity</string>
|
||||
<string name="compatibility_check_omapi_connectivity_desc">Does your device allow access to Secure Elements on SIM cards via OMAPI?</string>
|
||||
<string name="compatibility_check_omapi_connectivity_fail">Unable to detect Secure Element readers for SIM cards via OMAPI. If you have not inserted a SIM in this device, try inserting one and retry this check.</string>
|
||||
<string name="compatibility_check_omapi_connectivity_partial_success_sim_number">Successfully detected Secure Element access, but only for the following SIM slots: <b>SIM%s</b>.</string>
|
||||
<string name="compatibility_check_omapi_connectivity_partial_success_sim_number">Successfully detected Secure Element access, but only for the following SIM slots: <b>SIM%s</b>.</string>
|
||||
<string name="compatibility_check_isdr_channel">ISD-R Channel Access</string>
|
||||
<string name="compatibility_check_isdr_channel_desc">Does your device support opening an ISD-R (management) channel to eSIMs via OMAPI?</string>
|
||||
<string name="compatibility_check_isdr_channel_desc_unknown">Cannot determine whether ISD-R access through OMAPI is supported. You might want to retry with SIM cards inserted (any SIM card will do) if not already.</string>
|
||||
<string name="compatibility_check_isdr_channel_desc_partial_fail">OMAPI access to ISD-R is only possible on the following SIM slots: <b>SIM%s</b>.</string>
|
||||
<string name="compatibility_check_isdr_channel_desc_partial_fail">OMAPI access to ISD-R is only possible on the following SIM slots: <b>SIM%s</b>.</string>
|
||||
<string name="compatibility_check_known_broken">Not on the Known Broken List</string>
|
||||
<string name="compatibility_check_known_broken_desc">Making sure your device is not known to have bugs associated with removable eSIMs.</string>
|
||||
<string name="compatibility_check_known_broken_fail">Oops, your device is known to have bugs when accessing removable eSIMs. This does not necessarily mean that it will not work at all, but you will have to proceed with caution.</string>
|
||||
|
|
|
@ -5,6 +5,7 @@ import net.typeblog.lpac_jni.HttpInterface.HttpResponse
|
|||
interface LocalProfileAssistant {
|
||||
@Suppress("ArrayInDataClass")
|
||||
data class ProfileDownloadException(
|
||||
val lpaErrorReason: String,
|
||||
val lastHttpResponse: HttpResponse?,
|
||||
val lastHttpException: Exception?,
|
||||
val lastApduResponse: ByteArray?,
|
||||
|
|
|
@ -29,6 +29,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
|
||||
external fun downloadErrCodeToString(code: Int): String
|
||||
external fun handleNotification(handle: Long, seqNumber: Long): Int
|
||||
// Cancel any ongoing es9p and/or es10b sessions
|
||||
external fun cancelSessions(handle: Long)
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.security.cert.X509Certificate
|
|||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
@SuppressLint("CustomX509TrustManager")
|
||||
class IgnoreTLSCertificate : X509TrustManager {
|
||||
class AllowAllTrustManager : X509TrustManager {
|
||||
@SuppressLint("TrustAllX509TrustManager")
|
||||
override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) {
|
||||
return
|
|
@ -83,7 +83,7 @@ class HttpInterfaceImpl(
|
|||
private fun getSocketFactory(): SSLSocketFactory {
|
||||
val trustManagers =
|
||||
if (runBlocking { ignoreTLSCertificateFlow.first() }) {
|
||||
arrayOf(IgnoreTLSCertificate())
|
||||
arrayOf(AllowAllTrustManager())
|
||||
} else {
|
||||
this.trustManagers
|
||||
}
|
||||
|
|
|
@ -214,6 +214,7 @@ class LocalProfileAssistantImpl(
|
|||
if (res != 0) {
|
||||
// Construct the error now to store any error information we _can_ access
|
||||
val err = LocalProfileAssistant.ProfileDownloadException(
|
||||
lpaErrorReason = LpacJni.downloadErrCodeToString(-res),
|
||||
httpInterface.lastHttpResponse,
|
||||
httpInterface.lastHttpException,
|
||||
apduInterface.lastApduResponse,
|
||||
|
|
|
@ -148,4 +148,34 @@ Java_net_typeblog_lpac_1jni_LpacJni_cancelSessions(JNIEnv *env, jobject thiz, jl
|
|||
es9p_cancel_session(ctx);
|
||||
es10b_cancel_session(ctx, ES10B_CANCEL_SESSION_REASON_UNDEFINED);
|
||||
euicc_http_cleanup(ctx);
|
||||
}
|
||||
|
||||
#define QUOTE(S) #S
|
||||
#define ERRCODE_ENUM_TO_STRING(VARIANT) case VARIANT: return toJString(env, QUOTE(VARIANT))
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_net_typeblog_lpac_1jni_LpacJni_downloadErrCodeToString(JNIEnv *env, jobject thiz, jint code) {
|
||||
switch (code) {
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INCORRECT_INPUT_VALUES);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INVALID_SIGNATURE);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INVALID_TRANSACTION_ID);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_UNSUPPORTED_CRT_VALUES);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_UNSUPPORTED_REMOTE_OPERATION_TYPE);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_UNSUPPORTED_PROFILE_CLASS);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_SCP03T_STRUCTURE_ERROR);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_SCP03T_SECURITY_ERROR);
|
||||
ERRCODE_ENUM_TO_STRING(
|
||||
ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_ALREADY_EXISTS_ON_EUICC);
|
||||
ERRCODE_ENUM_TO_STRING(
|
||||
ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INSUFFICIENT_MEMORY_FOR_PROFILE);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INTERRUPTION);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_PE_PROCESSING_ERROR);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_MISMATCH);
|
||||
ERRCODE_ENUM_TO_STRING(
|
||||
ES10B_ERROR_REASON_TEST_PROFILE_INSTALL_FAILED_DUE_TO_INVALID_NAA_KEY);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_PPR_NOT_ALLOWED);
|
||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_UNKNOWN_ERROR);
|
||||
default:
|
||||
return toJString(env, "ES10B_ERROR_REASON_UNDEFINED");
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue