react-native-rectangle-doc-scanner 3.227.0 → 3.229.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,8 +9,8 @@ import android.graphics.Matrix
9
9
  import android.graphics.Rect
10
10
  import android.graphics.YuvImage
11
11
  import android.util.Log
12
+ import android.util.Size
12
13
  import android.view.Surface
13
- import androidx.camera.core.AspectRatio
14
14
  import androidx.camera.core.Camera
15
15
  import androidx.camera.core.CameraSelector
16
16
  import androidx.camera.core.ImageAnalysis
@@ -44,6 +44,9 @@ class CameraController(
44
44
  private val lastFrame = AtomicReference<LastFrame?>()
45
45
  private var analysisBound = false
46
46
  private var pendingBindAttempts = 0
47
+ private var triedLowResFallback = false
48
+ private val streamCheckHandler = android.os.Handler(android.os.Looper.getMainLooper())
49
+ private var streamCheckRunnable: Runnable? = null
47
50
 
48
51
  private var useFrontCamera = false
49
52
  private var detectionEnabled = true
@@ -81,6 +84,7 @@ class CameraController(
81
84
  Log.d(TAG, "[CAMERAX-V6] startCamera called")
82
85
  this.useFrontCamera = useFrontCam
83
86
  this.detectionEnabled = enableDetection
87
+ triedLowResFallback = false
84
88
 
85
89
  if (!hasCameraPermission()) {
86
90
  Log.e(TAG, "[CAMERAX-V6] Camera permission not granted")
@@ -105,6 +109,7 @@ class CameraController(
105
109
  Log.d(TAG, "[CAMERAX-V6] stopCamera called")
106
110
  isAnalysisActive = false
107
111
  analysisHandler.removeCallbacks(analysisRunnable)
112
+ streamCheckRunnable?.let { streamCheckHandler.removeCallbacks(it) }
108
113
  cameraProvider?.unbindAll()
109
114
  analysisBound = false
110
115
  }
@@ -167,7 +172,7 @@ class CameraController(
167
172
  cameraExecutor.shutdown()
168
173
  }
169
174
 
170
- private fun bindCameraUseCases() {
175
+ private fun bindCameraUseCases(useLowRes: Boolean = false) {
171
176
  if (!previewView.isAttachedToWindow || previewView.width == 0 || previewView.height == 0) {
172
177
  if (pendingBindAttempts < 5) {
173
178
  pendingBindAttempts++
@@ -187,15 +192,16 @@ class CameraController(
187
192
 
188
193
  val rotation = previewView.display?.rotation ?: Surface.ROTATION_0
189
194
 
190
- // Build Preview without a fixed size to avoid unsupported stream configs.
191
- preview = Preview.Builder()
192
- .setTargetAspectRatio(AspectRatio.RATIO_4_3)
195
+ // Build Preview; fall back to a low-res stream if the default config stalls.
196
+ val previewBuilder = Preview.Builder()
193
197
  .setTargetRotation(rotation)
194
- .build()
195
- .also {
196
- // IMPORTANT: Set surface provider BEFORE binding
197
- it.setSurfaceProvider(previewView.surfaceProvider)
198
- }
198
+ if (useLowRes) {
199
+ previewBuilder.setTargetResolution(Size(640, 480))
200
+ }
201
+ preview = previewBuilder.build().also {
202
+ // IMPORTANT: Set surface provider BEFORE binding
203
+ it.setSurfaceProvider(previewView.surfaceProvider)
204
+ }
199
205
 
200
206
  val cameraSelector = if (useFrontCamera) {
201
207
  CameraSelector.DEFAULT_FRONT_CAMERA
@@ -211,19 +217,39 @@ class CameraController(
211
217
  preview
212
218
  )
213
219
 
214
- Log.d(TAG, "[CAMERAX-V9] Preview bound with 640x480 resolution")
215
- Log.d(TAG, "[CAMERAX-V9] Waiting for capture session to configure...")
220
+ if (useLowRes) {
221
+ Log.d(TAG, "[CAMERAX-V9] Preview bound with low-res fallback (640x480)")
222
+ } else {
223
+ Log.d(TAG, "[CAMERAX-V9] Preview bound, waiting for capture session to configure...")
224
+ }
216
225
 
217
226
  // Log session state after some time
218
227
  android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
219
228
  Log.d(TAG, "[CAMERAX-V9] Camera state check - preview should be working now")
220
229
  }, 6000)
221
230
 
231
+ scheduleStreamCheck(useLowRes)
222
232
  } catch (e: Exception) {
223
233
  Log.e(TAG, "[CAMERAX-V8] Failed to bind preview", e)
224
234
  }
225
235
  }
226
236
 
237
+ private fun scheduleStreamCheck(usingLowRes: Boolean) {
238
+ streamCheckRunnable?.let { streamCheckHandler.removeCallbacks(it) }
239
+ streamCheckRunnable = Runnable {
240
+ val state = previewView.previewStreamState.value
241
+ val streaming = state == PreviewView.StreamState.STREAMING
242
+ if (!streaming && !usingLowRes && !triedLowResFallback) {
243
+ triedLowResFallback = true
244
+ Log.w(TAG, "[CAMERAX-V9] Preview not streaming; retrying with low-res fallback")
245
+ bindCameraUseCases(useLowRes = true)
246
+ } else if (!streaming) {
247
+ Log.w(TAG, "[CAMERAX-V9] Preview still not streaming after fallback")
248
+ }
249
+ }
250
+ streamCheckHandler.postDelayed(streamCheckRunnable!!, 6500)
251
+ }
252
+
227
253
  // Function removed - this device cannot handle ImageCapture + Preview simultaneously
228
254
 
229
255
  private fun captureFrameForAnalysis() {
@@ -78,8 +78,8 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
78
78
  layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
79
79
  visibility = View.VISIBLE
80
80
  keepScreenOn = true
81
- // SurfaceView path is more stable on some devices during session config.
82
- implementationMode = PreviewView.ImplementationMode.PERFORMANCE
81
+ // TextureView mode avoids some device-specific Camera2 session timeouts.
82
+ implementationMode = PreviewView.ImplementationMode.COMPATIBLE
83
83
  scaleType = PreviewView.ScaleType.FILL_CENTER
84
84
  }
85
85
  Log.d(TAG, "[INIT] PreviewView created: $previewView")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "3.227.0",
3
+ "version": "3.229.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",