Compare commits

...

2 commits

Author SHA1 Message Date
52fd037026
feat: supports for google euicc partner customization 2025-07-17 18:46:26 +08:00
6d43a9207c chore: simplify pretty print json string (#201)
https://developer.android.com/reference/org/json/JSONObject
Reviewed-on: PeterCxy/OpenEUICC#201
Co-authored-by: septs <github@septs.pw>
Co-committed-by: septs <github@septs.pw>
2025-07-16 14:24:05 +02:00
5 changed files with 70 additions and 71 deletions

View file

@ -8,6 +8,7 @@ import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import im.angry.openeuicc.common.R import im.angry.openeuicc.common.R
import im.angry.openeuicc.util.* import im.angry.openeuicc.util.*
import org.json.JSONObject
import java.util.Date import java.util.Date
class DownloadWizardDiagnosticsFragment : DownloadWizardActivity.DownloadWizardStepFragment() { class DownloadWizardDiagnosticsFragment : DownloadWizardActivity.DownloadWizardStepFragment() {
@ -86,9 +87,10 @@ class DownloadWizardDiagnosticsFragment : DownloadWizardActivity.DownloadWizardS
ret.appendLine() ret.appendLine()
val str = resp.data.decodeToString(throwOnInvalidSequence = false) val str = resp.data.decodeToString(throwOnInvalidSequence = false)
ret.appendLine( ret.appendLine(
if (str.startsWith('{')) { if (str.startsWith('{')) {
str.prettyPrintJson() JSONObject(str).toString(2)
} else { } else {
str str
} }

View file

@ -41,73 +41,3 @@ fun parseIsdrAidList(s: String): List<ByteArray> =
.filter(String::isNotEmpty) .filter(String::isNotEmpty)
.mapNotNull { runCatching(it::decodeHex).getOrNull() } .mapNotNull { runCatching(it::decodeHex).getOrNull() }
.ifEmpty { listOf(EUICC_DEFAULT_ISDR_AID.decodeHex()) } .ifEmpty { listOf(EUICC_DEFAULT_ISDR_AID.decodeHex()) }
fun String.prettyPrintJson(): String {
val ret = StringBuilder()
var inQuotes = false
var escaped = false
val indentSymbolStack = ArrayDeque<Char>()
val addNewLine = {
ret.append('\n')
repeat(indentSymbolStack.size) {
ret.append('\t')
}
}
var lastChar = ' '
for (c in this) {
when {
!inQuotes && (c == '{' || c == '[') -> {
ret.append(c)
indentSymbolStack.addLast(c)
addNewLine()
}
!inQuotes && (c == '}' || c == ']') -> {
indentSymbolStack.removeLast()
if (lastChar != ',') {
addNewLine()
}
ret.append(c)
}
!inQuotes && c == ',' -> {
ret.append(c)
addNewLine()
}
!inQuotes && c == ':' -> {
ret.append(c)
ret.append(' ')
}
inQuotes && c == '\\' -> {
ret.append(c)
escaped = true
continue
}
!escaped && c == '"' -> {
ret.append(c)
inQuotes = !inQuotes
}
!inQuotes && c == ' ' -> {
// Do nothing -- we ignore spaces outside of quotes by default
// This is to ensure predictable formatting
}
else -> ret.append(c)
}
if (escaped) {
escaped = false
}
lastChar = c
}
return ret.toString()
}

View file

@ -63,4 +63,9 @@
</service> </service>
</application> </application>
<queries>
<intent>
<action android:name="com.google.android.euicc.action.PARTNER_CUSTOMIZATION" />
</intent>
</queries>
</manifest> </manifest>

View file

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import android.telephony.UiccSlotMapping import android.telephony.UiccSlotMapping
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
@ -45,6 +46,10 @@ class SlotMappingFragment: BaseMaterialDialogFragment(),
private lateinit var adapter: SlotMappingAdapter private lateinit var adapter: SlotMappingAdapter
private lateinit var helpTextView: TextView private lateinit var helpTextView: TextView
private val partner: Partner? by lazy {
Partner.getInstance(requireContext())
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -67,6 +72,12 @@ class SlotMappingFragment: BaseMaterialDialogFragment(),
toolbar.setOnMenuItemClickListener(this) 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() { override fun onResume() {
super.onResume() super.onResume()
setWidthPercent(85) setWidthPercent(85)

View file

@ -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<String, Partner?>()
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)
}