@@ -96,8 +96,9 @@ import ai.openclaw.app.LocationMode
9696import ai.openclaw.app.MainViewModel
9797import ai.openclaw.app.R
9898import ai.openclaw.app.node.DeviceNotificationListenerService
99- import com.journeyapps.barcodescanner.ScanContract
100- import com.journeyapps.barcodescanner.ScanOptions
99+ import com.google.mlkit.vision.barcode.common.Barcode
100+ import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions
101+ import com.google.mlkit.vision.codescanner.GmsBarcodeScanning
101102
102103private enum class OnboardingStep (val index : Int , val label : String ) {
103104 Welcome (1 , " Welcome" ),
@@ -241,6 +242,13 @@ fun OnboardingFlow(viewModel: MainViewModel, modifier: Modifier = Modifier) {
241242 var attemptedConnect by rememberSaveable { mutableStateOf(false ) }
242243
243244 val lifecycleOwner = LocalLifecycleOwner .current
245+ val qrScannerOptions =
246+ remember {
247+ GmsBarcodeScannerOptions .Builder ()
248+ .setBarcodeFormats(Barcode .FORMAT_QR_CODE )
249+ .build()
250+ }
251+ val qrScanner = remember(context, qrScannerOptions) { GmsBarcodeScanning .getClient(context, qrScannerOptions) }
244252
245253 val smsAvailable =
246254 remember(context) {
@@ -460,23 +468,6 @@ fun OnboardingFlow(viewModel: MainViewModel, modifier: Modifier = Modifier) {
460468 onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
461469 }
462470
463- val qrScanLauncher =
464- rememberLauncherForActivityResult(ScanContract ()) { result ->
465- val contents = result.contents?.trim().orEmpty()
466- if (contents.isEmpty()) {
467- return @rememberLauncherForActivityResult
468- }
469- val scannedSetupCode = resolveScannedSetupCode(contents)
470- if (scannedSetupCode == null ) {
471- gatewayError = " QR code did not contain a valid setup code."
472- return @rememberLauncherForActivityResult
473- }
474- setupCode = scannedSetupCode
475- gatewayInputMode = GatewayInputMode .SetupCode
476- gatewayError = null
477- attemptedConnect = false
478- }
479-
480471 if (pendingTrust != null ) {
481472 val prompt = pendingTrust!!
482473 AlertDialog (
@@ -552,14 +543,28 @@ fun OnboardingFlow(viewModel: MainViewModel, modifier: Modifier = Modifier) {
552543 gatewayError = gatewayError,
553544 onScanQrClick = {
554545 gatewayError = null
555- qrScanLauncher.launch(
556- ScanOptions ().apply {
557- setDesiredBarcodeFormats(ScanOptions .QR_CODE )
558- setPrompt(" Scan OpenClaw onboarding QR" )
559- setBeepEnabled(false )
560- setOrientationLocked(false )
561- },
562- )
546+ qrScanner.startScan()
547+ .addOnSuccessListener { barcode ->
548+ val contents = barcode.rawValue?.trim().orEmpty()
549+ if (contents.isEmpty()) {
550+ return @addOnSuccessListener
551+ }
552+ val scannedSetupCode = resolveScannedSetupCode(contents)
553+ if (scannedSetupCode == null ) {
554+ gatewayError = " QR code did not contain a valid setup code."
555+ return @addOnSuccessListener
556+ }
557+ setupCode = scannedSetupCode
558+ gatewayInputMode = GatewayInputMode .SetupCode
559+ gatewayError = null
560+ attemptedConnect = false
561+ }
562+ .addOnCanceledListener {
563+ // User dismissed the scanner; preserve current form state.
564+ }
565+ .addOnFailureListener { error ->
566+ gatewayError = resolveQrScannerError(error)
567+ }
563568 },
564569 onAdvancedOpenChange = { gatewayAdvancedOpen = it },
565570 onInputModeChange = {
@@ -1785,6 +1790,12 @@ private fun isPermissionGranted(context: Context, permission: String): Boolean {
17851790 return ContextCompat .checkSelfPermission(context, permission) == PackageManager .PERMISSION_GRANTED
17861791}
17871792
1793+ private fun resolveQrScannerError (error : Exception ): String {
1794+ val detail = error.message?.trim().orEmpty()
1795+ val prefix = " Google Code Scanner could not start. Update Google Play services or use the setup code manually."
1796+ return if (detail.isEmpty()) prefix else " $prefix ($detail )"
1797+ }
1798+
17881799private fun isNotificationListenerEnabled (context : Context ): Boolean {
17891800 return DeviceNotificationListenerService .isAccessEnabled(context)
17901801}
0 commit comments