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
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
@ -32,6 +37,13 @@ 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)
@ -41,12 +53,11 @@ class EuiccInfoActivity : BaseEuiccAccessActivity() {
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
swipeRefresh = requireViewById(R.id.swipe_refresh)
infoList = requireViewById(R.id.recycler_view)
infoList.layoutManager =
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
infoList.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
infoList.adapter = EuiccInfoAdapter()
infoList = requireViewById<RecyclerView>(R.id.recycler_view).also {
it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
it.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
it.adapter = EuiccInfoAdapter()
}
logicalSlotId = intent.getIntExtra("logicalSlotId", 0)
@ -81,29 +92,33 @@ class EuiccInfoActivity : BaseEuiccAccessActivity() {
lifecycleScope.launch {
(infoList.adapter!! as EuiccInfoAdapter).euiccInfoItems =
euiccChannelManager.withEuiccChannel(logicalSlotId, ::buildPairs).map {
Pair(getString(it.first), it.second ?: getString(R.string.unknown))
}
euiccChannelManager.withEuiccChannel(logicalSlotId, ::buildEuiccInfoItems)
swipeRefresh.isRefreshing = false
}
}
private fun buildPairs(channel: EuiccChannel) = buildList {
add(Pair(R.string.euicc_info_access_mode, channel.type))
private fun buildEuiccInfoItems(channel: EuiccChannel) = buildList {
add(Item(R.string.euicc_info_access_mode, channel.type))
add(
Pair(
Item(
R.string.euicc_info_removable,
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 ->
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)))
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)))
}
channel.lpa.euiccInfo2?.euiccCiPKIdListForSigning.orEmpty().let { signers ->
// 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
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 content: TextView = root.requireViewById(R.id.euicc_info_content)
private var copiedToastResId: Int? = null
fun bind(item: Pair<String, String>) {
title.text = item.first
content.text = item.second
fun bind(item: Item) {
copiedToastResId = item.copiedToastResId
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>() {
var euiccInfoItems: List<Pair<String, String>> = listOf()
var euiccInfoItems: List<Item> = listOf()
@SuppressLint("NotifyDataSetChanged")
set(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_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>