Showing
7 changed files
with
68 additions
and
16 deletions
| 1 | package dev.steenbakker.mobile_scanner | 1 | package dev.steenbakker.mobile_scanner |
| 2 | 2 | ||
| 3 | import android.app.Activity | 3 | import android.app.Activity |
| 4 | +import android.content.Context | ||
| 4 | import android.graphics.Bitmap | 5 | import android.graphics.Bitmap |
| 5 | import android.graphics.Matrix | 6 | import android.graphics.Matrix |
| 6 | import android.graphics.Rect | 7 | import android.graphics.Rect |
| 8 | +import android.hardware.display.DisplayManager | ||
| 7 | import android.net.Uri | 9 | import android.net.Uri |
| 10 | +import android.os.Build | ||
| 8 | import android.os.Handler | 11 | import android.os.Handler |
| 9 | import android.os.Looper | 12 | import android.os.Looper |
| 13 | +import android.util.Size | ||
| 10 | import android.view.Surface | 14 | import android.view.Surface |
| 11 | -import androidx.camera.core.* | 15 | +import android.view.WindowManager |
| 16 | +import androidx.camera.core.Camera | ||
| 17 | +import androidx.camera.core.CameraSelector | ||
| 18 | +import androidx.camera.core.ExperimentalGetImage | ||
| 19 | +import androidx.camera.core.ImageAnalysis | ||
| 20 | +import androidx.camera.core.ImageProxy | ||
| 21 | +import androidx.camera.core.Preview | ||
| 22 | +import androidx.camera.core.resolutionselector.AspectRatioStrategy | ||
| 23 | +import androidx.camera.core.resolutionselector.ResolutionSelector | ||
| 24 | +import androidx.camera.core.resolutionselector.ResolutionStrategy | ||
| 12 | import androidx.camera.lifecycle.ProcessCameraProvider | 25 | import androidx.camera.lifecycle.ProcessCameraProvider |
| 13 | import androidx.core.content.ContextCompat | 26 | import androidx.core.content.ContextCompat |
| 14 | import androidx.lifecycle.LifecycleOwner | 27 | import androidx.lifecycle.LifecycleOwner |
| @@ -22,11 +35,7 @@ import dev.steenbakker.mobile_scanner.utils.YuvToRgbConverter | @@ -22,11 +35,7 @@ import dev.steenbakker.mobile_scanner.utils.YuvToRgbConverter | ||
| 22 | import io.flutter.view.TextureRegistry | 35 | import io.flutter.view.TextureRegistry |
| 23 | import java.io.ByteArrayOutputStream | 36 | import java.io.ByteArrayOutputStream |
| 24 | import kotlin.math.roundToInt | 37 | import kotlin.math.roundToInt |
| 25 | -import android.util.Size | ||
| 26 | -import android.hardware.display.DisplayManager | ||
| 27 | -import android.view.WindowManager | ||
| 28 | -import android.content.Context | ||
| 29 | -import android.os.Build | 38 | + |
| 30 | 39 | ||
| 31 | class MobileScanner( | 40 | class MobileScanner( |
| 32 | private val activity: Activity, | 41 | private val activity: Activity, |
| @@ -216,7 +225,8 @@ class MobileScanner( | @@ -216,7 +225,8 @@ class MobileScanner( | ||
| 216 | mobileScannerStartedCallback: MobileScannerStartedCallback, | 225 | mobileScannerStartedCallback: MobileScannerStartedCallback, |
| 217 | mobileScannerErrorCallback: (exception: Exception) -> Unit, | 226 | mobileScannerErrorCallback: (exception: Exception) -> Unit, |
| 218 | detectionTimeout: Long, | 227 | detectionTimeout: Long, |
| 219 | - cameraResolution: Size? | 228 | + cameraResolution: Size?, |
| 229 | + newCameraResolutionSelector: Boolean | ||
| 220 | ) { | 230 | ) { |
| 221 | this.detectionSpeed = detectionSpeed | 231 | this.detectionSpeed = detectionSpeed |
| 222 | this.detectionTimeout = detectionTimeout | 232 | this.detectionTimeout = detectionTimeout |
| @@ -277,9 +287,19 @@ class MobileScanner( | @@ -277,9 +287,19 @@ class MobileScanner( | ||
| 277 | val displayManager = activity.applicationContext.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager | 287 | val displayManager = activity.applicationContext.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager |
| 278 | 288 | ||
| 279 | if (cameraResolution != null) { | 289 | if (cameraResolution != null) { |
| 280 | - // TODO: migrate to ResolutionSelector with ResolutionStrategy when upgrading to camera 1.3.0 | ||
| 281 | - // Override initial resolution | ||
| 282 | - analysisBuilder.setTargetResolution(getResolution(cameraResolution)) | 290 | + if (newCameraResolutionSelector) { |
| 291 | + val selectorBuilder = ResolutionSelector.Builder() | ||
| 292 | + selectorBuilder.setResolutionStrategy( | ||
| 293 | + ResolutionStrategy( | ||
| 294 | + cameraResolution, | ||
| 295 | + ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER | ||
| 296 | + ) | ||
| 297 | + ) | ||
| 298 | + analysisBuilder.setResolutionSelector(selectorBuilder.build()).build() | ||
| 299 | + } else { | ||
| 300 | + @Suppress("DEPRECATION") | ||
| 301 | + analysisBuilder.setTargetResolution(getResolution(cameraResolution)) | ||
| 302 | + } | ||
| 283 | 303 | ||
| 284 | if (displayListener == null) { | 304 | if (displayListener == null) { |
| 285 | displayListener = object : DisplayManager.DisplayListener { | 305 | displayListener = object : DisplayManager.DisplayListener { |
| @@ -288,7 +308,19 @@ class MobileScanner( | @@ -288,7 +308,19 @@ class MobileScanner( | ||
| 288 | override fun onDisplayRemoved(displayId: Int) {} | 308 | override fun onDisplayRemoved(displayId: Int) {} |
| 289 | 309 | ||
| 290 | override fun onDisplayChanged(displayId: Int) { | 310 | override fun onDisplayChanged(displayId: Int) { |
| 291 | - analysisBuilder.setTargetResolution(getResolution(cameraResolution)) | 311 | + if (newCameraResolutionSelector) { |
| 312 | + val selectorBuilder = ResolutionSelector.Builder() | ||
| 313 | + selectorBuilder.setResolutionStrategy( | ||
| 314 | + ResolutionStrategy( | ||
| 315 | + cameraResolution, | ||
| 316 | + ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER | ||
| 317 | + ) | ||
| 318 | + ) | ||
| 319 | + analysisBuilder.setResolutionSelector(selectorBuilder.build()).build() | ||
| 320 | + } else { | ||
| 321 | + @Suppress("DEPRECATION") | ||
| 322 | + analysisBuilder.setTargetResolution(getResolution(cameraResolution)) | ||
| 323 | + } | ||
| 292 | } | 324 | } |
| 293 | } | 325 | } |
| 294 | 326 |
| @@ -137,6 +137,7 @@ class MobileScannerHandler( | @@ -137,6 +137,7 @@ class MobileScannerHandler( | ||
| 137 | val speed: Int = call.argument<Int>("speed") ?: 1 | 137 | val speed: Int = call.argument<Int>("speed") ?: 1 |
| 138 | val timeout: Int = call.argument<Int>("timeout") ?: 250 | 138 | val timeout: Int = call.argument<Int>("timeout") ?: 250 |
| 139 | val cameraResolutionValues: List<Int>? = call.argument<List<Int>>("cameraResolution") | 139 | val cameraResolutionValues: List<Int>? = call.argument<List<Int>>("cameraResolution") |
| 140 | + val useNewCameraSelector: Boolean = call.argument<Boolean>("useNewCameraSelector") ?: false | ||
| 140 | val cameraResolution: Size? = if (cameraResolutionValues != null) { | 141 | val cameraResolution: Size? = if (cameraResolutionValues != null) { |
| 141 | Size(cameraResolutionValues[0], cameraResolutionValues[1]) | 142 | Size(cameraResolutionValues[0], cameraResolutionValues[1]) |
| 142 | } else { | 143 | } else { |
| @@ -219,6 +220,7 @@ class MobileScannerHandler( | @@ -219,6 +220,7 @@ class MobileScannerHandler( | ||
| 219 | }, | 220 | }, |
| 220 | timeout.toLong(), | 221 | timeout.toLong(), |
| 221 | cameraResolution, | 222 | cameraResolution, |
| 223 | + useNewCameraSelector | ||
| 222 | ) | 224 | ) |
| 223 | } | 225 | } |
| 224 | 226 |
| @@ -17,7 +17,7 @@ class _BarcodeScannerWithControllerState | @@ -17,7 +17,7 @@ class _BarcodeScannerWithControllerState | ||
| 17 | BarcodeCapture? barcode; | 17 | BarcodeCapture? barcode; |
| 18 | 18 | ||
| 19 | final MobileScannerController controller = MobileScannerController( | 19 | final MobileScannerController controller = MobileScannerController( |
| 20 | - torchEnabled: true, | 20 | + torchEnabled: true, useNewCameraSelector: true, |
| 21 | // formats: [BarcodeFormat.qrCode] | 21 | // formats: [BarcodeFormat.qrCode] |
| 22 | // facing: CameraFacing.front, | 22 | // facing: CameraFacing.front, |
| 23 | // detectionSpeed: DetectionSpeed.normal | 23 | // detectionSpeed: DetectionSpeed.normal |
| @@ -16,7 +16,7 @@ class _BarcodeScannerReturningImageState | @@ -16,7 +16,7 @@ class _BarcodeScannerReturningImageState | ||
| 16 | extends State<BarcodeScannerReturningImage> | 16 | extends State<BarcodeScannerReturningImage> |
| 17 | with SingleTickerProviderStateMixin { | 17 | with SingleTickerProviderStateMixin { |
| 18 | BarcodeCapture? barcode; | 18 | BarcodeCapture? barcode; |
| 19 | - MobileScannerArguments? arguments; | 19 | + // MobileScannerArguments? arguments; |
| 20 | 20 | ||
| 21 | final MobileScannerController controller = MobileScannerController( | 21 | final MobileScannerController controller = MobileScannerController( |
| 22 | torchEnabled: true, | 22 | torchEnabled: true, |
| @@ -225,12 +225,22 @@ class _MobileScannerState extends State<MobileScanner> | @@ -225,12 +225,22 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 225 | return Stack( | 225 | return Stack( |
| 226 | alignment: Alignment.center, | 226 | alignment: Alignment.center, |
| 227 | children: [ | 227 | children: [ |
| 228 | - _scanner(value.size, value.webId, value.textureId, value.nrOfCameras), | 228 | + _scanner( |
| 229 | + value.size, | ||
| 230 | + value.webId, | ||
| 231 | + value.textureId, | ||
| 232 | + value.nrOfCameras, | ||
| 233 | + ), | ||
| 229 | widget.overlay!, | 234 | widget.overlay!, |
| 230 | ], | 235 | ], |
| 231 | ); | 236 | ); |
| 232 | } else { | 237 | } else { |
| 233 | - return _scanner(value.size, value.webId, value.textureId, value.nrOfCameras); | 238 | + return _scanner( |
| 239 | + value.size, | ||
| 240 | + value.webId, | ||
| 241 | + value.textureId, | ||
| 242 | + value.nrOfCameras, | ||
| 243 | + ); | ||
| 234 | } | 244 | } |
| 235 | }, | 245 | }, |
| 236 | ); | 246 | ); |
| @@ -23,6 +23,7 @@ class MobileScannerController { | @@ -23,6 +23,7 @@ class MobileScannerController { | ||
| 23 | this.onPermissionSet, | 23 | this.onPermissionSet, |
| 24 | this.autoStart = true, | 24 | this.autoStart = true, |
| 25 | this.cameraResolution, | 25 | this.cameraResolution, |
| 26 | + this.useNewCameraSelector = false, | ||
| 26 | }); | 27 | }); |
| 27 | 28 | ||
| 28 | /// Select which camera should be used. | 29 | /// Select which camera should be used. |
| @@ -74,6 +75,12 @@ class MobileScannerController { | @@ -74,6 +75,12 @@ class MobileScannerController { | ||
| 74 | /// Currently only supported on Android. | 75 | /// Currently only supported on Android. |
| 75 | final Size? cameraResolution; | 76 | final Size? cameraResolution; |
| 76 | 77 | ||
| 78 | + /// Use the new resolution selector. Warning: not fully tested, may produce | ||
| 79 | + /// unwanted/zoomed images. | ||
| 80 | + /// | ||
| 81 | + /// Only supported on Android | ||
| 82 | + final bool useNewCameraSelector; | ||
| 83 | + | ||
| 77 | /// Sets the barcode stream | 84 | /// Sets the barcode stream |
| 78 | final StreamController<BarcodeCapture> _barcodesController = | 85 | final StreamController<BarcodeCapture> _barcodesController = |
| 79 | StreamController.broadcast(); | 86 | StreamController.broadcast(); |
| @@ -136,6 +143,7 @@ class MobileScannerController { | @@ -136,6 +143,7 @@ class MobileScannerController { | ||
| 136 | arguments['speed'] = detectionSpeed.rawValue; | 143 | arguments['speed'] = detectionSpeed.rawValue; |
| 137 | arguments['timeout'] = detectionTimeoutMs; | 144 | arguments['timeout'] = detectionTimeoutMs; |
| 138 | arguments['returnImage'] = returnImage; | 145 | arguments['returnImage'] = returnImage; |
| 146 | + arguments['useNewCameraSelector'] = useNewCameraSelector; | ||
| 139 | 147 | ||
| 140 | /* if (scanWindow != null) { | 148 | /* if (scanWindow != null) { |
| 141 | arguments['scanWindow'] = [ | 149 | arguments['scanWindow'] = [ |
-
Please register or login to post a comment