diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1b178c7..1ddea46 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
The changes documented here do not include those from the original repository.
+# [2.1.1]
+
+### 2026-08-03
+
+- Show camera preview only after permission is granted. This issue was uncovered while updating a consumer app's androidx camera2 dependency do 1.6.2 (https://outsystemsrd.atlassian.net/browse/RMET-5329 + https://github.com/OutSystems/OSBarcodeLib-Android/issues/57)
+
# [2.1.0]
### 2026-06-26
diff --git a/docs/README.md b/docs/README.md
index f4b7856..b4fa9e1 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -46,7 +46,7 @@ In your app-level gradle file, import the OSBarcodeLib library like so:
```gradle
dependencies {
- implementation("com.github.outsystems:osbarcode-android:2.1.0@aar")
+ implementation("com.github.outsystems:osbarcode-android:2.1.1@aar")
}
```
diff --git a/pom.xml b/pom.xml
index 5ae04cd..ddde6e8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,5 +7,5 @@
4.0.0
io.ionic.libs
ionbarcode-android
- 2.1.0
+ 2.1.1
diff --git a/src/main/kotlin/com/outsystems/plugins/barcode/view/OSBARCScannerActivity.kt b/src/main/kotlin/com/outsystems/plugins/barcode/view/OSBARCScannerActivity.kt
index b8adab2..180c535 100644
--- a/src/main/kotlin/com/outsystems/plugins/barcode/view/OSBARCScannerActivity.kt
+++ b/src/main/kotlin/com/outsystems/plugins/barcode/view/OSBARCScannerActivity.kt
@@ -139,6 +139,7 @@ class OSBARCScannerActivity : ComponentActivity() {
private lateinit var selector: CameraSelector
private var permissionRequestCount = 0
private var showDialog by mutableStateOf(false)
+ private var permissionGiven by mutableStateOf(false)
private var isScanning = false
private lateinit var cameraExecutor: ExecutorService
@@ -213,7 +214,7 @@ class OSBARCScannerActivity : ComponentActivity() {
override fun onResume() {
super.onResume()
- showDialog = !hasCameraPermission(this.applicationContext)
+ updatePermissionState(hasCameraPermission(this.applicationContext))
}
override fun onDestroy() {
@@ -231,20 +232,13 @@ class OSBARCScannerActivity : ComponentActivity() {
fun ScanScreen(parameters: OSBARCScanParameters, windowSizeClass: WindowSizeClass) {
val lifecycleOwner = LocalLifecycleOwner.current
val context = LocalContext.current
- var permissionGiven by remember { mutableStateOf(true) }
var uiState by remember { mutableStateOf(OSBARCScannerUiState.DEFAULT) }
// permissions
val requestPermissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
- if (isGranted) {
- permissionGiven = true
- showDialog = false
- } else {
- permissionGiven = false
- showDialog = true
- }
+ updatePermissionState(isGranted)
}
SideEffect {
if (permissionRequestCount == 0) {
@@ -278,61 +272,53 @@ class OSBARCScannerActivity : ComponentActivity() {
ProcessCameraProvider.getInstance(context)
}
- try {
- camera = cameraProviderFuture.get().bindToLifecycle(
- lifecycleOwner,
- selector
- )
- } catch (e: Exception) {
- e.message?.let { Log.e(LOG_TAG, it) }
- setResult(OSBARCError.SCANNING_GENERAL_ERROR.code)
- finish()
- }
-
Box(
modifier = Modifier
.fillMaxSize()
+ .background(ScannerBackgroundBlack)
) {
- AndroidView(
- factory = { context ->
- val previewView = PreviewView(context)
- val preview = Preview.Builder().build()
- preview.setSurfaceProvider(previewView.surfaceProvider)
-
- val resolutionSelector = ResolutionSelector.Builder().setResolutionStrategy(
- ResolutionStrategy(android.util.Size(1920, 1080), // high resolution for optimal scanning
- ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER)
- ).build()
- val imageAnalysis = ImageAnalysis.Builder()
- .setResolutionSelector(resolutionSelector)
- .setBackpressureStrategy(STRATEGY_KEEP_ONLY_LATEST)
- .build()
- imageAnalysis.setAnalyzer(
- cameraExecutor,
- barcodeAnalyzer
- )
- try {
- camera = cameraProviderFuture.get().bindToLifecycle(
- lifecycleOwner,
- selector,
- preview,
- imageAnalysis
- ).also {
- uiState = OSBARCScannerUiState(
- hasFlashUnit = it.cameraInfo.hasFlashUnit(),
- minZoomRatio = it.cameraInfo.zoomState.value?.minZoomRatio ?: 1f,
- maxZoomRatio = it.cameraInfo.zoomState.value?.maxZoomRatio ?: 1f
- )
+ if (permissionGiven) {
+ AndroidView(
+ factory = { context ->
+ val previewView = PreviewView(context)
+ val preview = Preview.Builder().build()
+ preview.setSurfaceProvider(previewView.surfaceProvider)
+
+ val resolutionSelector = ResolutionSelector.Builder().setResolutionStrategy(
+ ResolutionStrategy(android.util.Size(1920, 1080), // high resolution for optimal scanning
+ ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER)
+ ).build()
+ val imageAnalysis = ImageAnalysis.Builder()
+ .setResolutionSelector(resolutionSelector)
+ .setBackpressureStrategy(STRATEGY_KEEP_ONLY_LATEST)
+ .build()
+ imageAnalysis.setAnalyzer(
+ cameraExecutor,
+ barcodeAnalyzer
+ )
+ try {
+ camera = cameraProviderFuture.get().bindToLifecycle(
+ lifecycleOwner,
+ selector,
+ preview,
+ imageAnalysis
+ ).also {
+ uiState = OSBARCScannerUiState(
+ hasFlashUnit = it.cameraInfo.hasFlashUnit(),
+ minZoomRatio = it.cameraInfo.zoomState.value?.minZoomRatio ?: 1f,
+ maxZoomRatio = it.cameraInfo.zoomState.value?.maxZoomRatio ?: 1f
+ )
+ }
+ } catch (e: Exception) {
+ e.message?.let { Log.e(LOG_TAG, it) }
+ setResult(OSBARCError.SCANNING_GENERAL_ERROR.code)
+ finish()
}
- } catch (e: Exception) {
- e.message?.let { Log.e(LOG_TAG, it) }
- setResult(OSBARCError.SCANNING_GENERAL_ERROR.code)
- finish()
- }
- previewView
- },
- modifier = Modifier.fillMaxSize()
- )
+ previewView
+ },
+ modifier = Modifier.fillMaxSize()
+ )
+ }
ScanScreenUI(parameters, windowSizeClass, uiState)
@@ -957,6 +943,13 @@ class OSBARCScannerActivity : ComponentActivity() {
) == PackageManager.PERMISSION_GRANTED
}
+ private fun updatePermissionState(hasPermission: Boolean) {
+ permissionGiven = hasPermission
+ if (permissionRequestCount > 0) {
+ showDialog = !hasPermission
+ }
+ }
+
private fun processReadSuccess(result: OSBARCScanResult) {
// we only want to process the scan result if scanning is active
if (isScanning) {