Fix qr code scanner when using multiwindow mode

This commit is contained in:
greenart7c3
2025-05-30 07:14:06 -03:00
parent b6c1043588
commit d5cdad8825
3 changed files with 129 additions and 28 deletions
+5
View File
@@ -31,6 +31,11 @@
android:windowSoftInputMode="adjustResize"
tools:targetApi="33">
<activity
android:name=".QrCodeScannerActivity"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
android:exported="false" />
<receiver
android:name=".service.BootReceiver"
android:enabled="true"
@@ -0,0 +1,106 @@
package com.greenart7c3.nostrsigner
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import com.google.zxing.BarcodeFormat
import com.google.zxing.ResultPoint
import com.journeyapps.barcodescanner.BarcodeCallback
import com.journeyapps.barcodescanner.BarcodeResult
import com.journeyapps.barcodescanner.DecoratedBarcodeView
import com.journeyapps.barcodescanner.DefaultDecoderFactory
class QrCodeScannerActivity : ComponentActivity() {
private lateinit var barcodeView: DecoratedBarcodeView
private var hasFailedToResumeCamera = false
private val cameraPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
) { isGranted ->
if (isGranted) {
setupScanner()
} else {
Toast.makeText(this, "Camera permission denied.", Toast.LENGTH_SHORT).show()
sendResultAndFinish(null)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (hasCameraPermission()) {
setupScanner()
} else {
cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
private fun hasCameraPermission(): Boolean {
return checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
}
private fun setupScanner() {
barcodeView = DecoratedBarcodeView(this).apply {
barcodeView.decoderFactory = DefaultDecoderFactory(listOf(BarcodeFormat.QR_CODE))
initializeFromIntent(intent)
decodeContinuous(object : BarcodeCallback {
override fun barcodeResult(result: BarcodeResult?) {
result?.text?.let {
sendResultAndFinish(it)
}
}
override fun possibleResultPoints(resultPoints: MutableList<ResultPoint>?) {}
})
}
setContentView(barcodeView)
safeResumeScanner()
}
private fun safeResumeScanner() {
try {
barcodeView.resume()
} catch (e: Exception) {
Log.e("QrScanner", "Camera resume failed: ${e.message}")
if (!hasFailedToResumeCamera) {
hasFailedToResumeCamera = true
Toast.makeText(this, "Camera is in use by another app.", Toast.LENGTH_LONG).show()
barcodeView.postDelayed({
sendResultAndFinish(null)
}, 1500)
}
}
}
override fun onResume() {
super.onResume()
if (::barcodeView.isInitialized && hasWindowFocus()) {
safeResumeScanner()
}
}
override fun onPause() {
super.onPause()
if (::barcodeView.isInitialized) {
barcodeView.pause()
}
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (::barcodeView.isInitialized) {
if (hasFocus) safeResumeScanner() else barcodeView.pause()
}
}
private fun sendResultAndFinish(result: String?) {
setResult(RESULT_OK, Intent().putExtra("qr_result", result))
finish()
}
}
@@ -1,37 +1,27 @@
package com.greenart7c3.nostrsigner.ui
import android.content.Intent
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.lifecycle.compose.LocalLifecycleOwner
import com.google.zxing.client.android.Intents
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanOptions
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.platform.LocalContext
import com.greenart7c3.nostrsigner.QrCodeScannerActivity
@Composable
fun SimpleQrCodeScanner(onScan: (String?) -> Unit) {
val lifecycleOwner = LocalLifecycleOwner.current
fun SimpleQrCodeScanner(
onScan: (String?) -> Unit,
) {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
) { result ->
val text = result.data?.getStringExtra("qr_result")
onScan(text)
}
val qrLauncher =
rememberLauncherForActivityResult(ScanContract()) {
if (it.contents != null) {
onScan(it.contents)
} else {
onScan(null)
}
}
val scanOptions =
ScanOptions().apply {
setDesiredBarcodeFormats(ScanOptions.QR_CODE)
setPrompt("Point to the QR Code")
setBeepEnabled(false)
setOrientationLocked(false)
addExtra(Intents.Scan.SCAN_TYPE, Intents.Scan.MIXED_SCAN)
}
DisposableEffect(lifecycleOwner) {
qrLauncher.launch(scanOptions)
onDispose { }
LaunchedEffect(Unit) {
val intent = Intent(context, QrCodeScannerActivity::class.java)
launcher.launch(intent)
}
}