Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ 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.0.0]

### 2025-08-22

**BREAKING CHANGE:** The signature of `handleActivityResult` has changed - the onSuccess now returns `OSBARCScanResult` instead of just a string with the scanned code.

- Add **hint** parameter to scan for specific barcode formats
- Return the format of the scanned code inside the scan result.

## [1.2.1]

### 20205-08-18
Expand Down
6 changes: 3 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ In your app-level gradle file, import the OSBarcodeLib library like so:

```gradle
dependencies {
implementation("com.github.outsystems:osbarcode-android:1.0.0@aar")
implementation("com.github.outsystems:osbarcode-android:2.0.0@aar")
}
```

Expand All @@ -72,7 +72,7 @@ A method that triggers the barcode reader/scanner, opening a new activity with t
- **scanOrientation**: An integer indicating which scan orientation to use - portrait, landscape, or adaptive.
- **scanButton**: A boolean that will display a scan button on the barcode reader. If true, scanning will only be triggered when pressing the button instead of automatically when framing the barcode. A second click on the button disables scannning.
- **scanText**: A string that contains the text to be displayed on the scan button. It will only be shown if **scanButton** is set to true.
- **hint**: An integer that holds a hint to what type of barcode to look for. **This parameter isn't being used yet**.
- **hint**: An integer that holds a hint to what type of barcode to look for.
- **androidScanningLibrary**: A string which determines what barcode library to use - ML Kit or ZXing.

#### Usage
Expand All @@ -89,7 +89,7 @@ fun handleActivityResult(
requestCode: Int,
resultCode: Int,
intent: Intent?,
onSuccess: (String) -> Unit,
onSuccess: (OSBARCScanResult) -> Unit,
onError: (OSBARCError) -> Unit
)
```
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.ionic.libs</groupId>
<artifactId>ionbarcode-android</artifactId>
<version>1.2.1</version>
<version>2.0.0</version>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.outsystems.plugins.barcode.controller.helper.OSBARCImageHelperInterface
import com.outsystems.plugins.barcode.model.OSBARCError
import com.outsystems.plugins.barcode.model.OSBARCScanResult
import com.outsystems.plugins.barcode.view.ui.theme.SizeRatioHeight
import com.outsystems.plugins.barcode.view.ui.theme.SizeRatioWidth
import java.lang.Exception
Expand All @@ -17,7 +18,7 @@ import java.lang.Exception
class OSBARCBarcodeAnalyzer(
private val scanLibrary: OSBARCScanLibraryInterface,
private val imageHelper: OSBARCImageHelperInterface,
private val onBarcodeScanned: (String) -> Unit,
private val onBarcodeScanned: (OSBARCScanResult) -> Unit,
private val onScanningError: (OSBARCError) -> Unit
): ImageAnalysis.Analyzer {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package com.outsystems.plugins.barcode.controller
import android.app.Activity
import android.content.Intent
import android.util.Log
import androidx.core.content.IntentCompat
import com.outsystems.plugins.barcode.model.OSBARCError
import com.outsystems.plugins.barcode.model.OSBARCScanParameters
import com.outsystems.plugins.barcode.model.OSBARCScanResult
import com.outsystems.plugins.barcode.view.OSBARCScannerActivity

/**
Expand Down Expand Up @@ -46,15 +48,17 @@ class OSBARCController {
requestCode: Int,
resultCode: Int,
intent: Intent?,
onSuccess: (String) -> Unit,
onSuccess: (OSBARCScanResult) -> Unit,
onError: (OSBARCError) -> Unit
) {
when (requestCode) {
SCAN_REQUEST_CODE -> {
when (resultCode) {
Activity.RESULT_OK -> {
val result = intent?.extras?.getString(SCAN_RESULT)
if (result.isNullOrEmpty()) {
val result: OSBARCScanResult? = intent?.let {
IntentCompat.getSerializableExtra(intent, SCAN_RESULT, OSBARCScanResult::class.java)
}
if (result == null || result.text.isEmpty()) {
onError(OSBARCError.SCANNING_GENERAL_ERROR)
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package com.outsystems.plugins.barcode.controller
import android.graphics.Bitmap
import android.util.Log
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.common.Barcode
import com.outsystems.plugins.barcode.controller.helper.OSBARCMLKitHelperInterface
import com.outsystems.plugins.barcode.model.OSBARCError
import com.outsystems.plugins.barcode.model.OSBARCScanResult
import com.outsystems.plugins.barcode.model.OSBARCScannerHint

/**
* Wrapper class that implements the OSBARCScanLibraryInterface
Expand All @@ -25,18 +28,20 @@ class OSBARCMLKitWrapper(private val helper: OSBARCMLKitHelperInterface): OSBARC
override fun scanBarcode(
imageProxy: ImageProxy,
imageBitmap: Bitmap,
onSuccess: (String) -> Unit,
onSuccess: (OSBARCScanResult) -> Unit,
onError: (OSBARCError) -> Unit
) {
try {
helper.decodeImage(imageProxy, imageBitmap,
{ barcodes ->
var result: String? = null
if (barcodes.isNotEmpty()) {
result = barcodes.first().rawValue
}
if (!result.isNullOrEmpty()) {
onSuccess(result)
barcodes.firstOrNull()?.let { barcode ->
val result = OSBARCScanResult(
text = barcode.rawValue ?: "",
format = barcode.format.toOSBARCScannerHint()
)
if (result.text.isNotEmpty()) {
onSuccess(result)
}
}
},
{
Expand All @@ -49,4 +54,22 @@ class OSBARCMLKitWrapper(private val helper: OSBARCMLKitHelperInterface): OSBARC
}
}

private fun Int?.toOSBARCScannerHint(): OSBARCScannerHint = when (this) {
Barcode.FORMAT_QR_CODE -> OSBARCScannerHint.QR_CODE
Barcode.FORMAT_AZTEC -> OSBARCScannerHint.AZTEC
Barcode.FORMAT_CODABAR -> OSBARCScannerHint.CODABAR
Barcode.FORMAT_CODE_39 -> OSBARCScannerHint.CODE_39
Barcode.FORMAT_CODE_93 -> OSBARCScannerHint.CODE_93
Barcode.FORMAT_CODE_128 -> OSBARCScannerHint.CODE_128
Barcode.FORMAT_DATA_MATRIX -> OSBARCScannerHint.DATA_MATRIX
Barcode.FORMAT_ITF -> OSBARCScannerHint.ITF
Barcode.FORMAT_EAN_13 -> OSBARCScannerHint.EAN_13
Barcode.FORMAT_EAN_8 -> OSBARCScannerHint.EAN_8
Barcode.FORMAT_PDF417 -> OSBARCScannerHint.PDF_417
Barcode.FORMAT_UPC_A -> OSBARCScannerHint.UPC_A
Barcode.FORMAT_UPC_E -> OSBARCScannerHint.UPC_E

// Formats not supported by ML Kit → map to UNKNOWN
else -> OSBARCScannerHint.UNKNOWN
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.outsystems.plugins.barcode.controller
import android.graphics.Bitmap
import androidx.camera.core.ImageProxy
import com.outsystems.plugins.barcode.model.OSBARCError
import com.outsystems.plugins.barcode.model.OSBARCScanResult

/**
* Interface that provides the signature of the scanBarcode method
Expand All @@ -11,7 +12,7 @@ fun interface OSBARCScanLibraryInterface {
fun scanBarcode(
imageProxy: ImageProxy,
imageBitmap: Bitmap,
onSuccess: (String) -> Unit,
onSuccess: (OSBARCScanResult) -> Unit,
onError: (OSBARCError) -> Unit
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.util.Log
import androidx.camera.core.ImageProxy
import com.outsystems.plugins.barcode.controller.helper.OSBARCZXingHelperInterface
import com.outsystems.plugins.barcode.model.OSBARCError
import com.outsystems.plugins.barcode.model.OSBARCScanResult

/**
* Wrapper class that implements the OSBARCScanLibraryInterface
Expand All @@ -25,7 +26,7 @@ class OSBARCZXingWrapper(private val helper: OSBARCZXingHelperInterface) : OSBAR
override fun scanBarcode(
imageProxy: ImageProxy,
imageBitmap: Bitmap,
onSuccess: (String) -> Unit,
onSuccess: (OSBARCScanResult) -> Unit,
onError: (OSBARCError) -> Unit
) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,51 @@ import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
import com.outsystems.plugins.barcode.model.OSBARCScannerHint
import org.jetbrains.annotations.VisibleForTesting

/**
* Helper class that implements the OSBARCMLKitHelperInterface
* to scan an image using the ML Kit library.
* It encapsulates all the code related with the ML Kit library.
*/
class OSBARCMLKitHelper: OSBARCMLKitHelperInterface {
class OSBARCMLKitHelper(private val hint: OSBARCScannerHint?): OSBARCMLKitHelperInterface {
companion object {
private const val LOG_TAG = "OSBARCMLKitHelper"

@VisibleForTesting
internal fun OSBARCScannerHint?.toMLKitBarcodeFormat(): Int? = when (this) {
OSBARCScannerHint.QR_CODE -> Barcode.FORMAT_QR_CODE
OSBARCScannerHint.AZTEC -> Barcode.FORMAT_AZTEC
OSBARCScannerHint.CODABAR -> Barcode.FORMAT_CODABAR
OSBARCScannerHint.CODE_39 -> Barcode.FORMAT_CODE_39
OSBARCScannerHint.CODE_93 -> Barcode.FORMAT_CODE_93
OSBARCScannerHint.CODE_128 -> Barcode.FORMAT_CODE_128
OSBARCScannerHint.DATA_MATRIX -> Barcode.FORMAT_DATA_MATRIX
OSBARCScannerHint.MAXICODE -> null // not supported by ML Kit
OSBARCScannerHint.ITF -> Barcode.FORMAT_ITF
OSBARCScannerHint.EAN_13 -> Barcode.FORMAT_EAN_13
OSBARCScannerHint.EAN_8 -> Barcode.FORMAT_EAN_8
OSBARCScannerHint.PDF_417 -> Barcode.FORMAT_PDF417
OSBARCScannerHint.RSS_14 -> null // not supported by ML Kit
OSBARCScannerHint.RSS_EXPANDED -> null // not supported by ML Kit
OSBARCScannerHint.UPC_A -> Barcode.FORMAT_UPC_A
OSBARCScannerHint.UPC_E -> Barcode.FORMAT_UPC_E
OSBARCScannerHint.UPC_EAN_EXTENSION -> null // not supported by ML Kit
OSBARCScannerHint.UNKNOWN -> null
null -> null
}
}

private val scanner by lazy {
val options = BarcodeScannerOptions.Builder()
.enableAllPotentialBarcodes()
.build()
val options = BarcodeScannerOptions.Builder().apply {
val format = hint.toMLKitBarcodeFormat()
if (format != null) {
setBarcodeFormats(format)
} else {
enableAllPotentialBarcodes()
}
}.build()
BarcodeScanning.getClient(options)
}

Expand Down Expand Up @@ -51,5 +81,4 @@ class OSBARCMLKitHelper: OSBARCMLKitHelperInterface {
onError()
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,38 @@ package com.outsystems.plugins.barcode.controller.helper
import android.graphics.Bitmap
import android.graphics.Matrix
import android.util.Log
import com.google.zxing.BarcodeFormat
import com.google.zxing.BinaryBitmap
import com.google.zxing.DecodeHintType
import com.google.zxing.MultiFormatReader
import com.google.zxing.NotFoundException
import com.google.zxing.RGBLuminanceSource
import com.google.zxing.common.HybridBinarizer
import com.outsystems.plugins.barcode.model.OSBARCScanResult
import com.outsystems.plugins.barcode.model.OSBARCScannerHint

/**
* Helper class that implements the OSBARCZXingHelperInterface
* to scan an image using the ZXing library.
* It encapsulates all the code related with the ZXing library.
*/
class OSBARCZXingHelper: OSBARCZXingHelperInterface {
class OSBARCZXingHelper(private val hint: OSBARCScannerHint?): OSBARCZXingHelperInterface {

companion object {
private const val LOG_TAG = "OSBARCZXingHelper"
}

private val reader: MultiFormatReader by lazy {
val format = hint.toZXingBarcodeFormat()
MultiFormatReader().apply {
if (format != null) {
setHints(
mapOf(DecodeHintType.POSSIBLE_FORMATS to setOf(format))
)
}
}
}

/**
* Rotates a bitmap, provided with the rotation degrees.
* @param bitmap - Bitmap object to rotate
Expand Down Expand Up @@ -51,22 +66,69 @@ class OSBARCZXingHelper: OSBARCZXingHelperInterface {
*/
override fun decodeImage(
pixels: IntArray, width: Int, height: Int,
onSuccess: (String) -> Unit,
onSuccess: (OSBARCScanResult) -> Unit,
onError: () -> Unit
) {
try {
val source = RGBLuminanceSource(width, height, pixels)
val binaryBitmap = BinaryBitmap(HybridBinarizer(source))
val result = MultiFormatReader().decodeWithState(binaryBitmap)
onSuccess(result.text)
val result = reader.decodeWithState(binaryBitmap)
onSuccess(
OSBARCScanResult(
text = result.text,
format = result.barcodeFormat.toOSBARCScannerHint()
)
)
} catch (e: NotFoundException) {
// keep trying, no barcode was found in this camera frame
e.message?.let { Log.d(LOG_TAG, it) }
} catch (e: Exception) {
e.message?.let { Log.e(LOG_TAG, it) }
onError()
}
}

private fun OSBARCScannerHint?.toZXingBarcodeFormat(): BarcodeFormat? = when (this) {
OSBARCScannerHint.QR_CODE -> BarcodeFormat.QR_CODE
OSBARCScannerHint.AZTEC -> BarcodeFormat.AZTEC
OSBARCScannerHint.CODABAR -> BarcodeFormat.CODABAR
OSBARCScannerHint.CODE_39 -> BarcodeFormat.CODE_39
OSBARCScannerHint.CODE_93 -> BarcodeFormat.CODE_93
OSBARCScannerHint.CODE_128 -> BarcodeFormat.CODE_128
OSBARCScannerHint.DATA_MATRIX -> BarcodeFormat.DATA_MATRIX
OSBARCScannerHint.MAXICODE -> BarcodeFormat.MAXICODE
OSBARCScannerHint.ITF -> BarcodeFormat.ITF
OSBARCScannerHint.EAN_13 -> BarcodeFormat.EAN_13
OSBARCScannerHint.EAN_8 -> BarcodeFormat.EAN_8
OSBARCScannerHint.PDF_417 -> BarcodeFormat.PDF_417
OSBARCScannerHint.RSS_14 -> BarcodeFormat.RSS_14
OSBARCScannerHint.RSS_EXPANDED -> BarcodeFormat.RSS_EXPANDED
OSBARCScannerHint.UPC_A -> BarcodeFormat.UPC_A
OSBARCScannerHint.UPC_E -> BarcodeFormat.UPC_E
OSBARCScannerHint.UPC_EAN_EXTENSION -> BarcodeFormat.UPC_EAN_EXTENSION
OSBARCScannerHint.UNKNOWN -> null
null -> null
}

private fun BarcodeFormat?.toOSBARCScannerHint(): OSBARCScannerHint = when (this) {
BarcodeFormat.QR_CODE -> OSBARCScannerHint.QR_CODE
BarcodeFormat.AZTEC -> OSBARCScannerHint.AZTEC
BarcodeFormat.CODABAR -> OSBARCScannerHint.CODABAR
BarcodeFormat.CODE_39 -> OSBARCScannerHint.CODE_39
BarcodeFormat.CODE_93 -> OSBARCScannerHint.CODE_93
BarcodeFormat.CODE_128 -> OSBARCScannerHint.CODE_128
BarcodeFormat.DATA_MATRIX -> OSBARCScannerHint.DATA_MATRIX
BarcodeFormat.MAXICODE -> OSBARCScannerHint.MAXICODE
BarcodeFormat.ITF -> OSBARCScannerHint.ITF
BarcodeFormat.EAN_13 -> OSBARCScannerHint.EAN_13
BarcodeFormat.EAN_8 -> OSBARCScannerHint.EAN_8
BarcodeFormat.PDF_417 -> OSBARCScannerHint.PDF_417
BarcodeFormat.RSS_14 -> OSBARCScannerHint.RSS_14
BarcodeFormat.RSS_EXPANDED -> OSBARCScannerHint.RSS_EXPANDED
BarcodeFormat.UPC_A -> OSBARCScannerHint.UPC_A
BarcodeFormat.UPC_E -> OSBARCScannerHint.UPC_E
BarcodeFormat.UPC_EAN_EXTENSION -> OSBARCScannerHint.UPC_EAN_EXTENSION

else -> OSBARCScannerHint.UNKNOWN
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.outsystems.plugins.barcode.controller.helper

import android.graphics.Bitmap
import com.outsystems.plugins.barcode.model.OSBARCScanResult

/**
* Interface that provides the signature of the type's methods.
Expand All @@ -11,7 +12,7 @@ interface OSBARCZXingHelperInterface {
pixels: IntArray,
width: Int,
height: Int,
onSuccess: (String) -> Unit,
onSuccess: (OSBARCScanResult) -> Unit,
onError: () -> Unit
)
}
Loading
Loading