feat: copyable eid string #107

Closed
septs wants to merge 12 commits from septs:copyable-eid-string into master
2 changed files with 52 additions and 24 deletions

View file

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

View file

@ -31,6 +31,7 @@
<string name="toast_profile_name_too_long">Nickname cannot be longer than 64 characters</string> <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_profile_delete_confirm_text_mismatched">Confirmation string mismatch</string>
<string name="toast_iccid_copied">ICCID copied to clipboard</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 Slot</string>
<string name="slot_select_select">Select</string> <string name="slot_select_select">Select</string>