Skip to content

Commit f04bcd5

Browse files
committed
fix(android): use Google Code Scanner for onboarding QR
1 parent f9ea879 commit f04bcd5

File tree

2 files changed

+39
-28
lines changed

2 files changed

+39
-28
lines changed

apps/android/app/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ dependencies {
194194
implementation("androidx.camera:camera-lifecycle:1.5.2")
195195
implementation("androidx.camera:camera-video:1.5.2")
196196
implementation("androidx.camera:camera-view:1.5.2")
197-
implementation("com.journeyapps:zxing-android-embedded:4.3.0")
197+
implementation("com.google.android.gms:play-services-code-scanner:16.1.0")
198198

199199
// Unicast DNS-SD (Wide-Area Bonjour) for tailnet discovery domains.
200200
implementation("dnsjava:dnsjava:3.6.4")

apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@ import ai.openclaw.app.LocationMode
9696
import ai.openclaw.app.MainViewModel
9797
import ai.openclaw.app.R
9898
import 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

102103
private 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+
17881799
private fun isNotificationListenerEnabled(context: Context): Boolean {
17891800
return DeviceNotificationListenerService.isAccessEnabled(context)
17901801
}

0 commit comments

Comments
 (0)