forked from PeterCxy/OpenEUICC
Compare commits
2 commits
83c4a7edfd
...
0fac24902f
Author | SHA1 | Date | |
---|---|---|---|
0fac24902f | |||
74cc08ce8e |
22 changed files with 384 additions and 167 deletions
|
@ -1,9 +1,11 @@
|
|||
package im.angry.openeuicc.core
|
||||
|
||||
import net.typeblog.lpac_jni.EuiccConfiguredAddresses
|
||||
import net.typeblog.lpac_jni.EuiccInfo2
|
||||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||
import net.typeblog.lpac_jni.LocalProfileInfo
|
||||
import net.typeblog.lpac_jni.LocalProfileNotification
|
||||
import net.typeblog.lpac_jni.ProfileDiscoveryCallback
|
||||
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
||||
|
||||
class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
|
||||
|
@ -32,6 +34,9 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
|
|||
|
||||
override fun setEs10xMss(mss: Byte) = lpa.setEs10xMss(mss)
|
||||
|
||||
override fun getEuiccConfiguredAddresses(): EuiccConfiguredAddresses =
|
||||
lpa.getEuiccConfiguredAddresses()
|
||||
|
||||
override fun enableProfile(iccid: String, refresh: Boolean): Boolean =
|
||||
lpa.enableProfile(iccid, refresh)
|
||||
|
||||
|
@ -48,6 +53,9 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
|
|||
callback: ProfileDownloadCallback
|
||||
) = lpa.downloadProfile(smdp, matchingId, imei, confirmationCode, callback)
|
||||
|
||||
override fun discoveryProfile(smds: String, imei: String?, callback: ProfileDiscoveryCallback) =
|
||||
lpa.discoveryProfile(smds, imei, callback)
|
||||
|
||||
override fun deleteNotification(seqNumber: Long): Boolean = lpa.deleteNotification(seqNumber)
|
||||
|
||||
override fun handleNotification(seqNumber: Long): Boolean = lpa.handleNotification(seqNumber)
|
||||
|
|
|
@ -21,6 +21,7 @@ import im.angry.openeuicc.ui.BaseEuiccAccessActivity
|
|||
import im.angry.openeuicc.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||
|
||||
class DownloadWizardActivity: BaseEuiccAccessActivity() {
|
||||
|
@ -28,6 +29,7 @@ class DownloadWizardActivity: BaseEuiccAccessActivity() {
|
|||
var currentStepFragmentClassName: String?,
|
||||
var selectedLogicalSlot: Int,
|
||||
var smdp: String,
|
||||
var smds: String?,
|
||||
var matchingId: String?,
|
||||
var confirmationCode: String?,
|
||||
var imei: String?,
|
||||
|
@ -67,6 +69,7 @@ class DownloadWizardActivity: BaseEuiccAccessActivity() {
|
|||
currentStepFragmentClassName = null,
|
||||
selectedLogicalSlot = intent.getIntExtra("selectedLogicalSlot", 0),
|
||||
smdp = "",
|
||||
smds = null,
|
||||
matchingId = null,
|
||||
confirmationCode = null,
|
||||
imei = null,
|
||||
|
|
|
@ -2,8 +2,10 @@ package im.angry.openeuicc.ui.wizard
|
|||
|
||||
import android.app.AlertDialog
|
||||
import android.content.ClipboardManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -11,6 +13,8 @@ import android.widget.ImageView
|
|||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
|
@ -25,18 +29,15 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withContext
|
||||
|
||||
class DownloadWizardMethodSelectFragment : DownloadWizardActivity.DownloadWizardStepFragment() {
|
||||
data class DownloadMethod(
|
||||
val iconRes: Int,
|
||||
val titleRes: Int,
|
||||
val onClick: () -> Unit
|
||||
)
|
||||
companion object {
|
||||
const val TAG = "DownloadWizardMethodSelectFragment"
|
||||
}
|
||||
|
||||
// TODO: Maybe we should find a better barcode scanner (or an external one?)
|
||||
private val barcodeScannerLauncher = registerForActivityResult(ScanContract()) { result ->
|
||||
result.contents?.let { content ->
|
||||
processLpaString(content)
|
||||
private val barcodeScannerLauncher =
|
||||
registerForActivityResult(ScanContract()) {
|
||||
it.contents?.let(::processLPAString)
|
||||
}
|
||||
}
|
||||
|
||||
private val gallerySelectorLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.GetContent()) { result ->
|
||||
|
@ -51,30 +52,36 @@ class DownloadWizardMethodSelectFragment : DownloadWizardActivity.DownloadWizard
|
|||
}
|
||||
}
|
||||
|
||||
decoded.getOrNull()?.let { processLpaString(it) }
|
||||
decoded.getOrNull()?.let { processLPAString(it) }
|
||||
}
|
||||
}
|
||||
|
||||
val downloadMethods = arrayOf(
|
||||
DownloadMethod(R.drawable.ic_scan_black, R.string.download_wizard_method_qr_code) {
|
||||
barcodeScannerLauncher.launch(ScanOptions().apply {
|
||||
setDesiredBarcodeFormats(ScanOptions.QR_CODE)
|
||||
setOrientationLocked(false)
|
||||
})
|
||||
},
|
||||
DownloadMethod(R.drawable.ic_gallery_black, R.string.download_wizard_method_gallery) {
|
||||
private fun getDownloadMethods() = buildList {
|
||||
add(DownloadMethod(R.drawable.ic_scan_black, R.string.download_wizard_method_qr_code) {
|
||||
val options = ScanOptions()
|
||||
.setDesiredBarcodeFormats(ScanOptions.QR_CODE)
|
||||
.setOrientationLocked(false)
|
||||
barcodeScannerLauncher.launch(options)
|
||||
})
|
||||
add(DownloadMethod(R.drawable.ic_gallery_black, R.string.download_wizard_method_gallery) {
|
||||
gallerySelectorLauncher.launch("image/*")
|
||||
},
|
||||
DownloadMethod(R.drawable.ic_paste_go, R.string.download_wizard_method_clipboard) {
|
||||
})
|
||||
add(DownloadMethod(R.drawable.ic_paste_go, R.string.download_wizard_method_clipboard) {
|
||||
handleLoadFromClipboard()
|
||||
},
|
||||
DownloadMethod(R.drawable.ic_edit, R.string.download_wizard_method_manual) {
|
||||
})
|
||||
if (state.smds != null) add(
|
||||
DownloadMethod(R.drawable.ic_search, R.string.download_wizard_method_discovery) {
|
||||
gotoNextFragment(DownloadWizardDetailsFragment())
|
||||
}
|
||||
)
|
||||
add(DownloadMethod(R.drawable.ic_edit, R.string.download_wizard_method_manual) {
|
||||
gotoNextFragment(DownloadWizardDetailsFragment())
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
override val hasNext: Boolean
|
||||
get() = false
|
||||
|
||||
override val hasPrev: Boolean
|
||||
get() = true
|
||||
|
||||
|
@ -88,38 +95,29 @@ class DownloadWizardMethodSelectFragment : DownloadWizardActivity.DownloadWizard
|
|||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val view = inflater.inflate(R.layout.fragment_download_method_select, container, false)
|
||||
val recyclerView = view.requireViewById<RecyclerView>(R.id.download_method_list)
|
||||
recyclerView.adapter = DownloadMethodAdapter()
|
||||
recyclerView.layoutManager =
|
||||
LinearLayoutManager(view.context, LinearLayoutManager.VERTICAL, false)
|
||||
recyclerView.addItemDecoration(
|
||||
DividerItemDecoration(
|
||||
requireContext(),
|
||||
LinearLayoutManager.VERTICAL
|
||||
)
|
||||
)
|
||||
return view
|
||||
}
|
||||
): View =
|
||||
inflater.inflate(R.layout.fragment_download_method_select, container, false).apply {
|
||||
requireViewById<RecyclerView>(R.id.download_method_list).apply {
|
||||
adapter = DownloadMethodAdapter(getDownloadMethods())
|
||||
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleLoadFromClipboard() {
|
||||
val clipboard = requireContext().getSystemService(ClipboardManager::class.java)
|
||||
val text = clipboard.primaryClip?.getItemAt(0)?.text
|
||||
|
||||
if (text == null) {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.profile_download_no_lpa_string,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
val resId = R.string.profile_download_no_lpa_string
|
||||
Toast.makeText(requireContext(), resId, Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
processLpaString(text.toString())
|
||||
processLPAString(text.toString())
|
||||
}
|
||||
|
||||
private fun processLpaString(input: String) {
|
||||
private fun processLPAString(input: String) {
|
||||
try {
|
||||
val parsed = LPAString.parse(input)
|
||||
state.smdp = parsed.address
|
||||
|
@ -136,38 +134,39 @@ class DownloadWizardMethodSelectFragment : DownloadWizardActivity.DownloadWizard
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class DownloadMethodViewHolder(private val root: View) : ViewHolder(root) {
|
||||
private val icon = root.requireViewById<ImageView>(R.id.download_method_icon)
|
||||
private val title = root.requireViewById<TextView>(R.id.download_method_title)
|
||||
private data class DownloadMethod(
|
||||
@DrawableRes
|
||||
val iconRes: Int,
|
||||
@StringRes
|
||||
val titleRes: Int,
|
||||
val disabled: Boolean = false,
|
||||
val onClick: () -> Unit
|
||||
)
|
||||
|
||||
fun bind(item: DownloadMethod) {
|
||||
icon.setImageResource(item.iconRes)
|
||||
title.setText(item.titleRes)
|
||||
root.setOnClickListener {
|
||||
// If the user elected to use another download method, reset the confirmation code flag
|
||||
// too
|
||||
state.confirmationCodeRequired = false
|
||||
item.onClick()
|
||||
}
|
||||
}
|
||||
private class DownloadMethodViewHolder(private val root: View) : ViewHolder(root) {
|
||||
private val icon: ImageView = root.requireViewById(R.id.download_method_icon)
|
||||
private val title: TextView = root.requireViewById(R.id.download_method_title)
|
||||
|
||||
fun bind(item: DownloadMethod) {
|
||||
icon.setImageResource(item.iconRes)
|
||||
title.setText(item.titleRes)
|
||||
root.setOnClickListener { item.onClick() }
|
||||
}
|
||||
}
|
||||
|
||||
private inner class DownloadMethodAdapter : RecyclerView.Adapter<DownloadMethodViewHolder>() {
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): DownloadMethodViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.download_method_item, parent, false)
|
||||
return DownloadMethodViewHolder(view)
|
||||
}
|
||||
private class DownloadMethodAdapter(private val methods: List<DownloadMethod>) :
|
||||
RecyclerView.Adapter<DownloadMethodViewHolder>() {
|
||||
|
||||
override fun getItemCount(): Int = downloadMethods.size
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.download_method_item, parent, false)
|
||||
.let { DownloadMethodViewHolder(it) }
|
||||
|
||||
override fun onBindViewHolder(holder: DownloadMethodViewHolder, position: Int) {
|
||||
holder.bind(downloadMethods[position])
|
||||
}
|
||||
override fun getItemCount(): Int = methods.size
|
||||
|
||||
override fun onBindViewHolder(holder: DownloadMethodViewHolder, position: Int) {
|
||||
holder.bind(methods[position])
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package im.angry.openeuicc.ui.wizard
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -19,7 +20,7 @@ import im.angry.openeuicc.util.*
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import net.typeblog.lpac_jni.LocalProfileInfo
|
||||
import net.typeblog.lpac_jni.EuiccConfiguredAddresses
|
||||
|
||||
class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardStepFragment() {
|
||||
companion object {
|
||||
|
@ -37,6 +38,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt
|
|||
val imei: String,
|
||||
val enabledProfileName: String?,
|
||||
val intrinsicChannelName: String?,
|
||||
val euiccConfiguredAddresses: EuiccConfiguredAddresses
|
||||
)
|
||||
|
||||
private var loaded = false
|
||||
|
@ -117,6 +119,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt
|
|||
},
|
||||
channel.lpa.profiles.enabled?.displayName,
|
||||
channel.intrinsicChannelName,
|
||||
channel.lpa.getEuiccConfiguredAddresses(),
|
||||
)
|
||||
}
|
||||
}.toList().sortedBy { it.logicalSlotId }
|
||||
|
@ -129,6 +132,7 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt
|
|||
} else {
|
||||
if (slots.isNotEmpty()) {
|
||||
state.selectedLogicalSlot = slots[0].logicalSlotId
|
||||
state.smds = slots[0].euiccConfiguredAddresses.rootDSAddress
|
||||
}
|
||||
0
|
||||
}
|
||||
|
@ -168,8 +172,11 @@ class DownloadWizardSlotSelectFragment : DownloadWizardActivity.DownloadWizardSt
|
|||
adapter.notifyItemChanged(lastIdx)
|
||||
adapter.notifyItemChanged(curIdx)
|
||||
// Selected index isn't logical slot ID directly, needs a conversion
|
||||
state.selectedLogicalSlot = adapter.slots[adapter.currentSelectedIdx].logicalSlotId
|
||||
state.imei = adapter.slots[adapter.currentSelectedIdx].imei
|
||||
adapter.slots[adapter.currentSelectedIdx].let {
|
||||
state.selectedLogicalSlot = it.logicalSlotId
|
||||
state.smds = it.euiccConfiguredAddresses.rootDSAddress
|
||||
state.imei = it.imei
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(item: SlotInfo, idx: Int) {
|
||||
|
|
|
@ -93,13 +93,12 @@ inline fun <T> Bitmap.use(f: (Bitmap) -> T): T =
|
|||
recycle()
|
||||
}
|
||||
|
||||
fun decodeQrFromBitmap(bmp: Bitmap): String? =
|
||||
runCatching {
|
||||
val pixels = IntArray(bmp.width * bmp.height)
|
||||
bmp.getPixels(pixels, 0, bmp.width, 0, 0, bmp.width, bmp.height)
|
||||
fun decodeQrFromBitmap(bmp: Bitmap): String? {
|
||||
val pixels = IntArray(bmp.width * bmp.height)
|
||||
bmp.getPixels(pixels, 0, bmp.width, 0, 0, bmp.width, bmp.height)
|
||||
|
||||
val luminanceSource = RGBLuminanceSource(bmp.width, bmp.height, pixels)
|
||||
val binaryBmp = BinaryBitmap(HybridBinarizer(luminanceSource))
|
||||
val luminanceSource = RGBLuminanceSource(bmp.width, bmp.height, pixels)
|
||||
val binaryBmp = BinaryBitmap(HybridBinarizer(luminanceSource))
|
||||
|
||||
QRCodeReader().decode(binaryBmp).text
|
||||
}.getOrNull()
|
||||
return QRCodeReader().decode(binaryBmp).text
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
|
||||
</vector>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M22,16L22,4c0,-1.1 -0.9,-2 -2,-2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zM11,12l2.03,2.71L16,11l4,5L8,16l3,-4zM2,6v14c0,1.1 0.9,2 2,2h14v-2L4,20L4,6L2,6z"/>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M22,16L22,4c0,-1.1 -0.9,-2 -2,-2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zM11,12l2.03,2.71L16,11l4,5L8,16l3,-4zM2,6v14c0,1.1 0.9,2 2,2h14v-2L4,20L4,6L2,6z" />
|
||||
</vector>
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="?attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M5,5h2v3h10V5h2v6h2V5c0,-1.1 -0.9,-2 -2,-2h-4.18C14.4,1.84 13.3,1 12,1S9.6,1.84 9.18,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h5v-2H5V5zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S11.45,3 12,3z"/>
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M18.01,13l-1.42,1.41l1.58,1.58l-6.17,0l0,2l6.17,0l-1.58,1.59l1.42,1.41l3.99,-4z"/>
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M5,5h2v3h10V5h2v6h2V5c0,-1.1 -0.9,-2 -2,-2h-4.18C14.4,1.84 13.3,1 12,1S9.6,1.84 9.18,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h5v-2H5V5zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S11.45,3 12,3z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M18.01,13l-1.42,1.41l1.58,1.58l-6.17,0l0,2l6.17,0l-1.58,1.59l1.42,1.41l3.99,-4z" />
|
||||
</vector>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M9.5,6.5v3h-3v-3H9.5M11,5H5v6h6V5L11,5zM9.5,14.5v3h-3v-3H9.5M11,13H5v6h6V13L11,13zM17.5,6.5v3h-3v-3H17.5M19,5h-6v6h6V5L19,5zM13,13h1.5v1.5H13V13zM14.5,14.5H16V16h-1.5V14.5zM16,13h1.5v1.5H16V13zM13,16h1.5v1.5H13V16zM14.5,17.5H16V19h-1.5V17.5zM16,16h1.5v1.5H16V16zM17.5,14.5H19V16h-1.5V14.5zM17.5,17.5H19V19h-1.5V17.5zM22,7h-2V4h-3V2h5V7zM22,22v-5h-2v3h-3v2H22zM2,22h5v-2H4v-3H2V22zM2,2v5h2V4h3V2H2z"/>
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M9.5,6.5v3h-3v-3H9.5M11,5H5v6h6V5L11,5zM9.5,14.5v3h-3v-3H9.5M11,13H5v6h6V13L11,13zM17.5,6.5v3h-3v-3H17.5M19,5h-6v6h6V5L19,5zM13,13h1.5v1.5H13V13zM14.5,14.5H16V16h-1.5V14.5zM16,13h1.5v1.5H16V13zM13,16h1.5v1.5H13V16zM14.5,17.5H16V19h-1.5V17.5zM16,16h1.5v1.5H16V16zM17.5,14.5H19V16h-1.5V14.5zM17.5,17.5H19V19h-1.5V17.5zM22,7h-2V4h-3V2h5V7zM22,22v-5h-2v3h-3v2H22zM2,22h5v-2H4v-3H2V22zM2,2v5h2V4h3V2H2z" />
|
||||
</vector>
|
||||
|
|
10
app-common/src/main/res/drawable/ic_search.xml
Normal file
10
app-common/src/main/res/drawable/ic_search.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="50"
|
||||
android:viewportHeight="50">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M21,3a17,17 0,1 0,10 31l13,13 3,-3 -13,-13c2,-3 4,-7 4,-11 0,-9 -8,-17 -17,-17ZM21,5a15,15 0,1 1,0 30,15 15,0 0,1 0,-30Z" />
|
||||
</vector>
|
|
@ -83,6 +83,7 @@
|
|||
<string name="download_wizard_method_gallery">Load a QR code from gallery</string>
|
||||
<string name="download_wizard_method_clipboard">Load from Clipboard</string>
|
||||
<string name="download_wizard_method_manual">Enter manually</string>
|
||||
<string name="download_wizard_method_discovery">Discovery</string>
|
||||
<string name="download_wizard_details">Input or confirm details for downloading your eSIM:</string>
|
||||
<string name="download_wizard_progress">Downloading your eSIM…</string>
|
||||
<string name="download_wizard_progress_step_preparing">Preparing</string>
|
||||
|
|
|
@ -71,7 +71,6 @@
|
|||
|
||||
<CheckBoxPreference
|
||||
app:iconSpaceReserved="false"
|
||||
app:isPreferenceVisible="false"
|
||||
app:key="pref_developer_euicc_memory_reset"
|
||||
app:summary="@string/pref_developer_euicc_memory_reset_desc"
|
||||
app:title="@string/pref_developer_euicc_memory_reset" />
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package net.typeblog.lpac_jni
|
||||
|
||||
class EuiccConfiguredAddresses(defaultDPAddress: String?, rootDSAddress: String?) {
|
||||
val defaultDPAddress: String? = defaultDPAddress
|
||||
.takeUnless { it.isNullOrBlank() }
|
||||
val rootDSAddress = rootDSAddress
|
||||
.takeIf(::isValidDPAddress)
|
||||
}
|
||||
|
||||
private fun isValidDPAddress(address: String?): Boolean {
|
||||
if (address.isNullOrBlank()) return false
|
||||
if (address.endsWith("gsma.com")) return false
|
||||
if (address.endsWith("example.com")) return false
|
||||
return true
|
||||
}
|
|
@ -12,6 +12,15 @@ interface LocalProfileAssistant {
|
|||
val lastApduException: Exception?,
|
||||
) : Exception("Failed to download profile")
|
||||
|
||||
@Suppress("ArrayInDataClass")
|
||||
data class ProfileDiscoveryException(
|
||||
val lpaErrorReason: String,
|
||||
val lastHttpResponse: HttpResponse?,
|
||||
val lastHttpException: Exception?,
|
||||
val lastApduResponse: ByteArray?,
|
||||
val lastApduException: Exception?,
|
||||
) : Exception("Failed to discovery profile")
|
||||
|
||||
class ProfileRenameException() : Exception("Failed to rename profile")
|
||||
class ProfileNameTooLongException() : Exception("Profile name too long")
|
||||
class ProfileNameIsInvalidUTF8Exception() : Exception("Profile name is invalid UTF-8")
|
||||
|
@ -30,6 +39,9 @@ interface LocalProfileAssistant {
|
|||
*/
|
||||
fun setEs10xMss(mss: Byte)
|
||||
|
||||
// es10a
|
||||
fun getEuiccConfiguredAddresses(): EuiccConfiguredAddresses
|
||||
|
||||
// All blocking functions in this class assume that they are executed on non-Main threads
|
||||
// The IO context in Kotlin's coroutine library is recommended.
|
||||
fun enableProfile(iccid: String, refresh: Boolean = true): Boolean
|
||||
|
@ -38,6 +50,7 @@ interface LocalProfileAssistant {
|
|||
|
||||
fun downloadProfile(smdp: String, matchingId: String?, imei: String?,
|
||||
confirmationCode: String?, callback: ProfileDownloadCallback)
|
||||
fun discoveryProfile(smds: String, imei: String?, callback: ProfileDiscoveryCallback)
|
||||
|
||||
fun deleteNotification(seqNumber: Long): Boolean
|
||||
fun handleNotification(seqNumber: Long): Boolean
|
||||
|
|
|
@ -29,6 +29,12 @@ internal object LpacJni {
|
|||
external fun es10bListNotification(handle: Long): Long // A native pointer to a linked list. Handle with linked list-related methods below. May be 0 (null)
|
||||
external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int
|
||||
|
||||
// es10a
|
||||
external fun es10aGetEuiccConfiguredAddresses(handle: Long): EuiccConfiguredAddresses
|
||||
|
||||
// es9p + es11
|
||||
external fun discoveryProfile(handle: Long, address: String, imei: String?, callback: ProfileDiscoveryCallback): Int
|
||||
|
||||
// es9p + es10b
|
||||
// We do not expose all of the functions because of tediousness :)
|
||||
external fun downloadProfile(handle: Long, smdp: String, matchingId: String?, imei: String?,
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package net.typeblog.lpac_jni
|
||||
|
||||
interface ProfileDiscoveryCallback {
|
||||
fun onDiscovered(hosts: Array<String>)
|
||||
}
|
|
@ -2,15 +2,14 @@ package net.typeblog.lpac_jni
|
|||
|
||||
interface ProfileDownloadCallback {
|
||||
companion object {
|
||||
fun lookupStateFromProgress(progress: Int): DownloadState =
|
||||
when (progress) {
|
||||
0 -> DownloadState.Preparing
|
||||
20 -> DownloadState.Connecting
|
||||
40 -> DownloadState.Authenticating
|
||||
60 -> DownloadState.Downloading
|
||||
80 -> DownloadState.Finalizing
|
||||
else -> throw IllegalArgumentException("Unknown state")
|
||||
}
|
||||
fun lookupStateFromProgress(progress: Int): DownloadState = when (progress) {
|
||||
0 -> DownloadState.Preparing
|
||||
20 -> DownloadState.Connecting
|
||||
40 -> DownloadState.Authenticating
|
||||
60 -> DownloadState.Downloading
|
||||
80 -> DownloadState.Finalizing
|
||||
else -> throw IllegalArgumentException("Unknown state")
|
||||
}
|
||||
}
|
||||
|
||||
enum class DownloadState(val progress: Int) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import net.typeblog.lpac_jni.HttpInterface.HttpResponse
|
|||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||
import net.typeblog.lpac_jni.LocalProfileInfo
|
||||
import net.typeblog.lpac_jni.LocalProfileNotification
|
||||
import net.typeblog.lpac_jni.ProfileDiscoveryCallback
|
||||
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
||||
import net.typeblog.lpac_jni.Version
|
||||
|
||||
|
@ -93,6 +94,9 @@ class LocalProfileAssistantImpl(
|
|||
LpacJni.euiccSetMss(contextHandle, mss)
|
||||
}
|
||||
|
||||
override fun getEuiccConfiguredAddresses() =
|
||||
LpacJni.es10aGetEuiccConfiguredAddresses(contextHandle)
|
||||
|
||||
override val valid: Boolean
|
||||
get() = !finalized && apduInterface.valid && try {
|
||||
// If we can read both eID and euiccInfo2 properly, we are likely looking at
|
||||
|
@ -212,21 +216,32 @@ class LocalProfileAssistantImpl(
|
|||
callback
|
||||
)
|
||||
|
||||
if (res != 0) {
|
||||
// Construct the error now to store any error information we _can_ access
|
||||
val err = LocalProfileAssistant.ProfileDownloadException(
|
||||
lpaErrorReason = LpacJni.downloadErrCodeToString(-res),
|
||||
httpInterface.lastHttpResponse,
|
||||
httpInterface.lastHttpException,
|
||||
apduInterface.lastApduResponse,
|
||||
apduInterface.lastApduException,
|
||||
)
|
||||
if (res == 0) return
|
||||
// Construct the error now to store any error information we _can_ access
|
||||
val err = LocalProfileAssistant.ProfileDownloadException(
|
||||
lpaErrorReason = LpacJni.downloadErrCodeToString(-res),
|
||||
httpInterface.lastHttpResponse,
|
||||
httpInterface.lastHttpException,
|
||||
apduInterface.lastApduResponse,
|
||||
apduInterface.lastApduException,
|
||||
)
|
||||
|
||||
// Cancel sessions if possible. This will overwrite recorded errors from HTTP and APDU interfaces.
|
||||
LpacJni.cancelSessions(contextHandle)
|
||||
// Cancel sessions if possible. This will overwrite recorded errors from HTTP and APDU interfaces.
|
||||
LpacJni.cancelSessions(contextHandle)
|
||||
|
||||
throw err
|
||||
}
|
||||
throw err
|
||||
}
|
||||
|
||||
override fun discoveryProfile(smds: String, imei: String?, callback: ProfileDiscoveryCallback) {
|
||||
val res = LpacJni.discoveryProfile(contextHandle, smds, imei, callback)
|
||||
if (res == 0) return
|
||||
throw LocalProfileAssistant.ProfileDiscoveryException(
|
||||
lpaErrorReason = LpacJni.downloadErrCodeToString(-res),
|
||||
httpInterface.lastHttpResponse,
|
||||
httpInterface.lastHttpException,
|
||||
apduInterface.lastApduResponse,
|
||||
apduInterface.lastApduException,
|
||||
)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
|
127
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.c
Normal file
127
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
#include "lpac-notifications.h"
|
||||
#include <euicc/es10a.h>
|
||||
#include <euicc/es10b.h>
|
||||
#include <euicc/es9p.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#define EUICC_CONFIGURED_ADDRESSES_CLASS "net/typeblog/lpac_jni/EuiccConfiguredAddresses"
|
||||
|
||||
jclass euicc_configured_addresses_class;
|
||||
jmethodID euicc_configured_addresses_constructor;
|
||||
|
||||
jmethodID on_discovered;
|
||||
|
||||
#define DISCOVERY_CALLBACK_CLASS "net/typeblog/lpac_jni/ProfileDiscoveryCallback"
|
||||
#define STRING_CLASS "java/lang/String"
|
||||
|
||||
static jobject bind_static_field(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
|
||||
jfieldID field = (*env)->GetStaticFieldID(env, clazz, name, sig);
|
||||
jobject bound = (*env)->GetStaticObjectField(env, clazz, field);
|
||||
return (*env)->NewGlobalRef(env, bound);
|
||||
}
|
||||
|
||||
void lpac_discovery_init() {
|
||||
LPAC_JNI_SETUP_ENV;
|
||||
|
||||
jclass download_callback_class = (*env)->FindClass(env, DISCOVERY_CALLBACK_CLASS);
|
||||
on_discovered = (*env)->GetMethodID(env, download_callback_class, "onDiscovered",
|
||||
"([L" STRING_CLASS ";)V");
|
||||
|
||||
euicc_configured_addresses_class = (*env)->FindClass(env, EUICC_CONFIGURED_ADDRESSES_CLASS);
|
||||
euicc_configured_addresses_class = (*env)->NewGlobalRef(env, euicc_configured_addresses_class);
|
||||
euicc_configured_addresses_constructor = (*env)->GetMethodID(
|
||||
env, euicc_configured_addresses_class, "<init>",
|
||||
"(L" STRING_CLASS ";L" STRING_CLASS ";)V");
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_net_typeblog_lpac_1jni_LpacJni_es10aGetEuiccConfiguredAddresses(
|
||||
JNIEnv *env,
|
||||
__attribute__((unused)) jobject thiz,
|
||||
jlong handle
|
||||
) {
|
||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||
struct es10a_euicc_configured_addresses addresses;
|
||||
jobject ret = NULL;
|
||||
if (es10a_get_euicc_configured_addresses(ctx, &addresses) == 0) {
|
||||
jstring default_dp_address = toJString(env, addresses.defaultDpAddress);
|
||||
jstring root_ds_address = toJString(env, addresses.rootDsAddress);
|
||||
ret = (*env)->NewObject(env, euicc_configured_addresses_class,
|
||||
euicc_configured_addresses_constructor,
|
||||
default_dp_address, root_ds_address);
|
||||
}
|
||||
es10a_euicc_configured_addresses_free(&addresses);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_net_typeblog_lpac_1jni_LpacJni_discoveryProfile(
|
||||
JNIEnv *env,
|
||||
__attribute__((unused)) jobject thiz,
|
||||
jlong handle,
|
||||
jstring address,
|
||||
jstring imei,
|
||||
jobject callback,
|
||||
) {
|
||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||
|
||||
const char *_address = (*env)->GetStringUTFChars(env, address, NULL);
|
||||
const char *_imei = NULL;
|
||||
|
||||
if (imei != NULL) {
|
||||
_imei = (*env)->GetStringUTFChars(env, address, NULL);
|
||||
}
|
||||
|
||||
ctx->http.server_address = _address;
|
||||
|
||||
char **smdp_list = NULL;
|
||||
jobjectArray addresses = NULL;
|
||||
int ret = -1;
|
||||
|
||||
ret = es10b_get_euicc_challenge_and_info(ctx);
|
||||
syslog(LOG_INFO, "es10b_get_euicc_challenge_and_info %d", ret);
|
||||
if (ret < 0) {
|
||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = es9p_initiate_authentication(ctx);
|
||||
syslog(LOG_INFO, "es9p_initiate_authentication %d", ret);
|
||||
if (ret < 0) {
|
||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = es10b_authenticate_server(ctx, NULL, _imei);
|
||||
syslog(LOG_INFO, "es10b_authenticate_server %d", ret);
|
||||
if (ret < 0) {
|
||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = es11_authenticate_client(ctx, &smdp_list);
|
||||
if (ret < 0) {
|
||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
jsize n = 0;
|
||||
for (n = 0; smdp_list[n] != NULL; n++) continue;
|
||||
|
||||
addresses = (*env)->NewObjectArray(env, n, string_class, NULL);
|
||||
|
||||
for (jsize index = 0; index < n; index++) {
|
||||
jstring element = toJString(env, smdp_list[index]);
|
||||
(*env)->SetObjectArrayElement(env, addresses, index, element);
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(env, callback, on_discovered, addresses);
|
||||
|
||||
out:
|
||||
if (_imei != NULL) (*env)->ReleaseStringUTFChars(env, imei, _imei);
|
||||
(*env)->ReleaseStringUTFChars(env, address, _address);
|
||||
es11_smdp_list_free_all(smdp_list);
|
||||
return ret;
|
||||
}
|
6
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.h
Normal file
6
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <jni.h>
|
||||
#include "lpac-jni.h"
|
||||
|
||||
void lpac_discovery_init();
|
|
@ -11,51 +11,38 @@ jobject download_state_authenticating;
|
|||
jobject download_state_downloading;
|
||||
jobject download_state_finalizing;
|
||||
|
||||
jmethodID on_state_update;
|
||||
jmethodID on_discovered;
|
||||
|
||||
#define DOWNLOAD_CALLBACK_CLASS "net/typeblog/lpac_jni/ProfileDownloadCallback"
|
||||
#define DOWNLOAD_STATE_CLASS DOWNLOAD_CALLBACK_CLASS "$DownloadState"
|
||||
|
||||
static jobject bind_static_field(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
|
||||
jfieldID field = (*env)->GetStaticFieldID(env, clazz, name, sig);
|
||||
jobject bound = (*env)->GetStaticObjectField(env, clazz, field);
|
||||
return (*env)->NewGlobalRef(env, bound);
|
||||
}
|
||||
|
||||
#define BIND_DOWNLOAD_STATE_STATIC_FIELD(NAME, FIELD) \
|
||||
NAME = bind_static_field(env, download_state_class, FIELD, "L" DOWNLOAD_STATE_CLASS ";")
|
||||
|
||||
void lpac_download_init() {
|
||||
LPAC_JNI_SETUP_ENV;
|
||||
|
||||
jclass download_state_class = (*env)->FindClass(env,
|
||||
"net/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState");
|
||||
jfieldID download_state_preparing_field = (*env)->GetStaticFieldID(env, download_state_class,
|
||||
"Preparing",
|
||||
"Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;");
|
||||
download_state_preparing = (*env)->GetStaticObjectField(env, download_state_class,
|
||||
download_state_preparing_field);
|
||||
download_state_preparing = (*env)->NewGlobalRef(env, download_state_preparing);
|
||||
jfieldID download_state_connecting_field = (*env)->GetStaticFieldID(env, download_state_class,
|
||||
"Connecting",
|
||||
"Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;");
|
||||
download_state_connecting = (*env)->GetStaticObjectField(env, download_state_class,
|
||||
download_state_connecting_field);
|
||||
download_state_connecting = (*env)->NewGlobalRef(env, download_state_connecting);
|
||||
jfieldID download_state_authenticating_field = (*env)->GetStaticFieldID(env,
|
||||
download_state_class,
|
||||
"Authenticating",
|
||||
"Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;");
|
||||
download_state_authenticating = (*env)->GetStaticObjectField(env, download_state_class,
|
||||
download_state_authenticating_field);
|
||||
download_state_authenticating = (*env)->NewGlobalRef(env, download_state_authenticating);
|
||||
jfieldID download_state_downloading_field = (*env)->GetStaticFieldID(env, download_state_class,
|
||||
"Downloading",
|
||||
"Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;");
|
||||
download_state_downloading = (*env)->GetStaticObjectField(env, download_state_class,
|
||||
download_state_downloading_field);
|
||||
download_state_downloading = (*env)->NewGlobalRef(env, download_state_downloading);
|
||||
jfieldID download_state_finalizng_field = (*env)->GetStaticFieldID(env, download_state_class,
|
||||
"Finalizing",
|
||||
"Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;");
|
||||
download_state_finalizing = (*env)->GetStaticObjectField(env, download_state_class,
|
||||
download_state_finalizng_field);
|
||||
download_state_finalizing = (*env)->NewGlobalRef(env, download_state_finalizing);
|
||||
jclass download_state_class = (*env)->FindClass(env, DOWNLOAD_STATE_CLASS);
|
||||
|
||||
jclass download_callback_class = (*env)->FindClass(env,
|
||||
"net/typeblog/lpac_jni/ProfileDownloadCallback");
|
||||
on_state_update = (*env)->GetMethodID(env, download_callback_class, "onStateUpdate",
|
||||
"(Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;)V");
|
||||
BIND_DOWNLOAD_STATE_STATIC_FIELD(download_state_preparing, "Preparing");
|
||||
BIND_DOWNLOAD_STATE_STATIC_FIELD(download_state_connecting, "Connecting");
|
||||
BIND_DOWNLOAD_STATE_STATIC_FIELD(download_state_authenticating, "Authenticating");
|
||||
BIND_DOWNLOAD_STATE_STATIC_FIELD(download_state_downloading, "Downloading");
|
||||
BIND_DOWNLOAD_STATE_STATIC_FIELD(download_state_finalizing, "Finalizing");
|
||||
|
||||
jclass download_callback_class = (*env)->FindClass(env, DOWNLOAD_CALLBACK_CLASS);
|
||||
on_discovered = (*env)->GetMethodID(
|
||||
env, download_callback_class, "onStateUpdate", "(L" DOWNLOAD_STATE_CLASS ";)V");
|
||||
}
|
||||
|
||||
#undef BIND_DOWNLOAD_STATE_STATIC_FIELD
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, jlong handle,
|
||||
jstring smdp, jstring matching_id,
|
||||
|
@ -79,7 +66,7 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
|
|||
|
||||
ctx->http.server_address = _smdp;
|
||||
|
||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_preparing);
|
||||
(*env)->CallVoidMethod(env, callback, on_discovered, download_state_preparing);
|
||||
ret = es10b_get_euicc_challenge_and_info(ctx);
|
||||
syslog(LOG_INFO, "es10b_get_euicc_challenge_and_info %d", ret);
|
||||
if (ret < 0) {
|
||||
|
@ -87,7 +74,7 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
|
|||
goto out;
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_connecting);
|
||||
(*env)->CallVoidMethod(env, callback, on_discovered, download_state_connecting);
|
||||
ret = es9p_initiate_authentication(ctx);
|
||||
syslog(LOG_INFO, "es9p_initiate_authentication %d", ret);
|
||||
if (ret < 0) {
|
||||
|
@ -95,7 +82,7 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
|
|||
goto out;
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_authenticating);
|
||||
(*env)->CallVoidMethod(env, callback, on_discovered, download_state_authenticating);
|
||||
ret = es10b_authenticate_server(ctx, _matching_id, _imei);
|
||||
syslog(LOG_INFO, "es10b_authenticate_server %d", ret);
|
||||
if (ret < 0) {
|
||||
|
@ -109,7 +96,7 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
|
|||
goto out;
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_downloading);
|
||||
(*env)->CallVoidMethod(env, callback, on_discovered, download_state_downloading);
|
||||
ret = es10b_prepare_download(ctx, _confirmation_code);
|
||||
syslog(LOG_INFO, "es10b_prepare_download %d", ret);
|
||||
if (ret < 0) {
|
||||
|
@ -121,7 +108,7 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_finalizing);
|
||||
(*env)->CallVoidMethod(env, callback, on_discovered, download_state_finalizing);
|
||||
ret = es10b_load_bound_profile_package(ctx, &es10b_load_bound_profile_package_result);
|
||||
syslog(LOG_INFO, "es10b_load_bound_profile_package %d, reason %d", ret, es10b_load_bound_profile_package_result.errorReason);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "lpac-jni.h"
|
||||
#include "lpac-download.h"
|
||||
#include "lpac-notifications.h"
|
||||
#include "lpac-discovery.h"
|
||||
#include "interface-wrapper.h"
|
||||
|
||||
JavaVM *jvm = NULL;
|
||||
|
@ -21,6 +22,7 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||
jvm = vm;
|
||||
interface_wrapper_init();
|
||||
lpac_download_init();
|
||||
lpac_discovery_init();
|
||||
|
||||
LPAC_JNI_SETUP_ENV;
|
||||
string_class = (*env)->FindClass(env, "java/lang/String");
|
||||
|
|
Loading…
Add table
Reference in a new issue