| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- 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.di.AppContainer
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.runBlocking
- import kotlinx.coroutines.sync.Mutex
- import kotlinx.coroutines.sync.withLock
- import kotlinx.coroutines.withContext
- import kotlin.RuntimeException
- import kotlin.coroutines.resume
- import kotlin.coroutines.resumeWithException
- import kotlin.coroutines.suspendCoroutine
- val Context.selfAppVersion: String
- get() =
- try {
- val pInfo = packageManager.getPackageInfo(packageName, 0)
- pInfo.versionName!!
- } catch (e: PackageManager.NameNotFoundException) {
- throw RuntimeException(e)
- }
- suspend fun readSelfLog(lines: Int = 2048): String = withContext(Dispatchers.IO) {
- try {
- Runtime.getRuntime().exec("logcat -t $lines").inputStream.readBytes()
- .decodeToString()
- } catch (_: Exception) {
- ""
- }
- }
- interface OpenEuiccContextMarker {
- val openEuiccMarkerContext: Context
- get() = when (this) {
- is Context -> this
- is Fragment -> requireContext()
- else -> throw RuntimeException("OpenEuiccUIContextMarker shall only be used on Fragments or UI types that derive from Context")
- }
- val openEuiccApplication: OpenEuiccApplication
- get() = openEuiccMarkerContext.applicationContext as OpenEuiccApplication
- val appContainer: AppContainer
- get() = openEuiccApplication.appContainer
- val telephonyManager: TelephonyManager
- get() = appContainer.telephonyManager
- }
- // Create an instance of OMAPI SEService in a manner that "makes sense" without unpredictable callbacks
- suspend fun connectSEService(context: Context): SEService = suspendCoroutine { cont ->
- // Use a Mutex to make sure the continuation is run *after* the "service" variable is assigned
- val lock = Mutex()
- var service: SEService? = null
- val callback = {
- runBlocking {
- lock.withLock {
- cont.resume(service!!)
- }
- }
- }
- runBlocking {
- // If this were not protected by a Mutex, callback might be run before service is even assigned
- // Yes, we are on Android, we could have used something like a Handler, but we cannot really
- // assume the coroutine is run on a thread that has a Handler. We either use our own HandlerThread
- // (and then cleanup becomes an issue), or we use a lock
- lock.withLock {
- try {
- service = SEService(context, { it.run() }, callback)
- } catch (e: Exception) {
- cont.resumeWithException(e)
- }
- }
- }
- }
- inline fun <T> Bitmap.use(f: (Bitmap) -> T): T =
- try {
- f(this)
- } finally {
- 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)
- val luminanceSource = RGBLuminanceSource(bmp.width, bmp.height, pixels)
- val binaryBmp = BinaryBitmap(HybridBinarizer(luminanceSource))
- QRCodeReader().decode(binaryBmp).text
- }.getOrNull()
|