Compare commits

...

2 commits

Author SHA1 Message Date
Peter Cai 3869374140 ProfileDownloadFragment: make OK always appear as action
All checks were successful
/ build-debug (push) Successful in 5m19s
2024-05-20 18:09:49 -04:00
Peter Cai fc4e5739de feat: Scan QR code from gallery
Close #6.
2024-05-20 18:09:00 -04:00
5 changed files with 64 additions and 5 deletions

View file

@ -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

View file

@ -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()

View file

@ -0,0 +1,5 @@
<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>

View file

@ -7,9 +7,15 @@
android:title="@string/profile_download_scan"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/scan_from_gallery"
android:icon="@drawable/ic_gallery_black"
android:title="@string/profile_download_scan_from_gallery"
app:showAsAction="ifRoom" />
<item
android:id="@+id/ok"
android:icon="@drawable/ic_check_black"
android:title="@string/profile_download_ok"
app:showAsAction="ifRoom"/>
app:showAsAction="always"/>
</menu>

View file

@ -31,6 +31,7 @@
<string name="profile_download_imei">IMEI (Optional)</string>
<string name="profile_download_free_space">Space remaining: %s</string>
<string name="profile_download_scan">Scan QR Code</string>
<string name="profile_download_scan_from_gallery">Scan QR Code from Gallery</string>
<string name="profile_download_ok">Download</string>
<string name="profile_download_failed">Failed to download eSIM. Check your activation / QR code.</string>