diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt
index feb0ab0..98237dc 100644
--- a/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt
+++ b/app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt
@@ -3,6 +3,7 @@ package im.angry.openeuicc.ui
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.DialogInterface
+import android.graphics.BitmapFactory
import android.os.Bundle
import android.text.Editable
import android.util.Log
@@ -10,6 +11,7 @@ import android.view.*
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.Toolbar
import androidx.lifecycle.lifecycleScope
import com.google.android.material.textfield.TextInputLayout
@@ -54,13 +56,38 @@ class ProfileDownloadFragment : BaseMaterialDialogFragment(),
private val barcodeScannerLauncher = registerForActivityResult(ScanContract()) { result ->
result.contents?.let { content ->
Log.d(TAG, content)
- val components = content.split("$")
- if (components.size < 3 || components[0] != "LPA:1") return@registerForActivityResult
- profileDownloadServer.editText?.setText(components[1])
- profileDownloadCode.editText?.setText(components[2])
+ onScanResult(content)
}
}
+ private val gallerySelectorLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { result ->
+ if (result == null) return@registerForActivityResult
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ runCatching {
+ requireContext().contentResolver.openInputStream(result)?.let { input ->
+ val bmp = BitmapFactory.decodeStream(input)
+ input.close()
+
+ decodeQrFromBitmap(bmp)?.let {
+ withContext(Dispatchers.Main) {
+ onScanResult(it)
+ }
+ }
+
+ bmp.recycle()
+ }
+ }
+ }
+ }
+
+ private fun onScanResult(result: String) {
+ val components = result.split("$")
+ if (components.size < 3 || components[0] != "LPA:1") return
+ profileDownloadServer.editText?.setText(components[1])
+ profileDownloadCode.editText?.setText(components[2])
+ }
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -103,6 +130,10 @@ class ProfileDownloadFragment : BaseMaterialDialogFragment(),
})
true
}
+ R.id.scan_from_gallery -> {
+ gallerySelectorLauncher.launch("image/*")
+ true
+ }
R.id.ok -> {
startDownloadProfile()
true
diff --git a/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt b/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt
index 6a43d00..a93e7d2 100644
--- a/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt
+++ b/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt
@@ -2,9 +2,14 @@ package im.angry.openeuicc.util
import android.content.Context
import android.content.pm.PackageManager
+import android.graphics.Bitmap
import android.se.omapi.SEService
import android.telephony.TelephonyManager
import androidx.fragment.app.Fragment
+import com.google.zxing.BinaryBitmap
+import com.google.zxing.RGBLuminanceSource
+import com.google.zxing.common.HybridBinarizer
+import com.google.zxing.qrcode.QRCodeReader
import im.angry.openeuicc.OpenEuiccApplication
import im.angry.openeuicc.core.EuiccChannel
import im.angry.openeuicc.di.AppContainer
@@ -88,3 +93,14 @@ suspend fun connectSEService(context: Context): SEService = suspendCoroutine { c
}
}
}
+
+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)
+
+ val luminanceSource = RGBLuminanceSource(bmp.width, bmp.height, pixels)
+ val binaryBmp = BinaryBitmap(HybridBinarizer(luminanceSource))
+
+ QRCodeReader().decode(binaryBmp).text
+ }.getOrNull()
diff --git a/app-common/src/main/res/drawable/ic_gallery_black.xml b/app-common/src/main/res/drawable/ic_gallery_black.xml
new file mode 100644
index 0000000..048f74a
--- /dev/null
+++ b/app-common/src/main/res/drawable/ic_gallery_black.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app-common/src/main/res/menu/fragment_profile_download.xml b/app-common/src/main/res/menu/fragment_profile_download.xml
index d89c52c..b75822a 100644
--- a/app-common/src/main/res/menu/fragment_profile_download.xml
+++ b/app-common/src/main/res/menu/fragment_profile_download.xml
@@ -7,6 +7,12 @@
android:title="@string/profile_download_scan"
app:showAsAction="ifRoom"/>
+
+
- IMEI (Optional)
Space remaining: %s
Scan QR Code
+ Scan QR Code from Gallery
Download
Failed to download eSIM. Check your activation / QR code.