Compare commits

..

No commits in common. "d21194e93ee7a0ddb5365d90a161ae2d2bcae214" and "f8cc78fe311e69d13d7a10473b6630c773c0202d" have entirely different histories.

29 changed files with 162 additions and 228 deletions

View file

@ -37,7 +37,6 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
return EuiccChannelImpl(
context.getString(R.string.omapi),
port,
intrinsicChannelName = null,
OmapiApduInterface(
seService!!,
port,
@ -68,7 +67,6 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
return EuiccChannelImpl(
context.getString(R.string.usb),
FakeUiccPortInfoCompat(FakeUiccCardInfoCompat(EuiccChannelManager.USB_CHANNEL_ID)),
intrinsicChannelName = usbDevice.productName,
UsbApduInterface(
conn,
bulkIn,

View file

@ -16,12 +16,5 @@ interface EuiccChannel {
val valid: Boolean
/**
* Intrinsic name of this channel. For device-internal SIM slots,
* this should be null; for USB readers, this should be the name of
* the reader device.
*/
val intrinsicChannelName: String?
fun close()
}

View file

@ -10,7 +10,6 @@ import net.typeblog.lpac_jni.impl.LocalProfileAssistantImpl
class EuiccChannelImpl(
override val type: String,
override val port: UiccPortInfoCompat,
override val intrinsicChannelName: String?,
apduInterface: ApduInterface,
verboseLoggingFlow: Flow<Boolean>,
ignoreTLSCertificateFlow: Flow<Boolean>

View file

@ -31,8 +31,6 @@ class EuiccChannelWrapper(orig: EuiccChannel) : EuiccChannel {
override val lpa: LocalProfileAssistant by lpaDelegate
override val valid: Boolean
get() = channel.valid
override val intrinsicChannelName: String?
get() = channel.intrinsicChannelName
override fun close() = channel.close()

View file

@ -15,5 +15,4 @@ interface AppContainer {
val preferenceRepository: PreferenceRepository
val uiComponentFactory: UiComponentFactory
val euiccChannelFactory: EuiccChannelFactory
val customizableTextProvider: CustomizableTextProvider
}

View file

@ -1,20 +0,0 @@
package im.angry.openeuicc.di
interface CustomizableTextProvider {
/**
* Explanation string for when no eUICC is found on the device.
* This could be different depending on whether the app is privileged or not.
*/
val noEuiccExplanation: String
/**
* Shown when we timed out switching between profiles.
*/
val profileSwitchingTimeoutMessage: String
/**
* Format the name of a logical slot; internal only -- not intended for
* other channels such as USB.
*/
fun formatInternalChannelName(logicalSlotId: Int): String
}

View file

@ -38,8 +38,4 @@ open class DefaultAppContainer(context: Context) : AppContainer {
override val euiccChannelFactory by lazy {
DefaultEuiccChannelFactory(context)
}
override val customizableTextProvider by lazy {
DefaultCustomizableTextProvider(context)
}
}

View file

@ -1,15 +0,0 @@
package im.angry.openeuicc.di
import android.content.Context
import im.angry.openeuicc.common.R
open class DefaultCustomizableTextProvider(private val context: Context) : CustomizableTextProvider {
override val noEuiccExplanation: String
get() = context.getString(R.string.no_euicc)
override val profileSwitchingTimeoutMessage: String
get() = context.getString(R.string.enable_disable_timeout)
override fun formatInternalChannelName(logicalSlotId: Int): String =
context.getString(R.string.channel_name_format, logicalSlotId)
}

View file

@ -1,18 +1,13 @@
package im.angry.openeuicc.ui
import android.annotation.SuppressLint
import android.content.ClipData
import android.content.ClipboardManager
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.annotation.StringRes
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
@ -37,13 +32,6 @@ class EuiccInfoActivity : BaseEuiccAccessActivity() {
private var logicalSlotId: Int = -1
data class Item(
@StringRes
val titleResId: Int,
val content: String?,
val copiedToastResId: Int? = null
)
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
@ -53,11 +41,12 @@ class EuiccInfoActivity : BaseEuiccAccessActivity() {
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
swipeRefresh = requireViewById(R.id.swipe_refresh)
infoList = requireViewById<RecyclerView>(R.id.recycler_view).also {
it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
it.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
it.adapter = EuiccInfoAdapter()
}
infoList = requireViewById(R.id.recycler_view)
infoList.layoutManager =
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
infoList.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
infoList.adapter = EuiccInfoAdapter()
logicalSlotId = intent.getIntExtra("logicalSlotId", 0)
@ -92,33 +81,29 @@ class EuiccInfoActivity : BaseEuiccAccessActivity() {
lifecycleScope.launch {
(infoList.adapter!! as EuiccInfoAdapter).euiccInfoItems =
euiccChannelManager.withEuiccChannel(logicalSlotId, ::buildEuiccInfoItems)
euiccChannelManager.withEuiccChannel(logicalSlotId, ::buildPairs).map {
Pair(getString(it.first), it.second ?: getString(R.string.unknown))
}
swipeRefresh.isRefreshing = false
}
}
private fun buildEuiccInfoItems(channel: EuiccChannel) = buildList {
add(Item(R.string.euicc_info_access_mode, channel.type))
private fun buildPairs(channel: EuiccChannel) = buildList {
add(Pair(R.string.euicc_info_access_mode, channel.type))
add(
Item(
Pair(
R.string.euicc_info_removable,
formatByBoolean(channel.port.card.isRemovable, YES_NO)
)
)
add(
Item(
R.string.euicc_info_eid,
channel.lpa.eID,
copiedToastResId = R.string.toast_eid_copied
)
)
add(Pair(R.string.euicc_info_eid, channel.lpa.eID))
channel.lpa.euiccInfo2.let { info ->
add(Item(R.string.euicc_info_firmware_version, info?.euiccFirmwareVersion))
add(Item(R.string.euicc_info_globalplatform_version, info?.globalPlatformVersion))
add(Item(R.string.euicc_info_pp_version, info?.ppVersion))
add(Item(R.string.euicc_info_sas_accreditation_number, info?.sasAccreditationNumber))
add(Item(R.string.euicc_info_free_nvram, info?.freeNvram?.let(::formatFreeSpace)))
add(Pair(R.string.euicc_info_firmware_version, info?.euiccFirmwareVersion))
add(Pair(R.string.euicc_info_globalplatform_version, info?.globalPlatformVersion))
add(Pair(R.string.euicc_info_pp_version, info?.ppVersion))
add(Pair(R.string.euicc_info_sas_accreditation_number, info?.sasAccreditationNumber))
add(Pair(R.string.euicc_info_free_nvram, info?.freeNvram?.let(::formatFreeSpace)))
}
channel.lpa.euiccInfo2?.euiccCiPKIdListForSigning.orEmpty().let { signers ->
// SGP.28 v1.0, eSIM CI Registration Criteria (Page 5 of 9, 2019-10-24)
@ -131,7 +116,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity() {
PKID_GSMA_TEST_CI.any(signers::contains) -> R.string.euicc_info_ci_gsma_test
else -> R.string.euicc_info_ci_unknown
}
add(Item(R.string.euicc_info_ci_type, getString(resId)))
add(Pair(R.string.euicc_info_ci_type, getString(resId)))
}
}
@ -147,34 +132,15 @@ class EuiccInfoActivity : BaseEuiccAccessActivity() {
inner class EuiccInfoViewHolder(root: View) : ViewHolder(root) {
private val title: TextView = root.requireViewById(R.id.euicc_info_title)
private val content: TextView = root.requireViewById(R.id.euicc_info_content)
private var copiedToastResId: Int? = null
init {
root.setOnClickListener {
if (copiedToastResId != null) {
val label = title.text.toString()
getSystemService(ClipboardManager::class.java)!!
.setPrimaryClip(ClipData.newPlainText(label, content.text))
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
Toast.makeText(
this@EuiccInfoActivity,
copiedToastResId!!,
Toast.LENGTH_SHORT
).show()
}
}
}
}
fun bind(item: Item) {
copiedToastResId = item.copiedToastResId
title.setText(item.titleResId)
content.text = item.content ?: getString(R.string.unknown)
fun bind(item: Pair<String, String>) {
title.text = item.first
content.text = item.second
}
}
inner class EuiccInfoAdapter : RecyclerView.Adapter<EuiccInfoViewHolder>() {
var euiccInfoItems: List<Item> = listOf()
var euiccInfoItems: List<Pair<String, String>> = listOf()
@SuppressLint("NotifyDataSetChanged")
set(newVal) {
field = newVal

View file

@ -262,7 +262,7 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
invalid = true
// Timed out waiting for SIM to come back online, we can no longer assume that the LPA is still valid
AlertDialog.Builder(requireContext()).apply {
setMessage(appContainer.customizableTextProvider.profileSwitchingTimeoutMessage)
setMessage(R.string.enable_disable_timeout)
setPositiveButton(android.R.string.ok) { dialog, _ ->
dialog.dismiss()
requireActivity().finish()

View file

@ -8,6 +8,7 @@ import android.view.View
import android.widget.ScrollView
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
@ -16,6 +17,7 @@ import im.angry.openeuicc.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.FileOutputStream
import java.util.Date
class LogsActivity : AppCompatActivity() {
@ -25,15 +27,15 @@ class LogsActivity : AppCompatActivity() {
private lateinit var logStr: String
private val saveLogs =
setupLogSaving(
getLogFileName = {
getString(
R.string.logs_filename_template,
SimpleDateFormat.getDateTimeInstance().format(Date())
)
},
getLogText = { logStr }
)
registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri ->
if (uri == null) return@registerForActivityResult
if (!this::logStr.isInitialized) return@registerForActivityResult
contentResolver.openFileDescriptor(uri, "w")?.use {
FileOutputStream(it.fileDescriptor).use { os ->
os.write(logStr.encodeToByteArray())
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
@ -74,7 +76,9 @@ class LogsActivity : AppCompatActivity() {
true
}
R.id.save -> {
saveLogs()
saveLogs.launch(getString(R.string.logs_filename_template,
SimpleDateFormat.getDateTimeInstance().format(Date())
))
true
}
else -> super.onOptionsItemSelected(item)

View file

@ -163,8 +163,7 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
// but it could change in the future
euiccChannelManager.notifyEuiccProfilesChanged(channel.logicalSlotId)
val channelName =
appContainer.customizableTextProvider.formatInternalChannelName(channel.logicalSlotId)
val channelName = getString(R.string.channel_name_format, channel.logicalSlotId)
newPages.add(Page(channel.logicalSlotId, channelName) {
appContainer.uiComponentFactory.createEuiccManagementFragment(slotId, portId)
})

View file

@ -4,20 +4,15 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import im.angry.openeuicc.common.R
import im.angry.openeuicc.util.*
class NoEuiccPlaceholderFragment : Fragment(), OpenEuiccContextMarker {
class NoEuiccPlaceholderFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_no_euicc_placeholder, container, false)
val textView = view.requireViewById<TextView>(R.id.no_euicc_placeholder)
textView.text = appContainer.customizableTextProvider.noEuiccExplanation
return view
return inflater.inflate(R.layout.fragment_no_euicc_placeholder, container, false)
}
}

View file

@ -0,0 +1,93 @@
package im.angry.openeuicc.ui
import android.content.DialogInterface
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Spinner
import androidx.appcompat.widget.Toolbar
import im.angry.openeuicc.common.R
import im.angry.openeuicc.core.EuiccChannel
import im.angry.openeuicc.util.*
class SlotSelectFragment : BaseMaterialDialogFragment(), OpenEuiccContextMarker {
companion object {
const val TAG = "SlotSelectFragment"
fun newInstance(slotIds: List<Int>, logicalSlotIds: List<Int>, portIds: List<Int>): SlotSelectFragment {
return SlotSelectFragment().apply {
arguments = Bundle().apply {
putIntArray("slotIds", slotIds.toIntArray())
putIntArray("logicalSlotIds", logicalSlotIds.toIntArray())
putIntArray("portIds", portIds.toIntArray())
}
}
}
}
interface SlotSelectedListener {
fun onSlotSelected(slotId: Int, portId: Int)
fun onSlotSelectCancelled()
}
private lateinit var toolbar: Toolbar
private lateinit var spinner: Spinner
private lateinit var adapter: ArrayAdapter<String>
private lateinit var slotIds: IntArray
private lateinit var logicalSlotIds: IntArray
private lateinit var portIds: IntArray
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_slot_select, container, false)
toolbar = view.requireViewById(R.id.toolbar)
toolbar.setTitle(R.string.slot_select)
toolbar.inflateMenu(R.menu.fragment_slot_select)
adapter = ArrayAdapter<String>(inflater.context, R.layout.spinner_item)
spinner = view.requireViewById(R.id.spinner)
spinner.adapter = adapter
return view
}
override fun onStart() {
super.onStart()
slotIds = requireArguments().getIntArray("slotIds")!!
logicalSlotIds = requireArguments().getIntArray("logicalSlotIds")!!
portIds = requireArguments().getIntArray("portIds")!!
logicalSlotIds.forEach { id ->
adapter.add(getString(R.string.channel_name_format, id))
}
toolbar.setNavigationOnClickListener {
(requireActivity() as SlotSelectedListener).onSlotSelectCancelled()
}
toolbar.setOnMenuItemClickListener {
val slotId = slotIds[spinner.selectedItemPosition]
val portId = portIds[spinner.selectedItemPosition]
(requireActivity() as SlotSelectedListener).onSlotSelected(slotId, portId)
dismiss()
true
}
}
override fun onResume() {
super.onResume()
setWidthPercent(75)
}
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
(requireActivity() as SlotSelectedListener).onSlotSelectCancelled()
}
}

View file

@ -6,8 +6,10 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import im.angry.openeuicc.common.R
import im.angry.openeuicc.util.*
import java.io.FileOutputStream
import java.util.Date
class DownloadWizardDiagnosticsFragment : DownloadWizardActivity.DownloadWizardStepFragment() {
@ -19,15 +21,14 @@ class DownloadWizardDiagnosticsFragment : DownloadWizardActivity.DownloadWizardS
private lateinit var diagnosticTextView: TextView
private val saveDiagnostics =
setupLogSaving(
getLogFileName = {
getString(
R.string.download_wizard_diagnostics_file_template,
SimpleDateFormat.getDateTimeInstance().format(Date())
)
},
getLogText = { diagnosticTextView.text.toString() }
)
registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri ->
if (uri == null) return@registerForActivityResult
requireActivity().contentResolver.openFileDescriptor(uri, "w")?.use {
FileOutputStream(it.fileDescriptor).use { os ->
os.write(diagnosticTextView.text.toString().encodeToByteArray())
}
}
}
override fun createNextFragment(): DownloadWizardActivity.DownloadWizardStepFragment? = null
@ -40,7 +41,12 @@ class DownloadWizardDiagnosticsFragment : DownloadWizardActivity.DownloadWizardS
): View? {
val view = inflater.inflate(R.layout.fragment_download_diagnostics, container, false)
view.requireViewById<View>(R.id.download_wizard_diagnostics_save).setOnClickListener {
saveDiagnostics()
saveDiagnostics.launch(
getString(
R.string.download_wizard_diagnostics_file_template,
SimpleDateFormat.getDateTimeInstance().format(Date())
)
)
}
diagnosticTextView = view.requireViewById(R.id.download_wizard_diagnostics_text)
return view

View file

@ -35,8 +35,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt
val eID: String,
val freeSpace: Int,
val imei: String,
val enabledProfileName: String?,
val intrinsicChannelName: String?,
val enabledProfileName: String?
)
private var loaded = false
@ -107,8 +106,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt
} catch (e: Exception) {
""
},
channel.lpa.profiles.find { it.state == LocalProfileInfo.State.Enabled }?.displayName,
channel.intrinsicChannelName,
channel.lpa.profiles.find { it.state == LocalProfileInfo.State.Enabled }?.displayName
)
}
}.toList().sortedBy { it.logicalSlotId }
@ -179,9 +177,9 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt
}
title.text = if (item.logicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
item.intrinsicChannelName ?: root.context.getString(R.string.usb)
root.context.getString(R.string.usb)
} else {
appContainer.customizableTextProvider.formatInternalChannelName(item.logicalSlotId)
root.context.getString(R.string.download_wizard_slot_title, item.logicalSlotId)
}
eID.text = item.eID
activeProfile.text = item.enabledProfileName ?: root.context.getString(R.string.unknown)

View file

@ -1,23 +1,17 @@
package im.angry.openeuicc.util
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.graphics.Rect
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.ActivityResultCaller
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import im.angry.openeuicc.common.R
import java.io.FileOutputStream
// Source: <https://stackoverflow.com/questions/12478520/how-to-set-dialogfragments-width-and-height>
/**
@ -75,44 +69,4 @@ fun setupRootViewInsets(view: ViewGroup) {
WindowInsetsCompat.CONSUMED
}
}
fun <T : ActivityResultCaller> T.setupLogSaving(
getLogFileName: () -> String,
getLogText: () -> String
): () -> Unit {
val launchSaveIntent =
registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri ->
if (uri == null) return@registerForActivityResult
val context = when (this@setupLogSaving) {
is Context -> this@setupLogSaving
is Fragment -> requireContext()
else -> throw IllegalArgumentException("Must be either Context or Fragment!")
}
context.contentResolver.openFileDescriptor(uri, "w")?.use {
FileOutputStream(it.fileDescriptor).use { os ->
os.write(getLogText().encodeToByteArray())
}
}
AlertDialog.Builder(context).apply {
setMessage(R.string.logs_saved_message)
setNegativeButton(R.string.no) { _, _ -> }
setPositiveButton(R.string.yes) { _, _ ->
val intent = Intent().apply {
action = Intent.ACTION_SEND
type = "text/plain"
putExtra(Intent.EXTRA_STREAM, uri)
}
context.startActivity(Intent.createChooser(intent, null))
}
}.show()
}
return {
launchSaveIntent.launch(getLogFileName())
}
}

View file

@ -43,6 +43,7 @@
<string name="download_wizard_back">戻る</string>
<string name="download_wizard_next">次へ</string>
<string name="download_wizard_slot_select">ダウンロードする eSIM を選択または確認:</string>
<string name="download_wizard_slot_title">論理スロット %d</string>
<string name="download_wizard_slot_type">タイプ:</string>
<string name="download_wizard_slot_type_removable">リムーバブル</string>
<string name="download_wizard_slot_type_internal">内部</string>

View file

@ -81,6 +81,7 @@
<string name="download_wizard_back">返回</string>
<string name="download_wizard_next">下一步</string>
<string name="download_wizard_slot_select">请选择或确认下载目标 eSIM 卡槽:</string>
<string name="download_wizard_slot_title">逻辑卡槽 %d</string>
<string name="download_wizard_slot_type">类型:</string>
<string name="download_wizard_slot_type_removable">可插拔</string>
<string name="download_wizard_slot_type_internal">内置</string>

View file

@ -31,7 +31,6 @@
<string name="toast_profile_name_too_long">Nickname cannot be longer than 64 characters</string>
<string name="toast_profile_delete_confirm_text_mismatched">Confirmation string mismatch</string>
<string name="toast_iccid_copied">ICCID copied to clipboard</string>
<string name="toast_eid_copied">EID copied to clipboard</string>
<string name="slot_select">Select Slot</string>
<string name="slot_select_select">Select</string>
@ -65,6 +64,7 @@
<string name="download_wizard_back">Back</string>
<string name="download_wizard_next">Next</string>
<string name="download_wizard_slot_select">Select or confirm the eSIM you would like to download to:</string>
<string name="download_wizard_slot_title">Logical slot %d</string>
<string name="download_wizard_slot_type">Type:</string>
<string name="download_wizard_slot_type_removable">Removable</string>
<string name="download_wizard_slot_type_internal">Internal</string>
@ -95,8 +95,6 @@
<string name="download_wizard_diagnostics_save">Save</string>
<string name="download_wizard_diagnostics_file_template">Diagnostics at %s</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>
<string name="profile_rename_new_name">New nickname</string>
<string name="profile_delete_confirm">Are you sure you want to delete the profile %s? This operation is irreversible.</string>

View file

@ -6,8 +6,4 @@ class UnprivilegedAppContainer(context: Context) : DefaultAppContainer(context)
override val uiComponentFactory by lazy {
UnprivilegedUiComponentFactory()
}
override val customizableTextProvider by lazy {
UnprivilegedCustomizableTextProvider(context)
}
}

View file

@ -1,10 +0,0 @@
package im.angry.openeuicc.di
import android.content.Context
import im.angry.easyeuicc.R
class UnprivilegedCustomizableTextProvider(private val context: Context) :
DefaultCustomizableTextProvider(context) {
override fun formatInternalChannelName(logicalSlotId: Int): String =
context.getString(R.string.channel_name_format_unpriv, logicalSlotId)
}

View file

@ -1,6 +1,6 @@
<resources>
<string name="app_name" translatable="false">EasyEUICC</string>
<string name="channel_name_format_unpriv" translatable="false">SIM %d</string>
<string name="channel_name_format" translatable="false">SIM %d</string>
<string name="compatibility_check">Compatibility Check</string>
<string name="open_sim_toolkit">Open SIM Toolkit</string>

View file

@ -30,7 +30,6 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto
return EuiccChannelImpl(
context.getString(R.string.telephony_manager),
port,
intrinsicChannelName = null,
TelephonyManagerApduInterface(
port,
tm,

View file

@ -23,8 +23,4 @@ class PrivilegedAppContainer(context: Context) : DefaultAppContainer(context) {
override val euiccChannelFactory by lazy {
PrivilegedEuiccChannelFactory(context)
}
override val customizableTextProvider by lazy {
PrivilegedCustomizableTextProvider(context)
}
}

View file

@ -1,10 +0,0 @@
package im.angry.openeuicc.di
import android.content.Context
import im.angry.openeuicc.R
class PrivilegedCustomizableTextProvider(private val context: Context) :
DefaultCustomizableTextProvider(context) {
override val noEuiccExplanation: String
get() = context.getString(R.string.no_euicc_priv)
}

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="no_euicc_priv">このデバイスで eUICC が見つかりません。\nデバイスによってはアプリのメニューからデュアル SIM を有効化する必要があります。</string>
<string name="no_euicc">このデバイスで eUICC が見つかりません。\nデバイスによってはアプリのメニューからデュアル SIM を有効化する必要があります。</string>
<string name="telephony_manager">TelephonyManager (特権)</string>
<string name="dsds">デュアル SIM</string>
<string name="toast_dsds_switched">DSDS の状態が切り替わりました。モデムが再起動するまでお待ちください。</string>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="no_euicc_priv">在此设备上找不到 eUICC 芯片。\n在某些设备上您可能需要先在此应用的菜单中启用双卡支持。</string>
<string name="no_euicc">在此设备上找不到 eUICC 芯片。\n在某些设备上您可能需要先在此应用的菜单中启用双卡支持。</string>
<string name="dsds">双卡</string>
<string name="toast_dsds_switched">双卡支持状态已切换。请等待基带重新启动。</string>
<string name="footer_mep">此卡槽支持多个启用配置文件 (MEP)。要启用或禁用此功能,请使用\"卡槽映射\"工具。</string>

View file

@ -1,6 +1,6 @@
<resources>
<string name="app_name" translatable="false">OpenEUICC</string>
<string name="no_euicc_priv">No eUICC found on this device.\nOn some devices, you may need to enable dual SIM first in the menu of this app.</string>
<string name="no_euicc">No eUICC found on this device.\nOn some devices, you may need to enable dual SIM first in the menu of this app.</string>
<string name="telephony_manager">TelephonyManager (Privileged)</string>
<string name="dsds">Dual SIM</string>