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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
* Fixed a leak of the barcode scanner on Android.
* [Android] Fixed a leak of the barcode scanner.
* [Android] Fixed a crash when encountering invalid numbers for the scan window.

## 5.1.1
* This release fixes an issue with automatic starts in the examples.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,25 +170,35 @@ class MobileScanner(
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}

// scales the scanWindow to the provided inputImage and checks if that scaled
// scanWindow contains the barcode
private fun isBarcodeInScanWindow(
// Scales the scanWindow to the provided inputImage and checks if that scaled
// scanWindow contains the barcode.
@VisibleForTesting
fun isBarcodeInScanWindow(
scanWindow: List<Float>,
barcode: Barcode,
inputImage: ImageProxy
): Boolean {
// TODO: use `cornerPoints` instead, since the bounding box is not bound to the coordinate system of the input image
// On iOS we do this correctly, so the calculation should match that.
val barcodeBoundingBox = barcode.boundingBox ?: return false

val imageWidth = inputImage.height
val imageHeight = inputImage.width
try {
val imageWidth = inputImage.height
val imageHeight = inputImage.width

val left = (scanWindow[0] * imageWidth).roundToInt()
val top = (scanWindow[1] * imageHeight).roundToInt()
val right = (scanWindow[2] * imageWidth).roundToInt()
val bottom = (scanWindow[3] * imageHeight).roundToInt()
val left = (scanWindow[0] * imageWidth).roundToInt()
val top = (scanWindow[1] * imageHeight).roundToInt()
val right = (scanWindow[2] * imageWidth).roundToInt()
val bottom = (scanWindow[3] * imageHeight).roundToInt()

val scaledScanWindow = Rect(left, top, right, bottom)
return scaledScanWindow.contains(barcodeBoundingBox)
val scaledScanWindow = Rect(left, top, right, bottom)

return scaledScanWindow.contains(barcodeBoundingBox)
} catch (exception: IllegalArgumentException) {
// Rounding of the scan window dimensions can fail, due to encountering NaN.
// If we get NaN, rather than give a false positive, just return false.
return false
}
}

// Return the best resolution for the actual device orientation.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dev.steenbakker.mobile_scanner

import android.app.Activity
import android.graphics.Rect
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScanner
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.common.Barcode
import kotlin.test.Test
import org.mockito.Mockito
import io.flutter.view.TextureRegistry
import kotlin.test.expect

/*
* This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
*
* Once you have built the plugin's example app, you can run these tests from the command
* line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
* you can run them directly from IDEs that support JUnit such as Android Studio.
*/

internal class MobileScannerTest {
@Test
fun isBarcodeInScanWindow_canHandleNaNValues() {
val barcodeScannerMock = Mockito.mock(BarcodeScanner::class.java)

val mobileScanner = MobileScanner(
Mockito.mock(Activity::class.java),
Mockito.mock(TextureRegistry::class.java),
{ _: List<Map<String, Any?>>, _: ByteArray?, _: Int?, _: Int? -> },
{ _: String -> },
{ _: BarcodeScannerOptions? -> barcodeScannerMock }
)

// Intentional suppression for the mock value in the test,
// since there is no NaN constant.
@Suppress("DIVISION_BY_ZERO")
val notANumber = 0.0f / 0.0f

val barcodeMock: Barcode = Mockito.mock(Barcode::class.java)
val imageMock: ImageProxy = Mockito.mock(ImageProxy::class.java)

// TODO: use corner points instead of bounding box

// Bounding box that is 100 pixels offset from the left and top,
// and is 100 pixels in width and height.
Mockito.`when`(barcodeMock.boundingBox).thenReturn(
Rect(100, 100, 200, 300))
Mockito.`when`(imageMock.height).thenReturn(400)
Mockito.`when`(imageMock.width).thenReturn(400)

// Use a scan window that has an invalid value, but otherwise uses the entire image.
val scanWindow: List<Float> = listOf(0f, notANumber, 100f, 100f)

expect(false) {
mobileScanner.isBarcodeInScanWindow(scanWindow, barcodeMock, imageMock)
}
}
}