diff --git a/.gitmodules b/.gitmodules
index f888959..863f185 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
[submodule "libs/lpac-jni/src/main/jni/lpac"]
path = libs/lpac-jni/src/main/jni/lpac
- url = https://github.com/estkme/lpac
+ url = https://github.com/estkme-group/lpac.git
diff --git a/app-common/src/main/java/im/angry/openeuicc/di/DefaultCustomizableTextProvider.kt b/app-common/src/main/java/im/angry/openeuicc/di/DefaultCustomizableTextProvider.kt
index b493611..76227fd 100644
--- a/app-common/src/main/java/im/angry/openeuicc/di/DefaultCustomizableTextProvider.kt
+++ b/app-common/src/main/java/im/angry/openeuicc/di/DefaultCustomizableTextProvider.kt
@@ -8,7 +8,7 @@ open class DefaultCustomizableTextProvider(private val context: Context) : Custo
get() = context.getString(R.string.no_euicc)
override val profileSwitchingTimeoutMessage: String
- get() = context.getString(R.string.enable_disable_timeout)
+ get() = context.getString(R.string.profile_switch_timeout)
override fun formatInternalChannelName(logicalSlotId: Int): String =
context.getString(R.string.channel_name_format, logicalSlotId)
diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt
index 3c94c6c..016e96f 100644
--- a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt
+++ b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt
@@ -253,7 +253,7 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
if (!isUsb) {
withContext(Dispatchers.Main) {
AlertDialog.Builder(requireContext()).apply {
- setMessage(R.string.switch_did_not_refresh)
+ setMessage(R.string.profile_switch_did_not_refresh)
setPositiveButton(android.R.string.ok) { dialog, _ ->
dialog.dismiss()
requireActivity().finish()
@@ -380,9 +380,9 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
state.setText(
if (profile.isEnabled) {
- R.string.enabled
+ R.string.profile_state_enabled
} else {
- R.string.disabled
+ R.string.profile_state_disabled
}
)
provider.text = profile.providerName
diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileRenameFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileRenameFragment.kt
index c588254..281e625 100644
--- a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileRenameFragment.kt
+++ b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileRenameFragment.kt
@@ -65,7 +65,7 @@ class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragment
super.onViewCreated(view, savedInstanceState)
profileRenameNewName.editText!!.setText(currentName)
toolbar.apply {
- setTitle(R.string.rename)
+ setTitle(R.string.profile_rename)
setNavigationOnClickListener {
if (!renaming) dismiss()
}
diff --git a/app-common/src/main/res/layout/euicc_profile.xml b/app-common/src/main/res/layout/euicc_profile.xml
index 74c1d7a..021c53b 100644
--- a/app-common/src/main/res/layout/euicc_profile.xml
+++ b/app-common/src/main/res/layout/euicc_profile.xml
@@ -54,7 +54,7 @@
\ No newline at end of file
diff --git a/app-common/src/main/res/menu/profile_options.xml b/app-common/src/main/res/menu/profile_options.xml
index 6add53d..60722d6 100644
--- a/app-common/src/main/res/menu/profile_options.xml
+++ b/app-common/src/main/res/menu/profile_options.xml
@@ -2,18 +2,18 @@
\ No newline at end of file
diff --git a/app-common/src/main/res/values-ja/strings.xml b/app-common/src/main/res/values-ja/strings.xml
index d51e2c7..e631d52 100644
--- a/app-common/src/main/res/values-ja/strings.xml
+++ b/app-common/src/main/res/values-ja/strings.xml
@@ -7,19 +7,19 @@
ヘルプ
スロットを再読み込み
論理スロット %d
- 有効済み
- 無効済み
- プロバイダー:
+ 有効済み
+ 無効済み
+ プロバイダー:
クラス:
テスト中
プロビジョニング
稼働中
- 有効化
- 無効化
- 削除
- 名前を変更
- eSIM チップがプロファイルの切り替えの待機中にタイムアウトしました。これはデバイスのモデムファームウェアのバグの可能性があります。機内モードに切り替えるかアプリを再起動、デバイスを再起動してください。
- 操作は成功しましたが、デバイスのモデムが更新を拒否しました。新しいプロファイルを使用するには機内モードに切り替えるか、再起動する必要があります。
+ 有効化
+ 無効化
+ 削除
+ 名前を変更
+ eSIM チップがプロファイルの切り替えの待機中にタイムアウトしました。これはデバイスのモデムファームウェアのバグの可能性があります。機内モードに切り替えるかアプリを再起動、デバイスを再起動してください。
+ 操作は成功しましたが、デバイスのモデムが更新を拒否しました。新しいプロファイルを使用するには機内モードに切り替えるか、再起動する必要があります。
新しい eSIM プロファイルに切り替えることができません。
確認文字列が一致しません
ICCID をクリップボードにコピーしました
diff --git a/app-common/src/main/res/values-zh-rCN/strings.xml b/app-common/src/main/res/values-zh-rCN/strings.xml
index 32ced90..b0938d3 100644
--- a/app-common/src/main/res/values-zh-rCN/strings.xml
+++ b/app-common/src/main/res/values-zh-rCN/strings.xml
@@ -6,16 +6,16 @@
帮助
重新加载卡槽
逻辑卡槽 %d
- 已启用
- 已禁用
- 提供商:
+ 已启用
+ 已禁用
+ 提供商:
类型:
- 启用
- 禁用
- 删除
- 重命名
- 等待 eSIM 芯片切换配置文件时超时。这可能是您手机基带固件中的一个错误。请尝试切换飞行模式、重新启动应用程序或重新启动手机
- 操作成功, 但是您手机的基带拒绝刷新。您可能需要切换飞行模式或重新启动,以便使用新的配置文件。
+ 启用
+ 禁用
+ 删除
+ 重命名
+ 等待 eSIM 芯片切换配置文件时超时。这可能是您手机基带固件中的一个错误。请尝试切换飞行模式、重新启动应用程序或重新启动手机
+ 操作成功, 但是您手机的基带拒绝刷新。您可能需要切换飞行模式或重新启动,以便使用新的配置文件。
无法切换到新的 eSIM 配置文件。
输入的确认文本不匹配
已复制 ICCID 到剪贴板
diff --git a/app-common/src/main/res/values-zh-rTW/strings.xml b/app-common/src/main/res/values-zh-rTW/strings.xml
index 5136bf7..e0334c6 100644
--- a/app-common/src/main/res/values-zh-rTW/strings.xml
+++ b/app-common/src/main/res/values-zh-rTW/strings.xml
@@ -6,16 +6,16 @@
幫助
重新載入卡槽
虛擬卡槽 %d
- 已啟用
- 已停用
- 電信業者:
+ 已啟用
+ 已停用
+ 電信業者:
類型:
- 啟用
- 停用
- 刪除
- 重新命名
- 等待 eSIM 切換設定檔時逾時。這可能是您手機基頻處理器韌體中的一個錯誤。請嘗試切換飛航模式、重新啟動應用程式或重新啟動手機
- 操作成功, 但是您手機的基頻處理器沒有重新整理。您可能需要切換飛航模式或重新啟動,以便使用新的設定檔。
+ 啟用
+ 停用
+ 刪除
+ 重新命名
+ 等待 eSIM 切換設定檔時逾時。這可能是您手機基頻處理器韌體中的一個錯誤。請嘗試切換飛航模式、重新啟動應用程式或重新啟動手機
+ 操作成功, 但是您手機的基頻處理器沒有重新整理。您可能需要切換飛航模式或重新啟動,以便使用新的設定檔。
無法切換到新的 eSIM 設定檔。
輸入的確認文字不匹配
已複製 ICCID 到剪貼簿
diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml
index 38bb976..d526238 100644
--- a/app-common/src/main/res/values/strings.xml
+++ b/app-common/src/main/res/values/strings.xml
@@ -11,23 +11,24 @@
USB
OpenMobile API (OMAPI)
- Enabled
- Disabled
- Provider:
+
+ Enabled
+ Disabled
+ Provider:
Class:
Testing
Provisioning
Operational
- ICCID:
+ ICCID:
#%d
- Enable
- Disable
- Delete
- Rename
+ Enable
+ Disable
+ Delete
+ Rename
- Timed out waiting for the eSIM chip to switch profiles. This may be a bug in your phone\'s modem firmware. Try toggling airplane mode, restarting the application, or rebooting the phone.
- The operation was successful, but your phone\'s modem refused to refresh. You might need to toggle airplane mode or reboot in order to use the new profile.
+ Timed out waiting for the eSIM chip to switch profiles. This may be a bug in your phone\'s modem firmware. Try toggling airplane mode, restarting the application, or rebooting the phone.
+ The operation was successful, but your phone\'s modem refused to refresh. You might need to toggle airplane mode or reboot in order to use the new profile.
Cannot switch to new eSIM profile.
Confirmation string mismatch
diff --git a/app-unpriv/src/main/AndroidManifest.xml b/app-unpriv/src/main/AndroidManifest.xml
index ce985cd..9c14163 100644
--- a/app-unpriv/src/main/AndroidManifest.xml
+++ b/app-unpriv/src/main/AndroidManifest.xml
@@ -24,9 +24,9 @@
+ android:label="@string/quick_compatibility" />
by lazy { getCompatibilityChecks(this) }
- private val adapter = CompatibilityChecksAdapter()
-
- override fun onCreate(savedInstanceState: Bundle?) {
- enableEdgeToEdge()
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_compatibility_check)
- setSupportActionBar(requireViewById(im.angry.openeuicc.common.R.id.toolbar))
- setupToolbarInsets()
- supportActionBar!!.setDisplayHomeAsUpEnabled(true)
-
- compatibilityCheckList = requireViewById(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 {
- compatibilityChecks.executeAll { adapter.notifyDataSetChanged() }
- }
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean =
- when (item.itemId) {
- android.R.id.home -> {
- finish()
- true
- }
- else -> super.onOptionsItemSelected(item)
- }
-
- inner class ViewHolder(private val root: View): RecyclerView.ViewHolder(root) {
- private val titleView: TextView = root.requireViewById(R.id.compatibility_check_title)
- private val descView: TextView = root.requireViewById(R.id.compatibility_check_desc)
- private val statusContainer: ViewGroup = root.requireViewById(R.id.compatibility_check_status_container)
-
- fun bindItem(item: CompatibilityCheck) {
- titleView.text = item.title
- descView.text = Html.fromHtml(item.description, Html.FROM_HTML_MODE_COMPACT)
-
- statusContainer.children.forEach {
- it.isVisible = false
- }
-
- val viewId = when (item.state) {
- CompatibilityCheck.State.SUCCESS -> R.id.compatibility_check_checkmark
- CompatibilityCheck.State.FAILURE -> R.id.compatibility_check_error
- CompatibilityCheck.State.FAILURE_UNKNOWN -> R.id.compatibility_check_unknown
- else -> R.id.compatibility_check_progress_bar
- }
- root.requireViewById(viewId).isVisible = true
- }
- }
-
- inner class CompatibilityChecksAdapter: RecyclerView.Adapter() {
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
- ViewHolder(layoutInflater.inflate(R.layout.compatibility_check_item, parent, false))
-
- override fun getItemCount(): Int =
- compatibilityChecks.indexOfLast { it.state != CompatibilityCheck.State.NOT_STARTED } + 1
-
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- holder.bindItem(compatibilityChecks[position])
- }
- }
-}
\ No newline at end of file
diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/ui/QuickCompatibilityActivity.kt b/app-unpriv/src/main/java/im/angry/openeuicc/ui/QuickCompatibilityActivity.kt
new file mode 100644
index 0000000..d5e599f
--- /dev/null
+++ b/app-unpriv/src/main/java/im/angry/openeuicc/ui/QuickCompatibilityActivity.kt
@@ -0,0 +1,24 @@
+package im.angry.openeuicc.ui
+
+import android.os.Bundle
+import androidx.activity.enableEdgeToEdge
+import androidx.appcompat.app.AppCompatActivity
+import im.angry.easyeuicc.R
+import im.angry.openeuicc.di.UnprivilegedUiComponentFactory
+import im.angry.openeuicc.util.OpenEuiccContextMarker
+
+class QuickCompatibilityActivity : AppCompatActivity(), OpenEuiccContextMarker {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContentView(R.layout.activity_quick_compatibility)
+
+ val quickCompatibilityFragment =
+ (appContainer.uiComponentFactory as UnprivilegedUiComponentFactory)
+ .createQuickCompatibilityFragment()
+
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.quick_compatibility_container, quickCompatibilityFragment)
+ .commit()
+ }
+}
diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/ui/QuickCompatibilityFragment.kt b/app-unpriv/src/main/java/im/angry/openeuicc/ui/QuickCompatibilityFragment.kt
new file mode 100644
index 0000000..9b41730
--- /dev/null
+++ b/app-unpriv/src/main/java/im/angry/openeuicc/ui/QuickCompatibilityFragment.kt
@@ -0,0 +1,186 @@
+package im.angry.openeuicc.ui
+
+import android.content.pm.PackageManager
+import android.icu.text.ListFormatter
+import android.os.Build
+import android.os.Bundle
+import android.se.omapi.Reader
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.CheckBox
+import android.widget.TextView
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import im.angry.easyeuicc.R
+import im.angry.openeuicc.util.EUICC_DEFAULT_ISDR_AID
+import im.angry.openeuicc.util.UnprivilegedEuiccContextMarker
+import im.angry.openeuicc.util.connectSEService
+import im.angry.openeuicc.util.decodeHex
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+
+open class QuickCompatibilityFragment : Fragment(), UnprivilegedEuiccContextMarker {
+ companion object {
+ enum class Compatibility {
+ COMPATIBLE,
+ NOT_COMPATIBLE,
+ }
+
+ data class CompatibilityResult(
+ val compatibility: Compatibility,
+ val slotsOmapi: List = emptyList(),
+ val slotsIsdr: List = emptyList()
+ )
+ }
+
+ private val conclusion: TextView by lazy {
+ requireView().requireViewById(R.id.quick_compatibility_conclusion)
+ }
+
+ private val resultSlots: TextView by lazy {
+ requireView().requireViewById(R.id.quick_compatibility_result_slots)
+ }
+
+ private val resultSlotsIsdr: TextView by lazy {
+ requireView().requireViewById(R.id.quick_compatibility_result_slots_isdr)
+ }
+
+ private val resultNotes: TextView by lazy {
+ requireView().requireViewById(R.id.quick_compatibility_result_notes)
+ }
+
+ private val skipCheckBox: CheckBox by lazy {
+ requireView().requireViewById(R.id.quick_compatibility_skip)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View = inflater.inflate(R.layout.fragment_quick_compatibility, container, false).apply {
+ requireViewById(R.id.quick_compatibility_device_information)
+ .text = formatDeviceInformation()
+ requireViewById
+
+
+
+
+
diff --git a/app/src/main/java/im/angry/openeuicc/ui/SlotMappingFragment.kt b/app/src/main/java/im/angry/openeuicc/ui/SlotMappingFragment.kt
index e17f60e..89412ab 100644
--- a/app/src/main/java/im/angry/openeuicc/ui/SlotMappingFragment.kt
+++ b/app/src/main/java/im/angry/openeuicc/ui/SlotMappingFragment.kt
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.os.Bundle
import android.telephony.TelephonyManager
import android.telephony.UiccSlotMapping
+import android.util.Log
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
@@ -45,6 +46,10 @@ class SlotMappingFragment: BaseMaterialDialogFragment(),
private lateinit var adapter: SlotMappingAdapter
private lateinit var helpTextView: TextView
+ private val partner: Partner? by lazy {
+ Partner.getInstance(requireContext())
+ }
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -67,6 +72,12 @@ class SlotMappingFragment: BaseMaterialDialogFragment(),
toolbar.setOnMenuItemClickListener(this)
}
+ override fun onStart() {
+ super.onStart()
+ val mappings = partner?.getString("sim_slot_mappings_json")
+ Log.e(TAG, "sim_slot_mappings_json = $mappings")
+ }
+
override fun onResume() {
super.onResume()
setWidthPercent(85)
diff --git a/app/src/main/java/im/angry/openeuicc/util/Partner.kt b/app/src/main/java/im/angry/openeuicc/util/Partner.kt
new file mode 100644
index 0000000..43ecc18
--- /dev/null
+++ b/app/src/main/java/im/angry/openeuicc/util/Partner.kt
@@ -0,0 +1,51 @@
+package im.angry.openeuicc.util
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import im.angry.openeuicc.BuildConfig
+
+
+class Partner {
+ companion object {
+ private const val ACTION = "com.google.android.euicc.action.PARTNER_CUSTOMIZATION"
+
+ private val instances = mutableMapOf()
+
+ private val packageFlags: Int
+ get() {
+ val flags = if (BuildConfig.DEBUG)
+ PackageManager.MATCH_UNINSTALLED_PACKAGES else
+ PackageManager.MATCH_SYSTEM_ONLY
+ return flags or PackageManager.MATCH_DISABLED_COMPONENTS
+ }
+
+ fun getInstance(context: Context, action: String = ACTION) = instances.getOrPut(action) {
+ context.packageManager
+ .queryBroadcastReceivers(Intent(action), packageFlags)
+ .mapNotNull { it.activityInfo?.applicationInfo }
+ .firstNotNullOfOrNull {
+ try {
+ context.packageManager.getResourcesForApplication(it)
+ } catch (_: PackageManager.NameNotFoundException) {
+ null
+ }
+ }
+ ?.let(::Partner)
+ }
+ }
+
+ private val resources: Resources
+
+ private constructor(resources: Resources) {
+ this.resources = resources
+ }
+
+ private fun getIdentifier(name: String) =
+ resources.getIdentifier(name, null, null).takeIf { it != 0 }
+
+ fun getString(name: String) = getIdentifier(name)?.let(resources::getString)
+
+ fun getBoolean(name: String) = getIdentifier(name)?.let(resources::getBoolean)
+}
\ No newline at end of file