Compare commits
No commits in common. "master" and "master" have entirely different histories.
26 changed files with 305 additions and 820 deletions
|
@ -33,23 +33,14 @@ jobs:
|
|||
uses: https://gitea.angry.im/actions/setup-android@v3
|
||||
|
||||
- name: Build Debug APKs
|
||||
run: ./gradlew --no-daemon assembleDebug :app:assembleDebugMagiskModuleDir
|
||||
run: ./gradlew --no-daemon assembleDebug
|
||||
|
||||
- name: Copy Artifacts
|
||||
run: |
|
||||
find . -name 'app*-debug.apk' -exec cp {} . \;
|
||||
cp -r app/build/magisk/debug ./magisk-debug
|
||||
run: find . -name 'app*-debug.apk' -exec cp {} . \;
|
||||
|
||||
- name: Upload APK Artifacts
|
||||
- name: Upload Artifacts
|
||||
uses: https://gitea.angry.im/actions/upload-artifact@v3
|
||||
with:
|
||||
name: Debug APKs
|
||||
compression-level: 0
|
||||
path: app*-debug.apk
|
||||
|
||||
- name: Upload Magisk Artifacts
|
||||
uses: https://gitea.angry.im/actions/upload-artifact@v3
|
||||
with:
|
||||
name: magisk-debug
|
||||
compression-level: 0
|
||||
path: magisk-debug
|
||||
|
|
21
.idea/.gitignore
generated
vendored
21
.idea/.gitignore
generated
vendored
|
@ -1,7 +1,14 @@
|
|||
*
|
||||
!/codeStyles/Project.xml
|
||||
!/codeStyles/codeStyleConfig.xml
|
||||
!/vcs.xml
|
||||
!/kotlinc.xml
|
||||
!/compiler.xml
|
||||
!/migrations.xml
|
||||
/shelf
|
||||
/caches
|
||||
/libraries
|
||||
/assetWizardSettings.xml
|
||||
/deploymentTargetDropDown.xml
|
||||
/gradle.xml
|
||||
/misc.xml
|
||||
/modules.xml
|
||||
/navEditor.xml
|
||||
/runConfigurations.xml
|
||||
/workspace.xml
|
||||
/AndroidProjectSystem.xml
|
||||
|
||||
**/*.iml
|
37
.idea/deploymentTargetSelector.xml
generated
Normal file
37
.idea/deploymentTargetSelector.xml
generated
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="deploymentTargetSelector">
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app-unpriv">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="app-unpriv.androidTest">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="app-unpriv.main">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="app-unpriv.unitTest">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="app.unitTest">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="app.androidTest">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="app.main">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="workspace.OpenEUICC.app-unpriv">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="workspace.OpenEUICC.app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
</project>
|
77
README.md
77
README.md
|
@ -4,44 +4,27 @@ A fully free and open-source Local Profile Assistant implementation for Android
|
|||
|
||||
There are two variants of this project, OpenEUICC and EasyEUICC:
|
||||
|
||||
| | OpenEUICC | EasyEUICC |
|
||||
| :---------------------------- | :-----------------------------: | :-----------------: |
|
||||
| Privileged | Must be installed as system app | No |
|
||||
| Internal eSIM | Supported | Unsupported |
|
||||
| External eSIM [^1] | Supported | Supported |
|
||||
| USB Readers | Supported | Supported |
|
||||
| Requires allowlisting by eSIM | No | Yes -- except USB |
|
||||
| System Integration | Partial [^2] | No |
|
||||
| Minimum Android Version | Android 11 or higher | Android 9 or higher |
|
||||
|
||||
[^1]: Also known as "Removable eSIM"
|
||||
[^2]: Carrier Partner API unimplemented yet
|
||||
| | OpenEUICC | EasyEUICC |
|
||||
|:------------------------------|:-----------------------------------------------:|:-----------------:|
|
||||
| Privileged | Must be installed as system app | No |
|
||||
| Internal eSIM | Supported | Unsupported |
|
||||
| External (Removable) eSIM | Supported | Supported |
|
||||
| USB Readers | Supported | Supported |
|
||||
| Requires allowlisting by eSIM | No | Yes -- except USB |
|
||||
| System Integration | Partial (carrier partner API unimplemented yet) | No |
|
||||
|
||||
Some side notes:
|
||||
1. When privileged, OpenEUICC supports any eUICC chip that implements the SGP.22 standard, internal or external. However, there is __no guarantee__ that external (removable) eSIMs actually follow the standard. Please __DO NOT__ submit bug reports for non-functioning removable eSIMs. They are __NOT__ officially supported unless they also support / are supported by EasyEUICC, the unprivileged variant.
|
||||
2. Both variants support accessing eUICC chips through USB CCID readers, regardless of whether the chip contains the correct ARA-M hash to allow for unprivileged access. However, only `T=0` readers that use the standard [USB CCID protocol](https://en.wikipedia.org/wiki/CCID_(protocol)) are supported.
|
||||
3. Prebuilt release-mode EasyEUICC apks can be downloaded [here](https://gitea.angry.im/PeterCxy/OpenEUICC/releases). For OpenEUICC, no official release is currently provided and only debug mode APKs can be found in the CI page.
|
||||
4. For removable eSIM chip vendors: to have your chip supported by official builds of EasyEUICC when inserted, include the ARA-M hash `2A2FA878BC7C3354C2CF82935A5945A3EDAE4AFA`.
|
||||
|
||||
1. When privileged, OpenEUICC supports any eUICC chip that implements the [SGP.22] standard, internal or external.
|
||||
However, there is **no guarantee** that external (removable) eSIMs actually follow the standard.
|
||||
Please **DO NOT** submit bug reports for non-functioning removable eSIMs.
|
||||
They are **NOT** officially supported unless they also support / are supported by EasyEUICC, the unprivileged variant.
|
||||
2. Both variants support accessing eUICC chips through USB CCID readers,
|
||||
regardless of whether the chip contains the correct ARA-M hash to allow for unprivileged access.
|
||||
However, only `T=0` readers that use the standard [USB CCID protocol][usb-ccid] are supported.
|
||||
3. Prebuilt release-mode EasyEUICC apks can be downloaded [here][releases].
|
||||
For OpenEUICC, no official release is currently provided and only debug mode APKs and Magisk modules can be found in the [CI page][actions].
|
||||
4. For removable eSIM chip vendors: to have your chip supported by official builds of EasyEUICC when inserted,
|
||||
include the ARA-M hash `2A2FA878BC7C3354C2CF82935A5945A3EDAE4AFA`.
|
||||
__This project is Free Software licensed under GNU GPL v3, WITHOUT the "or later" clause.__ Any modification and derivative work __MUST__ be released under the SAME license, which means, at the very least, that the source code __MUST__ be available upon request.
|
||||
|
||||
[sgp.22]: https://www.gsma.com/solutions-and-impact/technologies/esim/gsma_resources/sgp-22-v2-2-2/ "SGP.22 v2.2.2"
|
||||
[usb-ccid]: https://en.wikipedia.org/wiki/CCID_%28protocol%29 "USB CCID Protocol"
|
||||
[releases]: https://gitea.angry.im/PeterCxy/OpenEUICC/releases "EasyEUICC Releases"
|
||||
[actions]: https://gitea.angry.im/PeterCxy/OpenEUICC/actions "OpenEUICC Actions"
|
||||
__If you are releasing a modification of this app, you are kindly asked to make changes to at least the app name and package name.__
|
||||
|
||||
**This project is Free Software licensed under GNU GPL v3, WITHOUT the "or later" clause.**
|
||||
Any modification and derivative work **MUST** be released under the SAME license, which means, at the very least, that the source code **MUST** be available upon request.
|
||||
|
||||
**If you are releasing a modification of this app, you are kindly asked to make changes to at least the app name and package name.**
|
||||
|
||||
# Building (Gradle)
|
||||
Building (Gradle)
|
||||
===
|
||||
|
||||
Make sure you have all submodules cloned and updated by running
|
||||
|
||||
|
@ -74,7 +57,8 @@ For EasyEUICC:
|
|||
./gradlew :app-unpriv:assembleRelease
|
||||
```
|
||||
|
||||
# Building (AOSP)
|
||||
Building (AOSP)
|
||||
===
|
||||
|
||||
There are two ways to include OpenEUICC in your AOSP-based system image:
|
||||
|
||||
|
@ -84,22 +68,25 @@ There are two ways to include OpenEUICC in your AOSP-based system image:
|
|||
- Compilation of this project is **only** tested against the latest AOSP release version. The app itself should be compatible with older AOSP versions, but the source may not compile against an older AOSP source tree.
|
||||
2. If compilation against AOSP source tree is not possible, consider [building with gradle](#building-gradle) and import the apk as a prebuilt.
|
||||
- No official `Android.bp` is provided for this case but it should be straightforward to write.
|
||||
- You might want to include [`privapp_whitelist_im.angry.openeuicc.xml`] as well.
|
||||
- You might want to include `privapp_whitelist_im.angry.openeuicc.xml` as well.
|
||||
|
||||
[`privapp_whitelist_im.angry.openeuicc.xml`]: privapp_whitelist_im.angry.openeuicc.xml "OpenEUICC Privapp Whitelist"
|
||||
FAQs
|
||||
===
|
||||
|
||||
# FAQs
|
||||
- Q: Do you provide prebuilt binaries for OpenEUICC?
|
||||
- A: Debug-mode APKs are available continuously as an artifact of the [Actions](https://gitea.angry.im/PeterCxy/OpenEUICC/actions) CI used by this project. However, these debug-mode APKs are **not** intended for inclusion inside system images, nor are they supported by the developer in any sense. If you are a custom ROM developer, either include the entire OpenEUICC repository in your AOSP source tree, or generate an APK using `gradle` and import that as a prebuilt system app. Note that you might want `privapp_whitelist_im.angry.openeuicc.xml` as well.
|
||||
|
||||
- Q: Do you provide prebuilt binaries for OpenEUICC? \
|
||||
A: Debug-mode APKs and Magisk modules are available continuously as an artifact of the [Actions] CI used by this project. However, these debug-mode APKs are **not** intended for inclusion inside system images, nor are they supported by the developer in any sense. If you are a custom ROM developer, either include the entire OpenEUICC repository in your AOSP source tree, or generate an APK using `gradle` and import that as a prebuilt system app. Note that you might want [`privapp_whitelist_im.angry.openeuicc.xml`] as well.
|
||||
- Q: AOSP's Settings app seems to be confused by OpenEUICC (for example, disabling / enabling profiles from the Networks page do not work properly)
|
||||
- A: When your device has internal eSIM chip(s) __and__ you have inserted a removable eSIM chip, the Settings app can misbehave since it was never designed for this scenario. __Please prefer using OpenEUICC's own management interface whenever possible.__ In the future, there might be an option to exclude removable SIMs from being reported to the Android system.
|
||||
|
||||
- Q: Can EasyEUICC manage my phone's internal eSIM? \
|
||||
A: No. For EasyEUICC to work, the eSIM chip MUST proactively grant access via its ARA-M field.
|
||||
- Q: Can EasyEUICC manage my phone's internal eSIM?
|
||||
- A: No. For EasyEUICC to work, the eSIM chip MUST proactively grant access via its ARA-M field.
|
||||
|
||||
- Q: Removable eSIMs? Are they a joke? \
|
||||
A: No, even though the name "removable embedded SIM" can sound like an oxymoron. In fact, there can be many advantages to these chips compared to fully embedded ones. For example, the ability to transfer eSIM profiles without carrier support or approval, or the ability to use eSIM on devices that do not and may never get the support, such as Wi-Fi hotspots.
|
||||
- Q: Removable eSIMs? Are they a joke?
|
||||
- A: No, even though the name "removable embedded SIM" can sound like an oxymoron. In fact, there can be many advantages to these chips compared to fully embedded ones. For example, the ability to transfer eSIM profiles without carrier support or approval, or the ability to use eSIM on devices that do not and may never get the support, such as Wi-Fi hotspots.
|
||||
|
||||
# Copyright
|
||||
Copyright
|
||||
===
|
||||
|
||||
Everything except `libs/lpac-jni` and `art/`:
|
||||
|
||||
|
@ -139,4 +126,4 @@ License along with this library; if not, write to the Free Software
|
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
```
|
||||
|
||||
`art/`: Courtesy of [Aikoyori](https://github.com/Aikoyori), CC NC-SA 4.0.
|
||||
`art/`: Courtesy of [Aikoyori](https://github.com/Aikoyori), CC NC-SA 4.0.
|
|
@ -21,7 +21,7 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
|
|||
override suspend fun tryOpenEuiccChannel(
|
||||
port: UiccPortInfoCompat,
|
||||
isdrAid: ByteArray
|
||||
): EuiccChannel? = try {
|
||||
): EuiccChannel? {
|
||||
if (port.portIndex != 0) {
|
||||
Log.w(
|
||||
DefaultEuiccChannelManager.TAG,
|
||||
|
@ -35,52 +35,58 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
|
|||
DefaultEuiccChannelManager.TAG,
|
||||
"Trying OMAPI for physical slot ${port.card.physicalSlotIndex}"
|
||||
)
|
||||
EuiccChannelImpl(
|
||||
context.getString(R.string.channel_type_omapi),
|
||||
port,
|
||||
intrinsicChannelName = null,
|
||||
OmapiApduInterface(
|
||||
seService!!,
|
||||
try {
|
||||
return EuiccChannelImpl(
|
||||
context.getString(R.string.channel_type_omapi),
|
||||
port,
|
||||
context.preferenceRepository.verboseLoggingFlow
|
||||
),
|
||||
isdrAid,
|
||||
context.preferenceRepository.verboseLoggingFlow,
|
||||
context.preferenceRepository.ignoreTLSCertificateFlow,
|
||||
context.preferenceRepository.es10xMssFlow,
|
||||
)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
// Failed
|
||||
Log.w(
|
||||
DefaultEuiccChannelManager.TAG,
|
||||
"OMAPI APDU interface unavailable for physical slot ${port.card.physicalSlotIndex} with ISD-R AID: ${isdrAid.encodeHex()}."
|
||||
)
|
||||
null
|
||||
intrinsicChannelName = null,
|
||||
OmapiApduInterface(
|
||||
seService!!,
|
||||
port,
|
||||
context.preferenceRepository.verboseLoggingFlow
|
||||
),
|
||||
isdrAid,
|
||||
context.preferenceRepository.verboseLoggingFlow,
|
||||
context.preferenceRepository.ignoreTLSCertificateFlow,
|
||||
).also {
|
||||
Log.i(DefaultEuiccChannelManager.TAG, "Is OMAPI channel, setting MSS to 60")
|
||||
it.lpa.setEs10xMss(60)
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
// Failed
|
||||
Log.w(
|
||||
DefaultEuiccChannelManager.TAG,
|
||||
"OMAPI APDU interface unavailable for physical slot ${port.card.physicalSlotIndex} with ISD-R AID: ${isdrAid.encodeHex()}."
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun tryOpenUsbEuiccChannel(
|
||||
ccidCtx: UsbCcidContext,
|
||||
isdrAid: ByteArray
|
||||
): EuiccChannel? = try {
|
||||
EuiccChannelImpl(
|
||||
context.getString(R.string.channel_type_usb),
|
||||
FakeUiccPortInfoCompat(FakeUiccCardInfoCompat(EuiccChannelManager.USB_CHANNEL_ID)),
|
||||
intrinsicChannelName = ccidCtx.productName,
|
||||
UsbApduInterface(
|
||||
ccidCtx
|
||||
),
|
||||
isdrAid,
|
||||
context.preferenceRepository.verboseLoggingFlow,
|
||||
context.preferenceRepository.ignoreTLSCertificateFlow,
|
||||
context.preferenceRepository.es10xMssFlow,
|
||||
)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
// Failed
|
||||
Log.w(
|
||||
DefaultEuiccChannelManager.TAG,
|
||||
"USB APDU interface unavailable for ISD-R AID: ${isdrAid.encodeHex()}."
|
||||
)
|
||||
null
|
||||
): EuiccChannel? {
|
||||
try {
|
||||
return EuiccChannelImpl(
|
||||
context.getString(R.string.channel_type_usb),
|
||||
FakeUiccPortInfoCompat(FakeUiccCardInfoCompat(EuiccChannelManager.USB_CHANNEL_ID)),
|
||||
intrinsicChannelName = ccidCtx.productName,
|
||||
UsbApduInterface(
|
||||
ccidCtx
|
||||
),
|
||||
isdrAid,
|
||||
context.preferenceRepository.verboseLoggingFlow,
|
||||
context.preferenceRepository.ignoreTLSCertificateFlow,
|
||||
)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
// Failed
|
||||
Log.w(
|
||||
DefaultEuiccChannelManager.TAG,
|
||||
"USB APDU interface unavailable for ISD-R AID: ${isdrAid.encodeHex()}."
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun cleanup() {
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package im.angry.openeuicc.core
|
||||
|
||||
import im.angry.openeuicc.util.UiccPortInfoCompat
|
||||
import im.angry.openeuicc.util.decodeHex
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.typeblog.lpac_jni.ApduInterface
|
||||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||
import net.typeblog.lpac_jni.impl.HttpInterfaceImpl
|
||||
|
@ -16,8 +15,7 @@ class EuiccChannelImpl(
|
|||
override val apduInterface: ApduInterface,
|
||||
override val isdrAid: ByteArray,
|
||||
verboseLoggingFlow: Flow<Boolean>,
|
||||
ignoreTLSCertificateFlow: Flow<Boolean>,
|
||||
es10xMssFlow: Flow<Int>,
|
||||
ignoreTLSCertificateFlow: Flow<Boolean>
|
||||
) : EuiccChannel {
|
||||
override val slotId = port.card.physicalSlotIndex
|
||||
override val logicalSlotId = port.logicalSlotIndex
|
||||
|
@ -27,10 +25,8 @@ class EuiccChannelImpl(
|
|||
LocalProfileAssistantImpl(
|
||||
isdrAid,
|
||||
apduInterface,
|
||||
HttpInterfaceImpl(verboseLoggingFlow, ignoreTLSCertificateFlow),
|
||||
).also {
|
||||
it.setEs10xMss(runBlocking { es10xMssFlow.first().toByte() })
|
||||
}
|
||||
HttpInterfaceImpl(verboseLoggingFlow, ignoreTLSCertificateFlow)
|
||||
)
|
||||
|
||||
override val atr: ByteArray?
|
||||
get() = (apduInterface as? ApduInterfaceAtrProvider)?.atr
|
||||
|
|
|
@ -123,13 +123,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
|
|||
add(Item(R.string.euicc_info_pp_version, info.ppVersion.toString()))
|
||||
info.sasAccreditationNumber.trim().takeIf(RE_SAS::matches)
|
||||
?.let { add(Item(R.string.euicc_info_sas_accreditation_number, it.uppercase())) }
|
||||
|
||||
val nvramText = buildString {
|
||||
append(formatFreeSpace(info.freeNvram))
|
||||
append(' ')
|
||||
append(getString(R.string.euicc_info_free_nvram_hint))
|
||||
}
|
||||
add(Item(R.string.euicc_info_free_nvram, nvramText))
|
||||
add(Item(R.string.euicc_info_free_nvram, info.freeNvram.let(::formatFreeSpace)))
|
||||
}
|
||||
channel.lpa.euiccInfo2?.euiccCiPKIdListForSigning.orEmpty().let { signers ->
|
||||
// SGP.28 v1.0, eSIM CI Registration Criteria (Page 5 of 9, 2019-10-24)
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.provider.Settings
|
|||
import android.widget.Toast
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.CheckBoxPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
|
@ -17,6 +16,7 @@ import im.angry.openeuicc.util.*
|
|||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
open class SettingsFragment: PreferenceFragmentCompat() {
|
||||
private lateinit var developerPref: PreferenceCategory
|
||||
|
@ -34,7 +34,7 @@ open class SettingsFragment: PreferenceFragmentCompat() {
|
|||
// Show / hide developer preference based on whether it is enabled
|
||||
lifecycleScope.launch {
|
||||
preferenceRepository.developerOptionsEnabledFlow
|
||||
.onEach(developerPref::setVisible)
|
||||
.onEach { developerPref.isVisible = it }
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
@ -84,9 +84,6 @@ open class SettingsFragment: PreferenceFragmentCompat() {
|
|||
requirePreference<CheckBoxPreference>("pref_developer_euicc_memory_reset")
|
||||
.bindBooleanFlow(preferenceRepository.euiccMemoryResetFlow)
|
||||
|
||||
requirePreference<ListPreference>("pref_developer_es10x_mss")
|
||||
.bindIntFlow(preferenceRepository.es10xMssFlow, 63)
|
||||
|
||||
requirePreference<Preference>("pref_developer_isdr_aid_list").apply {
|
||||
intent = Intent(requireContext(), IsdrAidListActivity::class.java)
|
||||
}
|
||||
|
@ -103,53 +100,51 @@ open class SettingsFragment: PreferenceFragmentCompat() {
|
|||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun onAppVersionClicked(pref: Preference): Boolean {
|
||||
if (developerPref.isVisible) return false
|
||||
|
||||
val now = System.currentTimeMillis()
|
||||
numClicks = if (now - lastClickTimestamp >= 1000) 1 else numClicks + 1
|
||||
if (now - lastClickTimestamp >= 1000) {
|
||||
numClicks = 1
|
||||
} else {
|
||||
numClicks++
|
||||
}
|
||||
lastClickTimestamp = now
|
||||
|
||||
lifecycleScope.launch {
|
||||
preferenceRepository.developerOptionsEnabledFlow.updatePreference(numClicks >= 7)
|
||||
if (numClicks == 7) {
|
||||
lifecycleScope.launch {
|
||||
preferenceRepository.developerOptionsEnabledFlow.updatePreference(true)
|
||||
|
||||
lastToast?.cancel()
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.developer_options_enabled,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
} else if (numClicks > 1) {
|
||||
lastToast?.cancel()
|
||||
lastToast = Toast.makeText(
|
||||
requireContext(),
|
||||
getString(R.string.developer_options_steps, 7 - numClicks),
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
lastToast!!.show()
|
||||
}
|
||||
|
||||
val toastText = when {
|
||||
numClicks == 7 -> getString(R.string.developer_options_enabled)
|
||||
numClicks > 1 -> getString(R.string.developer_options_steps, 7 - numClicks)
|
||||
else -> return true
|
||||
}
|
||||
|
||||
lastToast?.cancel()
|
||||
lastToast = Toast.makeText(requireContext(), toastText, Toast.LENGTH_SHORT)
|
||||
lastToast!!.show()
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun CheckBoxPreference.bindBooleanFlow(flow: PreferenceFlowWrapper<Boolean>) {
|
||||
lifecycleScope.launch {
|
||||
flow.collect(::setChecked)
|
||||
flow.collect { isChecked = it }
|
||||
}
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
lifecycleScope.launch {
|
||||
runBlocking {
|
||||
flow.updatePreference(newValue as Boolean)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun ListPreference.bindIntFlow(flow: PreferenceFlowWrapper<Int>, defaultValue: Int) {
|
||||
lifecycleScope.launch {
|
||||
flow.collect { value = it.toString() }
|
||||
}
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
lifecycleScope.launch {
|
||||
flow.updatePreference((newValue as String).toIntOrNull() ?: defaultValue)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
protected fun mergePreferenceOverlay(overlayKey: String, targetKey: String) {
|
||||
val overlayCat = requirePreference<PreferenceCategory>(overlayKey)
|
||||
val targetCat = requirePreference<PreferenceCategory>(targetKey)
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.view.ViewGroup
|
|||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
|
@ -43,17 +42,19 @@ class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStep
|
|||
}
|
||||
|
||||
private data class ProgressItem(
|
||||
@StringRes val titleRes: Int,
|
||||
var state: ProgressState = ProgressState.NotStarted,
|
||||
var errorMessage: SimplifiedErrorMessages? = null,
|
||||
val titleRes: Int,
|
||||
var state: ProgressState
|
||||
)
|
||||
|
||||
private val progressItems = arrayOf(
|
||||
ProgressItem(R.string.download_wizard_progress_step_preparing),
|
||||
ProgressItem(R.string.download_wizard_progress_step_connecting),
|
||||
ProgressItem(R.string.download_wizard_progress_step_authenticating),
|
||||
ProgressItem(R.string.download_wizard_progress_step_downloading),
|
||||
ProgressItem(R.string.download_wizard_progress_step_finalizing)
|
||||
ProgressItem(R.string.download_wizard_progress_step_preparing, ProgressState.NotStarted),
|
||||
ProgressItem(R.string.download_wizard_progress_step_connecting, ProgressState.NotStarted),
|
||||
ProgressItem(
|
||||
R.string.download_wizard_progress_step_authenticating,
|
||||
ProgressState.NotStarted
|
||||
),
|
||||
ProgressItem(R.string.download_wizard_progress_step_downloading, ProgressState.NotStarted),
|
||||
ProgressItem(R.string.download_wizard_progress_step_finalizing, ProgressState.NotStarted)
|
||||
)
|
||||
|
||||
private val adapter = ProgressItemAdapter()
|
||||
|
@ -121,13 +122,8 @@ class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStep
|
|||
// Change the state of the last InProgress item to success (or error)
|
||||
progressItems.forEachIndexed { index, progressItem ->
|
||||
if (progressItem.state == ProgressState.InProgress) {
|
||||
if (state.downloadError == null) {
|
||||
progressItem.state = ProgressState.Done
|
||||
} else {
|
||||
progressItem.state = ProgressState.Error
|
||||
progressItem.errorMessage =
|
||||
SimplifiedErrorMessages.fromDownloadError(state.downloadError!!)
|
||||
}
|
||||
progressItem.state =
|
||||
if (state.downloadError == null) ProgressState.Done else ProgressState.Error
|
||||
}
|
||||
|
||||
adapter.notifyItemChanged(index)
|
||||
|
@ -137,8 +133,9 @@ class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStep
|
|||
refreshButtons()
|
||||
}
|
||||
|
||||
is EuiccChannelManagerService.ForegroundTaskState.InProgress ->
|
||||
is EuiccChannelManagerService.ForegroundTaskState.InProgress -> {
|
||||
updateProgress(it.progress)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
|
@ -200,15 +197,9 @@ class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStep
|
|||
private val progressBar =
|
||||
root.requireViewById<ProgressBar>(R.id.download_progress_icon_progress)
|
||||
private val icon = root.requireViewById<ImageView>(R.id.download_progress_icon)
|
||||
private val errorTitle =
|
||||
root.requireViewById<TextView>(R.id.download_progress_item_error_title)
|
||||
private val errorSuggestion =
|
||||
root.requireViewById<TextView>(R.id.download_progress_item_error_suggestion)
|
||||
|
||||
fun bind(item: ProgressItem) {
|
||||
title.text = getString(item.titleRes)
|
||||
errorTitle.visibility = View.GONE
|
||||
errorSuggestion.visibility = View.GONE
|
||||
|
||||
when (item.state) {
|
||||
ProgressState.NotStarted -> {
|
||||
|
@ -231,15 +222,6 @@ class DownloadWizardProgressFragment : DownloadWizardActivity.DownloadWizardStep
|
|||
progressBar.visibility = View.GONE
|
||||
icon.setImageResource(R.drawable.ic_error_outline)
|
||||
icon.visibility = View.VISIBLE
|
||||
|
||||
item.errorMessage?.titleResId?.let {
|
||||
errorTitle.visibility = View.VISIBLE
|
||||
errorTitle.text = getString(it)
|
||||
}
|
||||
item.errorMessage?.suggestResId?.let {
|
||||
errorSuggestion.visibility = View.VISIBLE
|
||||
errorSuggestion.text = getString(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,154 +0,0 @@
|
|||
package im.angry.openeuicc.ui.wizard
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import im.angry.openeuicc.common.R
|
||||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||
import org.json.JSONObject
|
||||
import java.net.NoRouteToHostException
|
||||
import java.net.PortUnreachableException
|
||||
import java.net.SocketException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import javax.net.ssl.SSLException
|
||||
|
||||
enum class SimplifiedErrorMessages(
|
||||
@StringRes val titleResId: Int,
|
||||
@StringRes val suggestResId: Int?
|
||||
) {
|
||||
ICCIDAlreadyInUse(
|
||||
R.string.download_wizard_error_iccid_already,
|
||||
R.string.download_wizard_error_suggest_profile_installed
|
||||
),
|
||||
InsufficientMemory(
|
||||
R.string.download_wizard_error_insufficient_memory,
|
||||
R.string.download_wizard_error_suggest_insufficient_memory
|
||||
),
|
||||
UnsupportedProfile(
|
||||
R.string.download_wizard_error_unsupported_profile,
|
||||
null
|
||||
),
|
||||
CardInternalError(
|
||||
R.string.download_wizard_error_card_internal_error,
|
||||
null
|
||||
),
|
||||
EIDNotSupported(
|
||||
R.string.download_wizard_error_eid_not_supported,
|
||||
R.string.download_wizard_error_suggest_contact_carrier
|
||||
),
|
||||
EIDMismatch(
|
||||
R.string.download_wizard_error_eid_mismatch,
|
||||
R.string.download_wizard_error_suggest_contact_reissue
|
||||
),
|
||||
UnreleasedProfile(
|
||||
R.string.download_wizard_error_profile_unreleased,
|
||||
R.string.download_wizard_error_suggest_contact_reissue
|
||||
),
|
||||
MatchingIDRefused(
|
||||
R.string.download_wizard_error_matching_id_refused,
|
||||
R.string.download_wizard_error_suggest_contact_carrier
|
||||
),
|
||||
ProfileRetriesExceeded(
|
||||
R.string.download_wizard_error_profile_retries_exceeded,
|
||||
R.string.download_wizard_error_suggest_contact_carrier
|
||||
),
|
||||
ConfirmationCodeMissing(
|
||||
R.string.download_wizard_error_confirmation_code_missing,
|
||||
R.string.download_wizard_error_suggest_contact_carrier
|
||||
),
|
||||
ConfirmationCodeRefused(
|
||||
R.string.download_wizard_error_confirmation_code_refused,
|
||||
R.string.download_wizard_error_suggest_contact_carrier
|
||||
),
|
||||
ConfirmationCodeRetriesExceeded(
|
||||
R.string.download_wizard_error_confirmation_code_retries_exceeded,
|
||||
R.string.download_wizard_error_suggest_contact_carrier
|
||||
),
|
||||
ProfileExpired(
|
||||
R.string.download_wizard_error_profile_expired,
|
||||
R.string.download_wizard_error_suggest_contact_carrier
|
||||
),
|
||||
UnknownHost(
|
||||
R.string.download_wizard_error_unknown_hostname,
|
||||
null
|
||||
),
|
||||
NetworkUnreachable(
|
||||
R.string.download_wizard_error_network_unreachable,
|
||||
R.string.download_wizard_error_suggest_network_unreachable
|
||||
),
|
||||
TLSError(
|
||||
R.string.download_wizard_error_tls_certificate,
|
||||
null
|
||||
);
|
||||
|
||||
companion object {
|
||||
private val httpErrors = buildMap {
|
||||
// Stage: AuthenticateClient
|
||||
put("8.1" to "4.8", InsufficientMemory)
|
||||
put("8.1.1" to "2.1", EIDNotSupported)
|
||||
put("8.1.1" to "3.8", EIDMismatch)
|
||||
put("8.2" to "1.2", UnreleasedProfile)
|
||||
put("8.2.6" to "3.8", MatchingIDRefused)
|
||||
put("8.8.5" to "6.4", ProfileRetriesExceeded)
|
||||
|
||||
// Stage: GetBoundProfilePackage
|
||||
put("8.2.7" to "2.2", ConfirmationCodeMissing)
|
||||
put("8.2.7" to "3.8", ConfirmationCodeRefused)
|
||||
put("8.2.7" to "6.4", ConfirmationCodeRetriesExceeded)
|
||||
|
||||
// Stage: AuthenticateClient, GetBoundProfilePackage
|
||||
put("8.8.5" to "4.10", ProfileExpired)
|
||||
}
|
||||
|
||||
fun fromDownloadError(exc: LocalProfileAssistant.ProfileDownloadException) = when {
|
||||
exc.lpaErrorReason != "ES10B_ERROR_REASON_UNDEFINED" -> fromLPAErrorReason(exc.lpaErrorReason)
|
||||
exc.lastHttpResponse?.rcode == 200 -> fromHTTPResponse(exc.lastHttpResponse!!)
|
||||
exc.lastHttpException != null -> fromHTTPException(exc.lastHttpException!!)
|
||||
exc.lastApduResponse != null -> fromAPDUResponse(exc.lastApduResponse!!)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun fromLPAErrorReason(reason: String) = when (reason) {
|
||||
"ES10B_ERROR_REASON_UNSUPPORTED_CRT_VALUES" -> UnsupportedProfile
|
||||
"ES10B_ERROR_REASON_UNSUPPORTED_REMOTE_OPERATION_TYPE" -> UnsupportedProfile
|
||||
"ES10B_ERROR_REASON_UNSUPPORTED_PROFILE_CLASS" -> UnsupportedProfile
|
||||
"ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_ALREADY_EXISTS_ON_EUICC" -> ICCIDAlreadyInUse
|
||||
"ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INSUFFICIENT_MEMORY_FOR_PROFILE" -> InsufficientMemory
|
||||
"ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INTERRUPTION" -> CardInternalError
|
||||
"ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_PE_PROCESSING_ERROR" -> CardInternalError
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun fromHTTPResponse(httpResponse: net.typeblog.lpac_jni.HttpInterface.HttpResponse): SimplifiedErrorMessages? {
|
||||
if (httpResponse.data.first().toInt() != '{'.code) return null
|
||||
val response = JSONObject(httpResponse.data.decodeToString())
|
||||
val statusCodeData = response.optJSONObject("header")
|
||||
?.optJSONObject("functionExecutionStatus")
|
||||
?.optJSONObject("statusCodeData")
|
||||
?: return null
|
||||
val subjectCode = statusCodeData.optString("subjectCode")
|
||||
val reasonCode = statusCodeData.optString("reasonCode")
|
||||
return httpErrors[subjectCode to reasonCode]
|
||||
}
|
||||
|
||||
private fun fromHTTPException(exc: Exception) = when (exc) {
|
||||
is SSLException -> TLSError
|
||||
is UnknownHostException -> UnknownHost
|
||||
is NoRouteToHostException -> NetworkUnreachable
|
||||
is PortUnreachableException -> NetworkUnreachable
|
||||
is SocketTimeoutException -> NetworkUnreachable
|
||||
is SocketException -> exc.message
|
||||
?.contains("Connection reset", ignoreCase = true)
|
||||
?.let { if (it) NetworkUnreachable else null }
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun fromAPDUResponse(resp: ByteArray): SimplifiedErrorMessages? {
|
||||
val isSuccess = resp.size >= 2 &&
|
||||
resp[resp.size - 2] == 0x90.toByte() &&
|
||||
resp[resp.size - 1] == 0x00.toByte()
|
||||
if (isSuccess) return null
|
||||
return CardInternalError
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import androidx.datastore.core.DataStore
|
|||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import androidx.fragment.app.Fragment
|
||||
|
@ -39,7 +38,6 @@ internal object PreferenceKeys {
|
|||
val IGNORE_TLS_CERTIFICATE = booleanPreferencesKey("ignore_tls_certificate")
|
||||
val EUICC_MEMORY_RESET = booleanPreferencesKey("euicc_memory_reset")
|
||||
val ISDR_AID_LIST = stringPreferencesKey("isdr_aid_list")
|
||||
val ES10X_MSS = intPreferencesKey("es10x_mss")
|
||||
}
|
||||
|
||||
const val EUICC_DEFAULT_ISDR_AID = "A0000005591010FFFFFFFF8900000100"
|
||||
|
@ -91,7 +89,6 @@ open class PreferenceRepository(private val context: Context) {
|
|||
PreferenceConstants.DEFAULT_AID_LIST,
|
||||
{ Base64.getEncoder().encodeToString(it.encodeToByteArray()) },
|
||||
{ Base64.getDecoder().decode(it).decodeToString() })
|
||||
val es10xMssFlow = bindFlow(PreferenceKeys.ES10X_MSS, 63)
|
||||
|
||||
protected fun <T> bindFlow(
|
||||
key: Preferences.Key<T>,
|
||||
|
|
|
@ -1,32 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/download_progress_item_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_margin="20dp"
|
||||
android:textSize="14sp"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="@id/download_progress_icon_container"
|
||||
app:layout_constraintEnd_toStartOf="@id/download_progress_icon_container"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/download_progress_icon_container"
|
||||
app:layout_constraintVertical_bias="0.5" />
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/download_progress_icon_container"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintHorizontal_bias="0.0" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/download_progress_icon_container"
|
||||
android:layout_margin="20dp"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_margin="20dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0">
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/download_progress_icon_progress"
|
||||
|
@ -44,38 +42,4 @@
|
|||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/download_progress_item_error_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:textColor="?attr/colorError"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toTopOf="@id/download_progress_item_error_suggestion"
|
||||
app:layout_constraintEnd_toStartOf="@id/download_progress_icon_container"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/download_progress_item_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/download_progress_item_error_suggestion"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:textColor="?attr/colorError"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/download_progress_icon_container"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/download_progress_item_title" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -2,13 +2,13 @@
|
|||
<resources>
|
||||
<string name="no_euicc">このアプリでアクセスできるリムーバブル eUICC カードがデバイス上で検出されていません。互換性のあるカード挿入または USB リーダーを接続してください。</string>
|
||||
<string name="no_profile">この eSIM にはプロファイルがありません。</string>
|
||||
<string name="euicc_info_unknown">不明</string>
|
||||
<string name="euicc_info_unavailable">情報がありません</string>
|
||||
<string name="notification_help">ヘルプ</string>
|
||||
<string name="profile_reload_slots">スロットを再読み込み</string>
|
||||
<string name="profile_no_enabled_profile">不明</string>
|
||||
<string name="channel_name_format">論理スロット %d</string>
|
||||
<!-- Profile -->
|
||||
<string name="profile_state_enabled">有効化済み</string>
|
||||
<string name="profile_state_disabled">無効化済み</string>
|
||||
<string name="profile_state_enabled">有効済み</string>
|
||||
<string name="profile_state_disabled">無効済み</string>
|
||||
<string name="profile_provider">プロバイダー:</string>
|
||||
<string name="profile_class">クラス:</string>
|
||||
<string name="profile_class_testing">テスト中</string>
|
||||
|
@ -22,8 +22,6 @@
|
|||
<string name="profile_switch_did_not_refresh">操作は成功しましたが、デバイスのモデムが更新を拒否しました。新しいプロファイルを使用するには機内モードに切り替えるか、再起動する必要があります。</string>
|
||||
<string name="toast_profile_enable_failed">新しい eSIM プロファイルに切り替えることができません。</string>
|
||||
<string name="toast_profile_delete_confirm_text_mismatched">確認文字列が一致しません</string>
|
||||
<string name="toast_euicc_memory_reset_confirm_text_mismatched">確認文字列が一致しません</string>
|
||||
<string name="toast_euicc_memory_reset_finitshed">このチップは消去されました</string>
|
||||
<string name="toast_iccid_copied">ICCID をクリップボードにコピーしました</string>
|
||||
<string name="toast_sn_copied">シリアル番号をクリップボードにコピーしました</string>
|
||||
<string name="toast_eid_copied">EID をクリップボードにコピーしました</string>
|
||||
|
@ -40,16 +38,14 @@
|
|||
<string name="task_profile_delete_failure">eSIM プロファイルの削除に失敗しました</string>
|
||||
<string name="task_profile_switch">eSIM プロファイルを切り替え中</string>
|
||||
<string name="task_profile_switch_failure">eSIM プロファイルの切り替えに失敗しました</string>
|
||||
<string name="task_euicc_memory_reset">eSIM チップを消去中</string>
|
||||
<string name="task_euicc_memory_reset_failure">eSIM チップの消去に失敗しました</string>
|
||||
<string name="profile_download">新しい eSIM</string>
|
||||
<string name="profile_download_server">サーバー (RSP / SM-DP+)</string>
|
||||
<string name="profile_download_code">アクティベーションコード</string>
|
||||
<string name="profile_download_confirmation_code">確認コード (オプション)</string>
|
||||
<string name="profile_download_confirmation_code_required">確認コード (必須)</string>
|
||||
<string name="profile_download_imei">IMEI (オプション)</string>
|
||||
<string name="profile_download_low_nvram_title">残りの容量が少量です</string>
|
||||
<string name="profile_download_low_nvram_message">残り容量が少ないため、このプロファイルのダウンロードに失敗する可能性があります。</string>
|
||||
<string name="profile_download_low_nvram_title">残り容量が少ない</string>
|
||||
<string name="profile_download_low_nvram_message">残り容量が少ないため、ダウンロードに失敗する可能性があります。</string>
|
||||
<string name="profile_download_no_lpa_string">クリップボードに LPA コードがありません</string>
|
||||
<string name="profile_download_incorrect_lpa_string">解析できません</string>
|
||||
<string name="profile_download_incorrect_lpa_string_message">QR コードまたはクリップボードの内容を LPA コードとして解析できませんでした。</string>
|
||||
|
@ -87,27 +83,6 @@
|
|||
<string name="download_wizard_diagnostics_last_apdu_exception">最終の APDU 例外:</string>
|
||||
<string name="download_wizard_diagnostics_save">保存</string>
|
||||
<string name="download_wizard_diagnostics_file_template">「%s」での診断</string>
|
||||
<string name="download_wizard_error_iccid_already">この eSIM プロファイルはすでに eSIM チップに存在します。</string>
|
||||
<string name="download_wizard_error_insufficient_memory">eSIM チップにはプロファイルをダウンロードするのに必要なメモリが残っていません。</string>
|
||||
<string name="download_wizard_error_unsupported_profile">この eSIM プロファイルは、eSIM チップではサポートされていません。</string>
|
||||
<string name="download_wizard_error_card_internal_error">eSIM チップでエラーが発生しました。</string>
|
||||
<string name="download_wizard_error_eid_not_supported">使用しているデバイスまたは eSIM チップの EID は、通信事業者によってサポートされていません。</string>
|
||||
<string name="download_wizard_error_eid_mismatch">この eSIM プロファイルは、別のデバイスにダウンロードされています。</string>
|
||||
<string name="download_wizard_error_profile_unreleased">この eSIM プロファイルは取り消されました。</string>
|
||||
<string name="download_wizard_error_matching_id_refused">アクティベーションコードが無効です。</string>
|
||||
<string name="download_wizard_error_profile_retries_exceeded">eSIM プロファイルのダウンロード試行回数の上限を超えました。</string>
|
||||
<string name="download_wizard_error_confirmation_code_missing">このプロファイルをダウンロードするには確認コードが必要です。</string>
|
||||
<string name="download_wizard_error_confirmation_code_refused">入力した確認コードは無効です。</string>
|
||||
<string name="download_wizard_error_profile_expired">この eSIM プロファイルは有効期限が切れています。</string>
|
||||
<string name="download_wizard_error_confirmation_code_retries_exceeded">確認コードのダウンロード試行回数の上限を超えました。</string>
|
||||
<string name="download_wizard_error_unknown_hostname">不明な SM-DP+ アドレス</string>
|
||||
<string name="download_wizard_error_network_unreachable">ネットワークにアクセスできません</string>
|
||||
<string name="download_wizard_error_tls_certificate">TLS 証明書エラー、この eSIM プロファイルはサポートされていません</string>
|
||||
<string name="download_wizard_error_suggest_profile_installed">ダウンロード済みの eSIM プロファイルを再インストールしようとしています</string>
|
||||
<string name="download_wizard_error_suggest_insufficient_memory">未使用の eSIM プロファイルをいくつか削除して、再度お試しください</string>
|
||||
<string name="download_wizard_error_suggest_contact_carrier">サポートについては、通信事業者にお問い合わせください。</string>
|
||||
<string name="download_wizard_error_suggest_contact_reissue">この eSIM プロファイルを再発行するには、通信事業者にお問い合わせください。</string>
|
||||
<string name="download_wizard_error_suggest_network_unreachable">別のネットワークに接続後 (例: Wi-Fi とデータを切り替え) を行った後に再度お試しください。</string>
|
||||
<string name="logs_saved_message">ログは共有したパスに保存されました。別のアプリで共有しますか?</string>
|
||||
<string name="profile_rename_new_name">新しいニックネーム</string>
|
||||
<string name="profile_rename_encoding_error">ニックネームを UTF-8 にエンコードできませんでした</string>
|
||||
|
@ -121,8 +96,8 @@
|
|||
<string name="profile_notifications_help">eSIM プロファイルはダウンロードや削除、有効化や無効化されたときに通信事業者に通知を送信できます。送信されるこれらの通知のキューはここにリストされます。\n\n設定では、各タイプの通知を自動的に送信するかどうかを指定できます。通知が送信された場合でもキューのスペースが不足していない限り、記録から自動的に削除されることはありません。\n\nここでは保留中の各通知を手動で送信または削除できます。</string>
|
||||
<string name="profile_notification_operation_download">ダウンロードしました</string>
|
||||
<string name="profile_notification_operation_delete">削除しました</string>
|
||||
<string name="profile_notification_operation_enable">有効化済み</string>
|
||||
<string name="profile_notification_operation_disable">無効化済み</string>
|
||||
<string name="profile_notification_operation_enable">有効化しました</string>
|
||||
<string name="profile_notification_operation_disable">無効化しました</string>
|
||||
<string name="profile_notification_process">処理</string>
|
||||
<string name="profile_notification_delete">削除</string>
|
||||
<string name="euicc_info">eUICC 情報</string>
|
||||
|
@ -139,29 +114,17 @@
|
|||
<string name="euicc_info_sas_accreditation_number">SAS 認定番号</string>
|
||||
<string name="euicc_info_pp_version">保護されたプロファイルのバージョン</string>
|
||||
<string name="euicc_info_free_nvram">NVRAM の空き容量 (eSIM プロファイルストレージ)</string>
|
||||
<string name="euicc_info_free_nvram_hint">(参照用)</string>
|
||||
<string name="euicc_info_ci_type">証明書発行者 (CI)</string>
|
||||
<string name="euicc_info_ci_gsma_live">GSMA ライブ CI</string>
|
||||
<string name="euicc_info_ci_gsma_test">GSMA テスト CI</string>
|
||||
<string name="euicc_info_ci_unknown">不明な eSIM CI</string>
|
||||
<string name="euicc_memory_reset">eUICC を消去</string>
|
||||
<string name="euicc_memory_reset_title">eUICC を消去</string>
|
||||
<string name="euicc_memory_reset_message">このチップ上のすべてのプロファイルを削除することを確認してください。この操作は元に戻せないことを理解してください。\n\nEID: %1$s\n\n%2$s</string>
|
||||
<string name="euicc_memory_reset_hint_text">確認のために「%s」を入力してください</string>
|
||||
<string name="euicc_memory_reset_confirm_text">EID が %s で終わるチップを消去することを確認し、この操作は元に戻せないことを理解してください</string>
|
||||
<string name="euicc_memory_reset_invoke_button">消去</string>
|
||||
<!-- eUICC Info -->
|
||||
<string name="euicc_info_yes">はい</string>
|
||||
<string name="euicc_info_no">いいえ</string>
|
||||
<string name="euicc_info_unknown">不明</string>
|
||||
<string name="euicc_info_unavailable">情報がありません</string>
|
||||
<string name="logs_save">保存</string>
|
||||
<string name="logs_filename_template">%s のログ</string>
|
||||
<string name="developer_options_steps">開発者になるまであと %d ステップです。</string>
|
||||
<string name="developer_options_enabled">あなたは開発者になりました!</string>
|
||||
<string name="isdr_aid_list">ISD-R AID リスト</string>
|
||||
<string name="isdr_aid_list_saved">カスタム ISD-R AID リストを保存しました。</string>
|
||||
<string name="isdr_aid_list_restore_defaults">リセット</string>
|
||||
<string name="isdr_aid_list_saved">カスタム ISD-R AID リストが保存されました</string>
|
||||
<string name="pref_settings">設定</string>
|
||||
<string name="pref_notifications">通知</string>
|
||||
<string name="pref_notifications_desc">eSIM のプロファイル操作により、通信事業者に通知が送信されます。必要に応じてこの動作を微調整できます。</string>
|
||||
|
@ -173,7 +136,7 @@
|
|||
<string name="pref_notifications_switch_desc">プロファイルを<i>切り替え中</i>の通知を送信します\nこのタイプの通知は信頼できないことに注意してください。</string>
|
||||
<string name="pref_advanced">高度な設定</string>
|
||||
<string name="pref_advanced_disable_safeguard_removable_esim">プロファイルの無効化と削除を許可</string>
|
||||
<string name="pref_advanced_disable_safeguard_removable_esim_desc">デフォルトでは、このアプリでデバイスに挿入されたリムーバブル eSIM の有効なプロファイルを無効化することを防いでいます。なぜなのかというと<i>時々</i>アクセスができなくなるからです。\nこのチェックボックスを ON にすることで、この保護機能を<i>解除</i>します。</string>
|
||||
<string name="pref_advanced_disable_safeguard_removable_esim_desc">デフォルトでは、このアプリでデバイスに挿入された取り外し可能な eSIM の有効なプロファイルを無効化することを防いでいます。なぜなのかというと<i>時々</i>アクセスができなくなるからです。\nこのチェックボックスを ON にすることで、この保護機能を<i>解除</i>します。</string>
|
||||
<string name="pref_advanced_verbose_logging">詳細ログ</string>
|
||||
<string name="pref_advanced_verbose_logging_desc">詳細ログを有効化します。これには個人的な情報が含まれている可能性があります。この機能を ON にした後は、信頼できるユーザーとのみログを共有してください。</string>
|
||||
<string name="pref_advanced_language">言語</string>
|
||||
|
@ -181,22 +144,29 @@
|
|||
<string name="pref_advanced_logs">ログ</string>
|
||||
<string name="pref_advanced_logs_desc">アプリの最新デバッグログを表示します</string>
|
||||
<string name="pref_developer">開発者オプション</string>
|
||||
<string name="pref_developer_refresh_after_switch">モデムに更新コマンドを送信</string>
|
||||
<string name="pref_developer_refresh_after_switch_desc">プロファイルを切り替えた後にモデムに更新コマンドを送信するかどうかを設定します。クラッシュが発生する場合は、この機能を無効化してください。</string>
|
||||
<string name="pref_developer_refresh_after_switch_desc">プロファイルを切り替えた後にモデムに更新コマンドを送信するかどうか。クラッシュが発生する場合は、これを無効にしてみてください。</string>
|
||||
<string name="pref_developer_unfiltered_profile_list">フィルタリングされていないプロファイル一覧を表示</string>
|
||||
<string name="pref_developer_unfiltered_profile_list_desc">非運用のプロファイルも含めます</string>
|
||||
<string name="pref_developer_ignore_tls_certificate">SM-DP+ TLS 証明書を無視する</string>
|
||||
<string name="pref_developer_ignore_tls_certificate_desc">RSP サーバーで使用される TLS 証明書を受け入れます</string>
|
||||
<string name="pref_developer_euicc_memory_reset">eUICC の消去を許可</string>
|
||||
<string name="pref_developer_euicc_memory_reset_desc">これは危険な操作であり、デフォルトでは非表示になっています。代わりとしてすべてのプロファイルを手動で削除することもできます。</string>
|
||||
<string name="pref_developer_es10x_mss_desc">グローバル ES10x MSS</string>
|
||||
<string-array name="pref_developer_es10x_entry_keys">
|
||||
<item>高速</item>
|
||||
<item>互換モード</item>
|
||||
</string-array>
|
||||
<string name="pref_developer_isdr_aid_list">ISD-R AID リストをカスタマイズ</string>
|
||||
<string name="pref_developer_isdr_aid_list_desc">一部ブランドのリムーバブル eUICC は独自の非標準な ISD-R AID を使用しているため、サードパーティー製アプリからアクセスできない場合があります。このリストに追加された非標準な AID の使用を試みますが、動作の保証はできません。</string>
|
||||
<string name="pref_developer_isdr_aid_list_desc">一部のブランドの取り外し可能な eUICC では、独自の非標準 ISD-R AID が使用されている場合があり、サードパーティ アプリからアクセスできなくなります。アプリはこのリストに追加された非標準の AID の使用を試みる可能性がありますが、動作することは保証されません。</string>
|
||||
<string name="pref_info">情報</string>
|
||||
<string name="pref_info_app_version">アプリバージョン</string>
|
||||
<string name="pref_info_source_code">ソースコード</string>
|
||||
<string name="toast_euicc_memory_reset_confirm_text_mismatched">確認文字列が一致しません</string>
|
||||
<string name="toast_euicc_memory_reset_finitshed">このチップは消去されました</string>
|
||||
<string name="task_euicc_memory_reset">eSIM チップを消去しています</string>
|
||||
<string name="task_euicc_memory_reset_failure">eSIM チップの消去は失敗しました</string>
|
||||
<string name="euicc_memory_reset">eSIM を消去する</string>
|
||||
<string name="euicc_memory_reset_title">eSIM を消去する</string>
|
||||
<string name="euicc_memory_reset_message">このチップ内のすべてのプロファイルを削除することをご確認してください。この操作は元に戻せないことをご理解してください。\n\nEID: %1$s\n\n%2$s</string>
|
||||
<string name="euicc_memory_reset_hint_text">確認のため、ここに「%s」を入力してください</string>
|
||||
<string name="euicc_memory_reset_confirm_text">EID が %s で終わるチップを消去することに同意します。これは元に戻せないことを理解しています。</string>
|
||||
<string name="euicc_memory_reset_invoke_button">消去する</string>
|
||||
<string name="pref_developer_euicc_memory_reset">eUICC の消去を可能にする</string>
|
||||
<string name="pref_developer_euicc_memory_reset_desc">この操作は、デフォルトでは非表示になっている危険な操作です。代わりに、すべての構成ファイルを手動で削除することもできます。</string>
|
||||
<string name="pref_developer_refresh_after_switch">モデムに更新コマンドを送信</string>
|
||||
<string name="pref_developer_isdr_aid_list">ISD-R AID リストのカスタマイズ</string>
|
||||
<string name="isdr_aid_list_restore_defaults">リセット</string>
|
||||
<string name="isdr_aid_list">ISD-R AID リスト</string>
|
||||
</resources>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
<string name="euicc_info_unknown">未知</string>
|
||||
<string name="notification_help">帮助</string>
|
||||
<string name="profile_reload_slots">重新加载卡槽</string>
|
||||
<string name="profile_no_enabled_profile">未知</string>
|
||||
<string name="channel_name_format">逻辑卡槽 %d</string>
|
||||
<string name="profile_state_enabled">已启用</string>
|
||||
<string name="profile_state_disabled">已禁用</string>
|
||||
|
@ -47,7 +46,6 @@
|
|||
<string name="profile_download_imei">IMEI (可选)</string>
|
||||
<string name="profile_download_low_nvram_title">剩余空间不足</string>
|
||||
<string name="profile_download_low_nvram_message">当前芯片的剩余空间不足,可能导致配置下载失败。\n是否继续下载?</string>
|
||||
<string name="download_wizard_error_suggest_network_unreachable">请连接到其他网络(例如在 Wi-Fi 和数据之间切换)后重试。</string>
|
||||
<string name="logs_saved_message">日志已保存到指定路径。需要通过其他 App 分享吗?</string>
|
||||
<string name="profile_rename_new_name">新昵称</string>
|
||||
<string name="profile_rename_encoding_error">无法将昵称编码为 UTF-8</string>
|
||||
|
@ -85,11 +83,6 @@
|
|||
<string name="pref_advanced_logs">日志</string>
|
||||
<string name="pref_advanced_logs_desc">查看应用程序的最新调试日志</string>
|
||||
<string name="pref_developer_isdr_aid_list_desc">某些品牌的可移除 eUICC 可能会使用自己的非标准 ISD-R AID,导致第三方应用无法访问。此 App 可以尝试使用此列表中添加的非标准 AID,但不能保证它们一定有效。</string>
|
||||
<string name="pref_developer_es10x_mss_desc">全局 ES10x MSS</string>
|
||||
<string-array name="pref_developer_es10x_entry_keys">
|
||||
<item>最佳效率</item>
|
||||
<item>最佳兼容性</item>
|
||||
</string-array>
|
||||
<string name="pref_info">信息</string>
|
||||
<string name="pref_info_app_version">App 版本</string>
|
||||
<string name="pref_info_source_code">源码</string>
|
||||
|
@ -143,7 +136,6 @@
|
|||
<string name="euicc_info_sas_accreditation_number">SAS 认证号码</string>
|
||||
<string name="euicc_info_pp_version">Protected Profile 版本</string>
|
||||
<string name="euicc_info_free_nvram">NVRAM 剩余空间 (eSIM 存储容量)</string>
|
||||
<string name="euicc_info_free_nvram_hint">(仅供参考)</string>
|
||||
<string name="euicc_info_ci_type">证书签发者 (CI)</string>
|
||||
<string name="euicc_info_ci_gsma_live">GSMA 生产环境 CI</string>
|
||||
<string name="euicc_info_ci_gsma_test">GSMA 测试 CI</string>
|
||||
|
@ -177,24 +169,4 @@
|
|||
<string name="pref_developer_isdr_aid_list">自定义 ISD-R AID 列表</string>
|
||||
<string name="isdr_aid_list_restore_defaults">重置</string>
|
||||
<string name="isdr_aid_list">ISD-R AID 列表</string>
|
||||
<string name="download_wizard_error_iccid_already">此 eSIM 配置文件已存在于您的 eSIM 芯片上。</string>
|
||||
<string name="download_wizard_error_insufficient_memory">您的 eSIM 芯片没有足够的空间来下载配置文件。</string>
|
||||
<string name="download_wizard_error_unsupported_profile">您的 eSIM 芯片不支持此 eSIM 配置文件。</string>
|
||||
<string name="download_wizard_error_card_internal_error">eSIM 芯片错误。</string>
|
||||
<string name="download_wizard_error_eid_not_supported">您的设备或 eSIM 芯片的 EID 不受您的运营商支持。</string>
|
||||
<string name="download_wizard_error_eid_mismatch">此 eSIM 配置文件已被下载到另一台设备上。</string>
|
||||
<string name="download_wizard_error_profile_unreleased">此 eSIM 配置文件已被撤销。</string>
|
||||
<string name="download_wizard_error_matching_id_refused">激活码无效。</string>
|
||||
<string name="download_wizard_error_profile_retries_exceeded">已超出 eSIM 配置文件的最大下载尝试次数。</string>
|
||||
<string name="download_wizard_error_confirmation_code_missing">下载此配置文件需要确认码。</string>
|
||||
<string name="download_wizard_error_confirmation_code_refused">您输入的确认码无效。</string>
|
||||
<string name="download_wizard_error_profile_expired">此 eSIM 配置文件已过期。</string>
|
||||
<string name="download_wizard_error_confirmation_code_retries_exceeded">已超出确认码的最大下载尝试次数。</string>
|
||||
<string name="download_wizard_error_unknown_hostname">未知的 SM-DP+ 地址</string>
|
||||
<string name="download_wizard_error_network_unreachable">网络不可达</string>
|
||||
<string name="download_wizard_error_tls_certificate">TLS 证书错误,不支持此 eSIM 配置文件</string>
|
||||
<string name="download_wizard_error_suggest_profile_installed">您正在尝试重新安装已下载的 eSIM 配置文件</string>
|
||||
<string name="download_wizard_error_suggest_insufficient_memory">请删除一些未使用的 eSIM 配置文件,然后重试</string>
|
||||
<string name="download_wizard_error_suggest_contact_carrier">请联系您的运营商寻求帮助。</string>
|
||||
<string name="download_wizard_error_suggest_contact_reissue">请联系您的运营商重新签发此 eSIM 配置文件。</string>
|
||||
</resources>
|
|
@ -5,7 +5,6 @@
|
|||
<string name="euicc_info_unknown">未知</string>
|
||||
<string name="notification_help">幫助</string>
|
||||
<string name="profile_reload_slots">重新載入卡槽</string>
|
||||
<string name="profile_no_enabled_profile">未知</string>
|
||||
<string name="channel_name_format">虛擬卡槽 %d</string>
|
||||
<string name="profile_state_enabled">已啟用</string>
|
||||
<string name="profile_state_disabled">已停用</string>
|
||||
|
@ -47,7 +46,6 @@
|
|||
<string name="profile_download_imei">IMEI (可選)</string>
|
||||
<string name="profile_download_low_nvram_title">剩餘空間不足</string>
|
||||
<string name="profile_download_low_nvram_message">目前晶片的剩餘空間不足,可能導致配置下載失敗。\n是否繼續下載?</string>
|
||||
<string name="download_wizard_error_suggest_network_unreachable">請連接到其他網路(例如在 Wi-Fi 和資料之間切換)後重試。</string>
|
||||
<string name="logs_saved_message">日誌已儲存到指定路徑。需要透過其他 App 分享嗎?</string>
|
||||
<string name="profile_rename_new_name">新名稱</string>
|
||||
<string name="profile_rename_encoding_error">無法將名稱編碼為 UTF-8</string>
|
||||
|
@ -85,7 +83,6 @@
|
|||
<string name="pref_advanced_disable_safeguard_removable_esim">允許 停用/刪除 已啟用的設定檔</string>
|
||||
<string name="pref_advanced_disable_safeguard_removable_esim_desc">預設情況下,此應用程式會阻止您停用可插拔 eSIM 中已啟用的設定檔。\n因為這樣做 <i>有時</i> 會導致無法存取。\n勾選此框以 <i>移除</i> 此保護措施。</string>
|
||||
<string name="pref_developer_isdr_aid_list_desc">某些品牌的可移除 eUICC 可能會使用自己的非標準 ISD-R AID,導致第三方應用程式無法存取。此 App 可以嘗試使用此清單中新增的非標準 AID,但不能保證它們一定有效。</string>
|
||||
<string name="pref_developer_es10x_mss_desc">全局 ES10x MSS</string>
|
||||
<string name="pref_info">資訊</string>
|
||||
<string name="pref_info_app_version">App 版本</string>
|
||||
<string name="pref_info_source_code">原始碼</string>
|
||||
|
@ -139,7 +136,6 @@
|
|||
<string name="euicc_info_sas_accreditation_number">SAS 認證號碼</string>
|
||||
<string name="euicc_info_pp_version">Protected Profile 版本</string>
|
||||
<string name="euicc_info_free_nvram">NVRAM 剩餘空間 (eSIM 儲存容量)</string>
|
||||
<string name="euicc_info_free_nvram_hint">(僅供參考)</string>
|
||||
<string name="euicc_info_ci_type">證書簽發者 (CI)</string>
|
||||
<string name="euicc_info_ci_gsma_live">GSMA 生產環境 CI</string>
|
||||
<string name="euicc_info_ci_gsma_test">GSMA 測試 CI</string>
|
||||
|
@ -173,24 +169,4 @@
|
|||
<string name="pref_developer_isdr_aid_list">自訂 ISD-R AID 列表</string>
|
||||
<string name="isdr_aid_list_restore_defaults">重置</string>
|
||||
<string name="isdr_aid_list">ISD-R AID 列表</string>
|
||||
<string name="download_wizard_error_iccid_already">此 eSIM 設定檔已存在於您的 eSIM 晶片上。</string>
|
||||
<string name="download_wizard_error_insufficient_memory">您的 eSIM 晶片沒有足夠的空間來下載設定檔。</string>
|
||||
<string name="download_wizard_error_unsupported_profile">您的 eSIM 晶片不支援此 eSIM 設定檔。</string>
|
||||
<string name="download_wizard_error_card_internal_error">eSIM 晶片錯誤。</string>
|
||||
<string name="download_wizard_error_eid_not_supported">您的裝置或 eSIM 晶片的 EID 不受您的電信業者支援。</string>
|
||||
<string name="download_wizard_error_eid_mismatch">此 eSIM 設定檔已被下載到另一台裝置上。</string>
|
||||
<string name="download_wizard_error_profile_unreleased">此 eSIM 設定檔已被撤銷。</string>
|
||||
<string name="download_wizard_error_matching_id_refused">啟用碼無效。</string>
|
||||
<string name="download_wizard_error_profile_retries_exceeded">已超出 eSIM 設定檔的最大下載嘗試次數。</string>
|
||||
<string name="download_wizard_error_confirmation_code_missing">下載此設定檔需要確認碼。</string>
|
||||
<string name="download_wizard_error_confirmation_code_refused">您輸入的確認碼無效。</string>
|
||||
<string name="download_wizard_error_profile_expired">此 eSIM 設定檔已過期。</string>
|
||||
<string name="download_wizard_error_confirmation_code_retries_exceeded">已超出確認碼的最大下載嘗試次數。</string>
|
||||
<string name="download_wizard_error_unknown_hostname">未知的 SM-DP+ 位址</string>
|
||||
<string name="download_wizard_error_network_unreachable">網路不可達</string>
|
||||
<string name="download_wizard_error_tls_certificate">TLS 憑證錯誤,不支援此 eSIM 設定檔</string>
|
||||
<string name="download_wizard_error_suggest_profile_installed">您正在嘗試重新安裝已下載的 eSIM 設定文件</string>
|
||||
<string name="download_wizard_error_suggest_insufficient_memory">請刪除一些未使用的 eSIM 設定文件,然後重試</string>
|
||||
<string name="download_wizard_error_suggest_contact_carrier">請聯絡您的電信業者尋求協助。</string>
|
||||
<string name="download_wizard_error_suggest_contact_reissue">請聯絡您的電信業者重新簽發此 eSIM 設定檔。</string>
|
||||
</resources>
|
|
@ -104,27 +104,6 @@
|
|||
<string name="download_wizard_diagnostics_last_apdu_exception">Last APDU exception:</string>
|
||||
<string name="download_wizard_diagnostics_save">Save</string>
|
||||
<string name="download_wizard_diagnostics_file_template">Diagnostics at %s</string>
|
||||
<string name="download_wizard_error_iccid_already">This eSIM profile is already present on your eSIM chip.</string>
|
||||
<string name="download_wizard_error_insufficient_memory">Your eSIM chip does not have sufficient memory left to download the profile.</string>
|
||||
<string name="download_wizard_error_unsupported_profile">This eSIM profile is unsupported by your eSIM chip.</string>
|
||||
<string name="download_wizard_error_card_internal_error">An error occurred in your eSIM chip.</string>
|
||||
<string name="download_wizard_error_eid_not_supported">The EID of your device or eSIM chip is unsupported by your carrier.</string>
|
||||
<string name="download_wizard_error_eid_mismatch">This eSIM profile has been downloaded on another device.</string>
|
||||
<string name="download_wizard_error_profile_unreleased">This eSIM profile has been revoked.</string>
|
||||
<string name="download_wizard_error_matching_id_refused">The activation code is invalid.</string>
|
||||
<string name="download_wizard_error_profile_retries_exceeded">The maximum number of download attempts for the eSIM profile has been exceeded.</string>
|
||||
<string name="download_wizard_error_confirmation_code_missing">Confirmation code is required to download this profile.</string>
|
||||
<string name="download_wizard_error_confirmation_code_refused">The confirmation code you entered is invalid.</string>
|
||||
<string name="download_wizard_error_profile_expired">This eSIM profile has expired.</string>
|
||||
<string name="download_wizard_error_confirmation_code_retries_exceeded">The maximum number of download attempts for the confirmation code has been exceeded.</string>
|
||||
<string name="download_wizard_error_unknown_hostname">Unknown SM-DP+ address</string>
|
||||
<string name="download_wizard_error_network_unreachable">Network is unreachable</string>
|
||||
<string name="download_wizard_error_tls_certificate">TLS certificate error, this eSIM profile is not supported</string>
|
||||
<string name="download_wizard_error_suggest_profile_installed">You are trying to reinstall an already downloaded eSIM profile</string>
|
||||
<string name="download_wizard_error_suggest_insufficient_memory">Please delete some unused eSIM profiles and try again</string>
|
||||
<string name="download_wizard_error_suggest_contact_carrier">Please contact your carrier for assistance.</string>
|
||||
<string name="download_wizard_error_suggest_contact_reissue">Please contact your carrier to reissue this eSIM profile.</string>
|
||||
<string name="download_wizard_error_suggest_network_unreachable">Please try again after connecting to a different network (e.g. switching between Wi-Fi and data).</string>
|
||||
|
||||
<string name="logs_saved_message">Logs have been saved to the selected path. Would you like to share the log through another app?</string>
|
||||
|
||||
|
@ -165,7 +144,6 @@
|
|||
<string name="euicc_info_sas_accreditation_number">SAS Accreditation Number</string>
|
||||
<string name="euicc_info_pp_version">Protected Profile Version</string>
|
||||
<string name="euicc_info_free_nvram">Free NVRAM (eSIM profile storage)</string>
|
||||
<string name="euicc_info_free_nvram_hint">(for reference only)</string>
|
||||
<string name="euicc_info_ci_type">Certificate Issuer (CI)</string>
|
||||
<string name="euicc_info_ci_gsma_live">GSMA Live CI</string>
|
||||
<string name="euicc_info_ci_gsma_test">GSMA Test CI</string>
|
||||
|
@ -222,16 +200,6 @@
|
|||
<string name="pref_developer_ignore_tls_certificate_desc">Accept any TLS certificate used by the RSP server</string>
|
||||
<string name="pref_developer_euicc_memory_reset">Allow erasing eUICC</string>
|
||||
<string name="pref_developer_euicc_memory_reset_desc">This is a dangerous operation and hidden by default. As an alternative, you can delete all profiles manually.</string>
|
||||
<string name="pref_developer_es10x_mss" translatable="false">ES10x MSS</string>
|
||||
<string name="pref_developer_es10x_mss_desc">Global ES10x MSS</string>
|
||||
<string-array name="pref_developer_es10x_entry_keys">
|
||||
<item>High Efficiency</item>
|
||||
<item>Most Compatible</item>
|
||||
</string-array>
|
||||
<string-array name="pref_developer_es10x_entry_values" translatable="false">
|
||||
<item>255</item>
|
||||
<item>63</item>
|
||||
</string-array>
|
||||
<string name="pref_developer_isdr_aid_list">Customize ISD-R AID list</string>
|
||||
<string name="pref_developer_isdr_aid_list_desc">Some brands of removable eUICCs may use their own non-standard ISD-R AID, rendering them inaccessible to third-party apps. We can attempt to use non-standard AIDs added in this list, but there is no guarantee that they will work.</string>
|
||||
<string name="pref_info">Info</string>
|
||||
|
|
|
@ -81,14 +81,6 @@
|
|||
app:summary="@string/pref_developer_euicc_memory_reset_desc"
|
||||
app:title="@string/pref_developer_euicc_memory_reset" />
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="pref_developer_es10x_mss"
|
||||
app:summary="@string/pref_developer_es10x_mss_desc"
|
||||
app:title="@string/pref_developer_es10x_mss"
|
||||
app:entries="@array/pref_developer_es10x_entry_keys"
|
||||
app:entryValues="@array/pref_developer_es10x_entry_values" />
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="pref_developer_isdr_aid_list"
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="compatibility_check">互換性の確認</string>
|
||||
<string name="compatibility_check">互換性のチェック</string>
|
||||
<string name="open_sim_toolkit">SIM ツールキットを開く</string>
|
||||
<!-- Settings -->
|
||||
<!-- Toast -->
|
||||
<string name="toast_ara_m_copied">ARA-M SHA-1 をクリップボードにコピーしました</string>
|
||||
<string name="toast_prompt_to_enable_sim_toolkit">「%s」アプリを有効化してください</string>
|
||||
<!-- Quick Compatibility -->
|
||||
<string name="quick_compatibility">クイックで互換性を確認</string>
|
||||
<string name="quick_compatibility_compatible">このデバイスで「%s」の対応カードを管理できます</string>
|
||||
<string name="quick_compatibility_not_compatible">使用しているデバイスは「%s」と互換性がありません</string>
|
||||
<string name="quick_compatibility_not_compatible_but_usb">使用しているデバイスは「%s」と完全に互換性がありません。ただし、USB スマートカードリーダーを使用すればほぼすべての機能を利用できます。</string>
|
||||
<string name="quick_compatibility_result_slots">アクセス可能スロット: %s</string>
|
||||
<string name="quick_compatibility">互換性のチェック</string>
|
||||
<string name="quick_compatibility_compatible">お使いのスマートフォンは %s 対応 SIM カードを管理できます</string>
|
||||
<string name="quick_compatibility_not_compatible">お使いのスマートフォンは %s と互換性がありません</string>
|
||||
<string name="quick_compatibility_not_compatible_but_usb">お使いのスマートフォンは %s と完全な互換性がありません。ただし、USBスマートカードリーダーを使用する場合、ほぼすべての機能を利用できます。</string>
|
||||
<string name="quick_compatibility_result_slots">アクセス可能なスロット: %s</string>
|
||||
<string name="quick_compatibility_result_slots_isdr">ISD-R アクセス: %s</string>
|
||||
<string name="quick_compatibility_result_notes">注意: これらの結果は参考値です。上記に記載されていない SIM スロットでも、<i>SIM カードを挿入</i>すれば互換性がある場合があります。</string>
|
||||
<string name="quick_compatibility_result_notes_incompatible">注意: 現在 SIM カードが挿入されていない場合は、SIM カードを挿入してから再度互換性の確認をお試しください。どの SIM カードでも構いません。</string>
|
||||
<string name="quick_compatibility_button_continue">続行</string>
|
||||
<string name="quick_compatibility_result_notes">注: これらの結果は参考用です。以上に記載されていない SIM スロットでも、SIM カードを挿入すれば利用できる可能性があります。</string>
|
||||
<string name="quick_compatibility_result_notes_incompatible">注:現在 SIM カードが挿入されていない場合は、SIM カードを挿入してから再度互換性チェックをお試しください。どの SIM カードでも構いません。</string>
|
||||
<string name="quick_compatibility_button_continue">つづく</string>
|
||||
<string name="quick_compatibility_skip">このメッセージを再度表示しない</string>
|
||||
<string name="quick_compatibility_unknown">不明</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import com.android.build.gradle.internal.api.ApkVariantOutputImpl
|
||||
import im.angry.openeuicc.build.*
|
||||
|
||||
plugins {
|
||||
|
@ -49,63 +48,4 @@ dependencies {
|
|||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
}
|
||||
|
||||
val modulePropsTemplate = mutableMapOf(
|
||||
"id" to android.defaultConfig.applicationId!!,
|
||||
"name" to "OpenEUICC",
|
||||
"version" to android.defaultConfig.versionName!!,
|
||||
"versionCode" to "${android.defaultConfig.versionCode}",
|
||||
"author" to "OpenEUICC authors",
|
||||
"description" to "OpenEUICC is an open-source app that provides system-level eSIM integration."
|
||||
)
|
||||
|
||||
val moduleCustomizeScript = project.file("magisk/customize.sh").readText()
|
||||
.replace("{APK_NAME}", "OpenEUICC")
|
||||
.replace("{PKG_NAME}", android.defaultConfig.applicationId!!)
|
||||
|
||||
val moduleUninstallScript = project.file("magisk/uninstall.sh").readText()
|
||||
.replace("{PKG_NAME}", android.defaultConfig.applicationId!!)
|
||||
|
||||
tasks.register<MagiskModuleDirTask>("assembleDebugMagiskModuleDir") {
|
||||
variant = "debug"
|
||||
appName = "OpenEUICC"
|
||||
permsFile = project.rootProject.file("privapp_whitelist_im.angry.openeuicc.xml")
|
||||
moduleInstaller = project.file("magisk/module_installer.sh")
|
||||
moduleCustomizeScriptText = moduleCustomizeScript
|
||||
moduleUninstallScriptText = moduleUninstallScript
|
||||
moduleProp = modulePropsTemplate.let {
|
||||
it["description"] = "(debug build) ${it["description"]}"
|
||||
it["versionCode"] = "${(android.applicationVariants.find { it.name == "debug" }!!.outputs.first() as ApkVariantOutputImpl).versionCodeOverride}"
|
||||
it["updateJson"] = "https://openeuicc.com/magisk/magisk-debug.json"
|
||||
it
|
||||
}
|
||||
dependsOn("assembleDebug")
|
||||
}
|
||||
|
||||
tasks.register<Zip>("assembleDebugMagiskModule") {
|
||||
dependsOn("assembleDebugMagiskModuleDir")
|
||||
from((tasks.getByName("assembleDebugMagiskModuleDir") as MagiskModuleDirTask).outputDir)
|
||||
archiveFileName = "magisk-debug.zip"
|
||||
destinationDirectory = project.layout.buildDirectory.dir("magisk")
|
||||
entryCompression = ZipEntryCompression.STORED
|
||||
}
|
||||
|
||||
tasks.register<MagiskModuleDirTask>("assembleReleaseMagiskModuleDir") {
|
||||
variant = "release"
|
||||
appName = "OpenEUICC"
|
||||
permsFile = project.rootProject.file("privapp_whitelist_im.angry.openeuicc.xml")
|
||||
moduleInstaller = project.file("magisk/module_installer.sh")
|
||||
moduleCustomizeScriptText = moduleCustomizeScript
|
||||
moduleUninstallScriptText = moduleUninstallScript
|
||||
moduleProp = modulePropsTemplate
|
||||
dependsOn("assembleRelease")
|
||||
}
|
||||
|
||||
tasks.register<Zip>("assembleReleaseMagiskModule") {
|
||||
dependsOn("assembleReleaseMagiskModuleDir")
|
||||
from((tasks.getByName("assembleReleaseMagiskModuleDir") as MagiskModuleDirTask).outputDir)
|
||||
archiveFileName = "magisk-release.zip"
|
||||
destinationDirectory = project.layout.buildDirectory.dir("magisk")
|
||||
entryCompression = ZipEntryCompression.STORED
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
TMP_FILE="$TMPDIR/{APK_NAME}"
|
||||
|
||||
chmod u+x "$MODPATH/uninstall.sh"
|
||||
cp "$MODPATH/system/system_ext/priv-app/{APK_NAME}/{APK_NAME}.apk" "$TMP_FILE"
|
||||
|
||||
pm install -r "$TMP_FILE"
|
||||
rm -f "$TMP_FILE"
|
||||
|
||||
pm grant "{PKG_NAME}" android.permission.READ_PHONE_STATE
|
|
@ -1,33 +0,0 @@
|
|||
#!/sbin/sh
|
||||
|
||||
#################
|
||||
# Initialization
|
||||
#################
|
||||
|
||||
umask 022
|
||||
|
||||
# echo before loading util_functions
|
||||
ui_print() { echo "$1"; }
|
||||
|
||||
require_new_magisk() {
|
||||
ui_print "*******************************"
|
||||
ui_print " Please install Magisk v20.4+! "
|
||||
ui_print "*******************************"
|
||||
exit 1
|
||||
}
|
||||
|
||||
#########################
|
||||
# Load util_functions.sh
|
||||
#########################
|
||||
|
||||
OUTFD=$2
|
||||
ZIPFILE=$3
|
||||
|
||||
mount /data 2>/dev/null
|
||||
|
||||
[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
|
||||
. /data/adb/magisk/util_functions.sh
|
||||
[ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk
|
||||
|
||||
install_module
|
||||
exit 0
|
|
@ -1 +0,0 @@
|
|||
pm uninstall "{PKG_NAME}"
|
|
@ -42,7 +42,6 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto
|
|||
isdrAid,
|
||||
context.preferenceRepository.verboseLoggingFlow,
|
||||
context.preferenceRepository.ignoreTLSCertificateFlow,
|
||||
context.preferenceRepository.es10xMssFlow,
|
||||
)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
// Failed
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
<string name="lui_desc">使用しているデバイスは eSIM をサポートしています。モバイルネットワークに接続するには通信事業者が発行した eSIM をダウンロードするか、物理 SIM を挿入してください。</string>
|
||||
<string name="lui_skip">スキップ</string>
|
||||
<string name="lui_download">eSIM をダウンロード</string>
|
||||
<!-- Preference -->
|
||||
<string name="pref_developer_telephony_manager_removable">TelephonyManager を常に使用可能にする</string>
|
||||
<string name="pref_developer_telephony_manager_removable_desc">デフォルトでは、非特権モード (EasyEUICC など) での動作と一致させるためにリムーバブル eUICC に対しては OMAPI のみを試行します。ただし、一部デバイスでは正常に動作しない場合があります。このオプションを選択するとリムーバブル eUICC でも TelephonyManager の使用が強制されます。</string>
|
||||
<string name="pref_developer_telephony_manager_removable">TelephonyManagerをどこでも使用</string>
|
||||
<string name="pref_developer_telephony_manager_removable_desc">デフォルトでは、非特権モード (EasyEUICC) と一致するように、取り外し可能な eUICC に対して OMAPI のみが試行されます。これは、一部のデバイスではうまく機能しない可能性があります。このオプションを選択する場合、取り外し可能な eUICC でも TelephonyManager を使用することになります。</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
package im.angry.openeuicc.build
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import java.io.File
|
||||
|
||||
abstract class MagiskModuleDirTask : DefaultTask() {
|
||||
@get:Input
|
||||
abstract val variant : Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val appName : Property<String>
|
||||
|
||||
@get:InputFile
|
||||
abstract val permsFile : Property<File>
|
||||
|
||||
@get:InputFile
|
||||
abstract val moduleInstaller : Property<File>
|
||||
|
||||
@get:Input
|
||||
abstract val moduleCustomizeScriptText : Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val moduleUninstallScriptText : Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val moduleProp : MapProperty<String, String>
|
||||
|
||||
@InputDirectory
|
||||
val inputDir = variant.map { project.layout.buildDirectory.dir("outputs/apk/${it}") }
|
||||
|
||||
@OutputDirectory
|
||||
val outputDir = variant.map { project.layout.buildDirectory.dir("magisk/${it}") }
|
||||
|
||||
@TaskAction
|
||||
fun build() {
|
||||
val dir = outputDir.get().get()
|
||||
project.mkdir(dir)
|
||||
val systemExtDir = dir.dir("system/system_ext")
|
||||
val permDir = dir.dir("system/system_ext/etc/permissions")
|
||||
val appDir = systemExtDir.dir("priv-app/${appName.get()}")
|
||||
val metaInfDir = dir.dir("META-INF/com/google/android")
|
||||
project.mkdir(systemExtDir)
|
||||
project.mkdir(metaInfDir)
|
||||
project.mkdir(appDir)
|
||||
project.mkdir(permDir)
|
||||
project.copy {
|
||||
into(appDir)
|
||||
from(inputDir) {
|
||||
include("app-${variant.get()}.apk")
|
||||
rename("app-${variant.get()}.apk", "${appName.get()}.apk")
|
||||
}
|
||||
}
|
||||
project.copy {
|
||||
from(permsFile)
|
||||
into(permDir)
|
||||
}
|
||||
project.copy {
|
||||
from(moduleInstaller)
|
||||
into(metaInfDir)
|
||||
rename(".*", "update-binary")
|
||||
}
|
||||
dir.file("customize.sh").asFile.writeText(moduleCustomizeScriptText.get())
|
||||
dir.file("uninstall.sh").asFile.writeText(moduleUninstallScriptText.get())
|
||||
metaInfDir.file("updater-script").asFile.writeText("#MAGISK\n")
|
||||
dir.file("module.prop").asFile.writeText(moduleProp.get().map { (k, v) -> "$k=$v" }.joinToString("\n"))
|
||||
}
|
||||
}
|
|
@ -11,14 +11,12 @@ import net.typeblog.lpac_jni.LocalProfileInfo
|
|||
import net.typeblog.lpac_jni.LocalProfileNotification
|
||||
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
||||
import net.typeblog.lpac_jni.Version
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
class LocalProfileAssistantImpl(
|
||||
isdrAid: ByteArray,
|
||||
rawApduInterface: ApduInterface,
|
||||
rawHttpInterface: HttpInterface
|
||||
) : LocalProfileAssistant {
|
||||
): LocalProfileAssistant {
|
||||
companion object {
|
||||
private const val TAG = "LocalProfileAssistantImpl"
|
||||
}
|
||||
|
@ -76,10 +74,6 @@ class LocalProfileAssistantImpl(
|
|||
}
|
||||
}
|
||||
|
||||
// Controls concurrency of every single method in this class, since
|
||||
// the C-side is explicitly NOT thread-safe
|
||||
private val lock = ReentrantLock()
|
||||
|
||||
private val apduInterface = ApduInterfaceWrapper(rawApduInterface)
|
||||
private val httpInterface = HttpInterfaceWrapper(rawHttpInterface)
|
||||
|
||||
|
@ -111,24 +105,23 @@ class LocalProfileAssistantImpl(
|
|||
}
|
||||
|
||||
override val profiles: List<LocalProfileInfo>
|
||||
get() = lock.withLock {
|
||||
@Synchronized
|
||||
get() {
|
||||
val head = LpacJni.es10cGetProfilesInfo(contextHandle)
|
||||
var curr = head
|
||||
val ret = mutableListOf<LocalProfileInfo>()
|
||||
while (curr != 0L) {
|
||||
val state = LocalProfileInfo.State.fromString(LpacJni.profileGetStateString(curr))
|
||||
val clazz = LocalProfileInfo.Clazz.fromString(LpacJni.profileGetClassString(curr))
|
||||
ret.add(
|
||||
LocalProfileInfo(
|
||||
LpacJni.profileGetIccid(curr),
|
||||
state,
|
||||
LpacJni.profileGetName(curr),
|
||||
LpacJni.profileGetNickname(curr),
|
||||
LpacJni.profileGetServiceProvider(curr),
|
||||
LpacJni.profileGetIsdpAid(curr),
|
||||
clazz
|
||||
)
|
||||
)
|
||||
ret.add(LocalProfileInfo(
|
||||
LpacJni.profileGetIccid(curr),
|
||||
state,
|
||||
LpacJni.profileGetName(curr),
|
||||
LpacJni.profileGetNickname(curr),
|
||||
LpacJni.profileGetServiceProvider(curr),
|
||||
LpacJni.profileGetIsdpAid(curr),
|
||||
clazz
|
||||
))
|
||||
curr = LpacJni.profilesNext(curr)
|
||||
}
|
||||
|
||||
|
@ -137,87 +130,79 @@ class LocalProfileAssistantImpl(
|
|||
}
|
||||
|
||||
override val notifications: List<LocalProfileNotification>
|
||||
get() = lock.withLock {
|
||||
@Synchronized
|
||||
get() {
|
||||
val head = LpacJni.es10bListNotification(contextHandle)
|
||||
var curr = head
|
||||
|
||||
try {
|
||||
val ret = mutableListOf<LocalProfileNotification>()
|
||||
while (curr != 0L) {
|
||||
ret.add(
|
||||
LocalProfileNotification(
|
||||
LpacJni.notificationGetSeq(curr),
|
||||
LocalProfileNotification.Operation.fromString(
|
||||
LpacJni.notificationGetOperationString(
|
||||
curr
|
||||
)
|
||||
),
|
||||
LpacJni.notificationGetAddress(curr),
|
||||
LpacJni.notificationGetIccid(curr),
|
||||
)
|
||||
)
|
||||
curr = LpacJni.notificationsNext(curr)
|
||||
}
|
||||
return ret.sortedBy { it.seqNumber }.reversed()
|
||||
} finally {
|
||||
LpacJni.notificationsFree(head)
|
||||
val ret = mutableListOf<LocalProfileNotification>()
|
||||
while (curr != 0L) {
|
||||
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
|
||||
get() = lock.withLock { LpacJni.es10cGetEid(contextHandle)!! }
|
||||
@Synchronized
|
||||
get() = LpacJni.es10cGetEid(contextHandle)!!
|
||||
|
||||
override val euiccInfo2: EuiccInfo2?
|
||||
get() = lock.withLock {
|
||||
@Synchronized
|
||||
get() {
|
||||
val cInfo = LpacJni.es10cexGetEuiccInfo2(contextHandle)
|
||||
if (cInfo == 0L) return null
|
||||
|
||||
try {
|
||||
return EuiccInfo2(
|
||||
Version(LpacJni.euiccInfo2GetSGP22Version(cInfo)),
|
||||
Version(LpacJni.euiccInfo2GetProfileVersion(cInfo)),
|
||||
Version(LpacJni.euiccInfo2GetEuiccFirmwareVersion(cInfo)),
|
||||
Version(LpacJni.euiccInfo2GetGlobalPlatformVersion(cInfo)),
|
||||
LpacJni.euiccInfo2GetSasAcreditationNumber(cInfo),
|
||||
Version(LpacJni.euiccInfo2GetPpVersion(cInfo)),
|
||||
LpacJni.euiccInfo2GetFreeNonVolatileMemory(cInfo).toInt(),
|
||||
LpacJni.euiccInfo2GetFreeVolatileMemory(cInfo).toInt(),
|
||||
buildSet {
|
||||
var cursor = LpacJni.euiccInfo2GetEuiccCiPKIdListForSigning(cInfo)
|
||||
while (cursor != 0L) {
|
||||
add(LpacJni.stringDeref(cursor))
|
||||
cursor = LpacJni.stringArrNext(cursor)
|
||||
}
|
||||
},
|
||||
buildSet {
|
||||
var cursor = LpacJni.euiccInfo2GetEuiccCiPKIdListForVerification(cInfo)
|
||||
while (cursor != 0L) {
|
||||
add(LpacJni.stringDeref(cursor))
|
||||
cursor = LpacJni.stringArrNext(cursor)
|
||||
}
|
||||
},
|
||||
)
|
||||
} finally {
|
||||
LpacJni.euiccInfo2Free(cInfo)
|
||||
}
|
||||
val ret = EuiccInfo2(
|
||||
Version(LpacJni.euiccInfo2GetSGP22Version(cInfo)),
|
||||
Version(LpacJni.euiccInfo2GetProfileVersion(cInfo)),
|
||||
Version(LpacJni.euiccInfo2GetEuiccFirmwareVersion(cInfo)),
|
||||
Version(LpacJni.euiccInfo2GetGlobalPlatformVersion(cInfo)),
|
||||
LpacJni.euiccInfo2GetSasAcreditationNumber(cInfo),
|
||||
Version(LpacJni.euiccInfo2GetPpVersion(cInfo)),
|
||||
LpacJni.euiccInfo2GetFreeNonVolatileMemory(cInfo).toInt(),
|
||||
LpacJni.euiccInfo2GetFreeVolatileMemory(cInfo).toInt(),
|
||||
buildSet {
|
||||
var cursor = LpacJni.euiccInfo2GetEuiccCiPKIdListForSigning(cInfo)
|
||||
while (cursor != 0L) {
|
||||
add(LpacJni.stringDeref(cursor))
|
||||
cursor = LpacJni.stringArrNext(cursor)
|
||||
}
|
||||
},
|
||||
buildSet {
|
||||
var cursor = LpacJni.euiccInfo2GetEuiccCiPKIdListForVerification(cInfo)
|
||||
while (cursor != 0L) {
|
||||
add(LpacJni.stringDeref(cursor))
|
||||
cursor = LpacJni.stringArrNext(cursor)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
LpacJni.euiccInfo2Free(cInfo)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
override fun enableProfile(iccid: String, refresh: Boolean): Boolean = lock.withLock {
|
||||
@Synchronized
|
||||
override fun enableProfile(iccid: String, refresh: Boolean): Boolean =
|
||||
LpacJni.es10cEnableProfile(contextHandle, iccid, refresh) == 0
|
||||
}
|
||||
|
||||
override fun disableProfile(iccid: String, refresh: Boolean): Boolean = lock.withLock {
|
||||
@Synchronized
|
||||
override fun disableProfile(iccid: String, refresh: Boolean): Boolean =
|
||||
LpacJni.es10cDisableProfile(contextHandle, iccid, refresh) == 0
|
||||
}
|
||||
|
||||
override fun deleteProfile(iccid: String): Boolean = lock.withLock {
|
||||
@Synchronized
|
||||
override fun deleteProfile(iccid: String): Boolean =
|
||||
LpacJni.es10cDeleteProfile(contextHandle, iccid) == 0
|
||||
}
|
||||
|
||||
override fun downloadProfile(
|
||||
smdp: String, matchingId: String?, imei: String?,
|
||||
confirmationCode: String?, callback: ProfileDownloadCallback
|
||||
) = lock.withLock {
|
||||
@Synchronized
|
||||
override fun downloadProfile(smdp: String, matchingId: String?, imei: String?,
|
||||
confirmationCode: String?, callback: ProfileDownloadCallback) {
|
||||
val res = LpacJni.downloadProfile(
|
||||
contextHandle,
|
||||
smdp,
|
||||
|
@ -244,17 +229,18 @@ class LocalProfileAssistantImpl(
|
|||
}
|
||||
}
|
||||
|
||||
override fun deleteNotification(seqNumber: Long): Boolean = lock.withLock {
|
||||
@Synchronized
|
||||
override fun deleteNotification(seqNumber: Long): Boolean =
|
||||
LpacJni.es10bDeleteNotification(contextHandle, seqNumber) == 0
|
||||
}
|
||||
|
||||
override fun handleNotification(seqNumber: Long): Boolean = lock.withLock {
|
||||
@Synchronized
|
||||
override fun handleNotification(seqNumber: Long): Boolean =
|
||||
LpacJni.handleNotification(contextHandle, seqNumber).also {
|
||||
Log.d(TAG, "handleNotification $seqNumber = $it")
|
||||
} == 0
|
||||
}
|
||||
|
||||
override fun setNickname(iccid: String, nickname: String) = lock.withLock {
|
||||
@Synchronized
|
||||
override fun setNickname(iccid: String, nickname: String) {
|
||||
val encoded = try {
|
||||
Charsets.UTF_8.encode(nickname).array()
|
||||
} catch (e: CharacterCodingException) {
|
||||
|
@ -273,12 +259,11 @@ class LocalProfileAssistantImpl(
|
|||
}
|
||||
|
||||
override fun euiccMemoryReset() {
|
||||
lock.withLock {
|
||||
LpacJni.es10cEuiccMemoryReset(contextHandle)
|
||||
}
|
||||
LpacJni.es10cEuiccMemoryReset(contextHandle)
|
||||
}
|
||||
|
||||
override fun close() = lock.withLock {
|
||||
@Synchronized
|
||||
override fun close() {
|
||||
if (!finalized) {
|
||||
LpacJni.euiccFini(contextHandle)
|
||||
LpacJni.destroyContext(contextHandle)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue