expo-camera 13.9.0 → 14.0.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/android/build.gradle +3 -3
  3. package/android/src/main/java/expo/modules/camera/Events.kt +1 -1
  4. package/android/src/main/java/expo/modules/camera/ExpoCameraView.kt +2 -2
  5. package/android/src/main/java/expo/modules/camera/next/CameraViewNextModule.kt +14 -5
  6. package/android/src/main/java/expo/modules/camera/next/ExpoCameraView.kt +56 -88
  7. package/android/src/main/java/expo/modules/camera/next/Options.kt +2 -2
  8. package/android/src/main/java/expo/modules/camera/next/analyzers/BarcodeAnalyzer.kt +1 -1
  9. package/android/src/main/java/expo/modules/camera/next/records/CameraRecords.kt +24 -1
  10. package/build/Camera.d.ts +4 -4
  11. package/build/Camera.d.ts.map +1 -1
  12. package/build/Camera.js +7 -7
  13. package/build/Camera.js.map +1 -1
  14. package/build/next/Camera.types.d.ts +42 -34
  15. package/build/next/Camera.types.d.ts.map +1 -1
  16. package/build/next/Camera.types.js +0 -12
  17. package/build/next/Camera.types.js.map +1 -1
  18. package/build/next/{Camera.d.ts → CameraView.d.ts} +8 -52
  19. package/build/next/CameraView.d.ts.map +1 -0
  20. package/build/next/{Camera.js → CameraView.js} +23 -92
  21. package/build/next/CameraView.js.map +1 -0
  22. package/build/next/index.d.ts +50 -2
  23. package/build/next/index.d.ts.map +1 -1
  24. package/build/next/index.js +71 -2
  25. package/build/next/index.js.map +1 -1
  26. package/build/next/utils/props.js +2 -2
  27. package/build/next/utils/props.js.map +1 -1
  28. package/ios/CameraRecordingOptions.swift +0 -1
  29. package/ios/CameraView.swift +8 -12
  30. package/ios/CameraViewModule.swift +4 -6
  31. package/ios/CameraViewNextModule.swift +73 -20
  32. package/ios/Next/BarcodeScanner.swift +61 -17
  33. package/ios/Next/CameraRecordingOptionsNext.swift +1 -0
  34. package/ios/Next/CameraViewNext.swift +48 -31
  35. package/package.json +2 -2
  36. package/src/Camera.tsx +7 -7
  37. package/src/next/Camera.types.ts +41 -33
  38. package/src/next/{Camera.tsx → CameraView.tsx} +27 -118
  39. package/src/next/index.ts +79 -5
  40. package/src/next/utils/props.ts +2 -2
  41. package/build/next/Camera.d.ts.map +0 -1
  42. package/build/next/Camera.js.map +0 -1
  43. package/ios/Next/Scanner+Delegates.swift +0 -52
package/CHANGELOG.md CHANGED
@@ -10,6 +10,16 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 14.0.0 — 2023-12-12
14
+
15
+ ### 🎉 New features
16
+
17
+ - Methods `stopRecording`, `pausePreview` and `resumePreview` have been updated to return promises. ([#25737](https://github.com/expo/expo/pull/25737) by [@lukmccall](https://github.com/lukmccall))
18
+
19
+ ### 💡 Others
20
+
21
+ - [iOS] Replace legacy `FileSystem` interfaces usage with core `FileSystemUtilities`. ([#25495](https://github.com/expo/expo/pull/25495) by [@alanhughes](https://github.com/alanjhughes))
22
+
13
23
  ## 13.9.0 — 2023-11-14
14
24
 
15
25
  ### 🛠 Breaking changes
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven-publish'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '13.9.0'
6
+ version = '14.0.0'
7
7
 
8
8
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
9
9
  if (expoModulesCorePlugin.exists()) {
@@ -94,7 +94,7 @@ android {
94
94
  namespace "expo.modules.camera"
95
95
  defaultConfig {
96
96
  versionCode 32
97
- versionName "13.9.0"
97
+ versionName "14.0.0"
98
98
  }
99
99
  }
100
100
 
@@ -111,7 +111,7 @@ dependencies {
111
111
  implementation project(':expo-modules-core')
112
112
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
113
113
  }
114
- def camerax_version = "1.3.0"
114
+ def camerax_version = "1.4.0-alpha02"
115
115
 
116
116
  api "androidx.exifinterface:exifinterface:1.3.6"
117
117
  api 'com.google.android:cameraview:1.0.0'
@@ -4,7 +4,7 @@ import android.os.Bundle
4
4
  import expo.modules.kotlin.records.Field
5
5
  import expo.modules.kotlin.records.Record
6
6
 
7
- data class BarCodeScannedEvent(
7
+ data class BarcodeScannedEvent(
8
8
  @Field val target: Int,
9
9
  @Field val data: String,
10
10
  @Field val type: Int,
@@ -63,7 +63,7 @@ class ExpoCameraView(
63
63
 
64
64
  private val onCameraReady by EventDispatcher<Unit>()
65
65
  private val onMountError by EventDispatcher<CameraMountErrorEvent>()
66
- private val onBarCodeScanned by EventDispatcher<BarCodeScannedEvent>(
66
+ private val onBarCodeScanned by EventDispatcher<BarcodeScannedEvent>(
67
67
  /**
68
68
  * We want every distinct barcode to be reported to the JS listener.
69
69
  * If we return some static value as a coalescing key there may be two barcode events
@@ -273,7 +273,7 @@ class ExpoCameraView(
273
273
  transformBarCodeScannerResultToViewCoordinates(barCode)
274
274
  val (cornerPoints, boundingBox) = getCornerPointsAndBoundingBox(barCode.cornerPoints, barCode.boundingBox)
275
275
  onBarCodeScanned(
276
- BarCodeScannedEvent(
276
+ BarcodeScannedEvent(
277
277
  target = id,
278
278
  data = barCode.value,
279
279
  type = barCode.type,
@@ -2,10 +2,11 @@ package expo.modules.camera.next
2
2
 
3
3
  import android.Manifest
4
4
  import android.util.Log
5
- import expo.modules.camera.next.records.BarCodeSettings
5
+ import expo.modules.camera.next.records.BarcodeSettings
6
6
  import expo.modules.camera.next.records.CameraMode
7
7
  import expo.modules.camera.next.records.CameraType
8
8
  import expo.modules.camera.next.records.FlashMode
9
+ import expo.modules.camera.next.records.VideoQuality
9
10
  import expo.modules.camera.next.tasks.ResolveTakenPicture
10
11
  import expo.modules.core.errors.ModuleDestroyedException
11
12
  import expo.modules.core.utilities.EmulatorUtilities
@@ -24,7 +25,7 @@ import java.io.File
24
25
  val cameraEvents = arrayOf(
25
26
  "onCameraReady",
26
27
  "onMountError",
27
- "onBarCodeScanned",
28
+ "onBarcodeScanned",
28
29
  "onFacesDetected",
29
30
  "onFaceDetectionError",
30
31
  "onPictureSaved"
@@ -104,15 +105,23 @@ class CameraViewNextModule : Module() {
104
105
  view.mute = muted ?: false
105
106
  }
106
107
 
107
- Prop("barCodeScannerSettings") { view, settings: BarCodeSettings? ->
108
+ Prop("videoQuality") { view, quality: VideoQuality? ->
109
+ if (quality != null) {
110
+ view.videoQuality = quality
111
+ } else {
112
+ view.videoQuality = VideoQuality.VIDEO1080P
113
+ }
114
+ }
115
+
116
+ Prop("barcodeScannerSettings") { view, settings: BarcodeSettings? ->
108
117
  if (settings == null) {
109
118
  return@Prop
110
119
  }
111
120
  view.setBarCodeScannerSettings(settings)
112
121
  }
113
122
 
114
- Prop("barCodeScannerEnabled") { view, barCodeScannerEnabled: Boolean? ->
115
- view.setShouldScanBarCodes(barCodeScannerEnabled ?: false)
123
+ Prop("barcodeScannerEnabled") { view, barCodeScannerEnabled: Boolean? ->
124
+ view.setShouldScanBarcodes(barCodeScannerEnabled ?: false)
116
125
  }
117
126
 
118
127
  AsyncFunction("takePicture") { view: ExpoCameraView, options: PictureOptions, promise: Promise ->
@@ -1,11 +1,11 @@
1
1
  package expo.modules.camera.next
2
2
 
3
+ import android.Manifest
3
4
  import android.annotation.SuppressLint
4
5
  import android.content.Context
5
- import android.graphics.Color
6
+ import android.content.pm.PackageManager
6
7
  import android.graphics.SurfaceTexture
7
8
  import android.hardware.camera2.CameraCharacteristics
8
- import android.hardware.camera2.CameraMetadata
9
9
  import android.os.Bundle
10
10
  import android.util.Log
11
11
  import android.view.View
@@ -14,36 +14,35 @@ import androidx.appcompat.app.AppCompatActivity
14
14
  import androidx.camera.camera2.interop.Camera2CameraInfo
15
15
  import androidx.camera.core.Camera
16
16
  import androidx.camera.core.CameraInfo
17
+ import androidx.camera.core.CameraSelector
17
18
  import androidx.camera.core.CameraState
18
19
  import androidx.camera.core.ImageAnalysis
19
20
  import androidx.camera.core.ImageCapture
20
21
  import androidx.camera.core.ImageCaptureException
21
22
  import androidx.camera.core.ImageProxy
22
- import androidx.camera.core.MirrorMode
23
23
  import androidx.camera.core.Preview
24
24
  import androidx.camera.core.UseCaseGroup
25
- import androidx.camera.core.resolutionselector.AspectRatioStrategy
26
- import androidx.camera.core.resolutionselector.ResolutionSelector
27
25
  import androidx.camera.lifecycle.ProcessCameraProvider
28
26
  import androidx.camera.video.FileOutputOptions
29
- import androidx.camera.video.Quality
30
27
  import androidx.camera.video.QualitySelector
31
28
  import androidx.camera.video.Recorder
32
29
  import androidx.camera.video.Recording
33
30
  import androidx.camera.video.VideoCapture
34
31
  import androidx.camera.video.VideoRecordEvent
35
32
  import androidx.camera.view.PreviewView
33
+ import androidx.core.app.ActivityCompat
36
34
  import androidx.core.content.ContextCompat
37
- import expo.modules.camera.BarCodeScannedEvent
35
+ import expo.modules.camera.BarcodeScannedEvent
38
36
  import expo.modules.camera.CameraMountErrorEvent
39
37
  import expo.modules.camera.PictureSavedEvent
40
38
  import expo.modules.camera.next.analyzers.BarcodeAnalyzer
41
39
  import expo.modules.camera.next.analyzers.toByteArray
42
- import expo.modules.camera.next.records.BarCodeSettings
40
+ import expo.modules.camera.next.records.BarcodeSettings
43
41
  import expo.modules.camera.next.records.BarcodeType
44
42
  import expo.modules.camera.next.records.CameraMode
45
43
  import expo.modules.camera.next.records.CameraType
46
44
  import expo.modules.camera.next.records.FlashMode
45
+ import expo.modules.camera.next.records.VideoQuality
47
46
  import expo.modules.camera.next.tasks.ResolveTakenPicture
48
47
  import expo.modules.camera.next.utils.FileSystemUtils
49
48
  import expo.modules.camera.utils.mapX
@@ -78,6 +77,7 @@ class ExpoCameraView(
78
77
  var camera: Camera? = null
79
78
  var activeRecording: Recording? = null
80
79
 
80
+ private val providerFuture = ProcessCameraProvider.getInstance(context)
81
81
  private var imageCaptureUseCase: ImageCapture? = null
82
82
  private var imageAnalysisUseCase: ImageAnalysis? = null
83
83
  private var recorder: Recorder? = null
@@ -98,11 +98,17 @@ class ExpoCameraView(
98
98
  createCamera()
99
99
  }
100
100
 
101
+ var videoQuality: VideoQuality = VideoQuality.VIDEO1080P
102
+ set(value) {
103
+ field = value
104
+ createCamera()
105
+ }
106
+
101
107
  var mute: Boolean = false
102
108
 
103
109
  private val onCameraReady by EventDispatcher<Unit>()
104
110
  private val onMountError by EventDispatcher<CameraMountErrorEvent>()
105
- private val onBarCodeScanned by EventDispatcher<BarCodeScannedEvent>(
111
+ private val onBarcodeScanned by EventDispatcher<BarcodeScannedEvent>(
106
112
  /**
107
113
  * We want every distinct barcode to be reported to the JS listener.
108
114
  * If we return some static value as a coalescing key there may be two barcode events
@@ -121,46 +127,22 @@ class ExpoCameraView(
121
127
  )
122
128
 
123
129
  // Scanning-related properties
124
- private var shouldScanBarCodes = false
130
+ private var shouldScanBarcodes = false
125
131
 
126
132
  override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
127
133
  val width = right - left
128
134
  val height = bottom - top
129
135
 
130
136
  previewView.layout(0, 0, width, height)
131
- previewView.setBackgroundColor(Color.BLACK)
132
- if (changed) {
133
- createCamera()
134
- }
137
+ postInvalidate(left, top, right, bottom)
135
138
  }
136
139
 
137
140
  override fun onViewAdded(child: View) {
138
- // react adds children to containers at the beginning of children list and that moves pre-react added preview to the end of that list
139
- // above would cause preview (TextureView that covers all available space) to be rendered at the top of children stack
140
- // while we need this preview to be rendered last beneath all other children
141
-
142
- // child is not preview
143
141
  if (previewView === child) {
144
142
  return
145
143
  }
146
-
147
- // bring to front all non-preview children
148
- val childrenToBeReordered = mutableListOf<View>()
149
- for (i in 0 until this.childCount) {
150
- val childView = getChildAt(i)
151
- if (i == 0 && childView === previewView) {
152
- // preview is already first in children list - do not reorder anything
153
- return
154
- }
155
- if (childView !== previewView) {
156
- childrenToBeReordered.add(childView)
157
- }
158
- }
159
- for (childView in childrenToBeReordered) {
160
- bringChildToFront(childView)
161
- }
162
- previewView.requestLayout()
163
- previewView.invalidate()
144
+ removeView(previewView)
145
+ addView(previewView, 0)
164
146
  }
165
147
 
166
148
  fun takePicture(options: PictureOptions, promise: Promise, cacheDirectory: File) {
@@ -195,7 +177,9 @@ class ExpoCameraView(
195
177
  }
196
178
 
197
179
  fun setTorchEnabled(enabled: Boolean) {
198
- camera?.cameraControl?.enableTorch(enabled)
180
+ if (camera?.cameraInfo?.hasFlashUnit() == true) {
181
+ camera?.cameraControl?.enableTorch(enabled)
182
+ }
199
183
  }
200
184
 
201
185
  fun record(options: RecordingOptions, promise: Promise, cacheDirectory: File) {
@@ -204,9 +188,12 @@ class ExpoCameraView(
204
188
  .setFileSizeLimit(options.maxFileSize.toLong())
205
189
  .setDurationLimitMillis(options.maxDuration.toLong())
206
190
  .build()
207
-
208
191
  recorder?.let {
192
+ if (ActivityCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
193
+ return
194
+ }
209
195
  activeRecording = it.prepareRecording(context, fileOutputOptions)
196
+ .withAudioEnabled()
210
197
  .start(ContextCompat.getMainExecutor(context)) { event ->
211
198
  when (event) {
212
199
  is VideoRecordEvent.Finalize -> {
@@ -235,8 +222,6 @@ class ExpoCameraView(
235
222
 
236
223
  @SuppressLint("UnsafeOptInUsageError")
237
224
  private fun createCamera() {
238
- val providerFuture = ProcessCameraProvider.getInstance(context)
239
-
240
225
  providerFuture.addListener(
241
226
  {
242
227
  val cameraProvider: ProcessCameraProvider = providerFuture.get()
@@ -247,7 +232,9 @@ class ExpoCameraView(
247
232
  it.setSurfaceProvider(previewView.surfaceProvider)
248
233
  }
249
234
 
250
- val cameraSelector = lenFacing.mapToSelector()
235
+ val cameraSelector = CameraSelector.Builder()
236
+ .requireLensFacing(lenFacing.mapToCharacteristic())
237
+ .build()
251
238
 
252
239
  imageCaptureUseCase = ImageCapture.Builder()
253
240
  .build()
@@ -255,7 +242,7 @@ class ExpoCameraView(
255
242
  val cameraInfo = cameraProvider.availableCameraInfos.filter {
256
243
  Camera2CameraInfo
257
244
  .from(it)
258
- .getCameraCharacteristic(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_BACK
245
+ .getCameraCharacteristic(CameraCharacteristics.LENS_FACING) == lenFacing.mapToCharacteristic()
259
246
  }
260
247
 
261
248
  val videoCapture = createVideoCapture(cameraInfo)
@@ -294,18 +281,13 @@ class ExpoCameraView(
294
281
  private fun createImageAnalyzer(): ImageAnalysis =
295
282
  ImageAnalysis.Builder()
296
283
  .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
297
- .setResolutionSelector(
298
- ResolutionSelector.Builder()
299
- .setAspectRatioStrategy(AspectRatioStrategy.RATIO_16_9_FALLBACK_AUTO_STRATEGY)
300
- .build()
301
- )
302
284
  .build()
303
285
  .also { analyzer ->
304
- if (shouldScanBarCodes) {
286
+ if (shouldScanBarcodes) {
305
287
  analyzer.setAnalyzer(
306
288
  ContextCompat.getMainExecutor(context),
307
289
  BarcodeAnalyzer(lenFacing, barcodeFormats) {
308
- onBarCodeScanned(it)
290
+ onBarcodeScanned(it)
309
291
  }
310
292
  )
311
293
  }
@@ -313,9 +295,9 @@ class ExpoCameraView(
313
295
 
314
296
  private fun createVideoCapture(info: List<CameraInfo>): VideoCapture<Recorder> {
315
297
  val supportedQualities = QualitySelector.getSupportedQualities(info[0])
316
-
317
- val filteredQualities = arrayListOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD)
298
+ val filteredQualities = arrayListOf(videoQuality.mapToQuality())
318
299
  .filter { supportedQualities.contains(it) }
300
+
319
301
  val qualitySelector = QualitySelector.fromOrderedList(filteredQualities)
320
302
 
321
303
  val recorder = Recorder.Builder()
@@ -327,7 +309,7 @@ class ExpoCameraView(
327
309
  }
328
310
 
329
311
  return VideoCapture.Builder(recorder)
330
- .setMirrorMode(MirrorMode.MIRROR_MODE_ON_FRONT_ONLY)
312
+ .setVideoStabilizationEnabled(true)
331
313
  .build()
332
314
  }
333
315
 
@@ -337,29 +319,26 @@ class ExpoCameraView(
337
319
  CameraState.Type.OPEN -> {
338
320
  onCameraReady(Unit)
339
321
  }
322
+
340
323
  else -> {}
341
324
  }
342
325
  }
343
326
  }
344
327
 
345
- fun setShouldScanBarCodes(shouldScanBarCodes: Boolean) {
346
- this.shouldScanBarCodes = shouldScanBarCodes
328
+ fun setShouldScanBarcodes(shouldScanBarCodes: Boolean) {
329
+ this.shouldScanBarcodes = shouldScanBarCodes
347
330
  createCamera()
348
331
  }
349
332
 
350
- fun setBarCodeScannerSettings(settings: BarCodeSettings?) {
333
+ fun setBarCodeScannerSettings(settings: BarcodeSettings?) {
351
334
  barcodeFormats = settings?.barcodeTypes ?: emptyList()
352
- createCamera()
353
335
  }
354
336
 
355
337
  private fun getDeviceOrientation() =
356
338
  (context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.rotation
357
339
 
358
- private fun transformBarCodeScannerResultToViewCoordinates(barCode: BarCodeScannerResult) {
359
- val cornerPoints = barCode.cornerPoints
360
-
361
- val cameraWidth = barCode.referenceImageHeight
362
- val cameraHeight = barCode.referenceImageWidth
340
+ private fun transformBarcodeScannerResultToViewCoordinates(barcode: BarCodeScannerResult) {
341
+ val cornerPoints = barcode.cornerPoints
363
342
  val previewWidth = previewView.width
364
343
  val previewHeight = previewView.height
365
344
 
@@ -368,33 +347,24 @@ class ExpoCameraView(
368
347
  val landscape = getDeviceOrientation() % 2 != 0
369
348
 
370
349
  if (facingFront && portrait) {
371
- cornerPoints.mapY { barCode.referenceImageHeight - cornerPoints[it] }
350
+ cornerPoints.mapY { barcode.referenceImageHeight - cornerPoints[it] }
372
351
  }
373
352
  if (facingFront && landscape) {
374
- cornerPoints.mapX { barCode.referenceImageWidth - cornerPoints[it] }
375
- }
376
-
377
- val scaleX = if (portrait) {
378
- previewWidth / cameraHeight.toFloat()
379
- } else {
380
- previewWidth / cameraWidth.toFloat()
381
- }
382
- val scaleY = if (portrait) {
383
- previewHeight / cameraWidth.toFloat()
384
- } else {
385
- previewHeight / cameraHeight.toFloat()
353
+ cornerPoints.mapX { barcode.referenceImageWidth - cornerPoints[it] }
386
354
  }
387
355
 
388
356
  cornerPoints.mapX {
389
- (cornerPoints[it] * scaleX)
357
+ (cornerPoints[it] * previewWidth / barcode.referenceImageWidth.toFloat())
390
358
  .roundToInt()
391
359
  }
392
360
  cornerPoints.mapY {
393
- (cornerPoints[it] * scaleY)
361
+ (cornerPoints[it] * previewHeight / barcode.referenceImageHeight.toFloat())
394
362
  .roundToInt()
395
363
  }
396
364
 
397
- barCode.cornerPoints = cornerPoints
365
+ barcode.cornerPoints = cornerPoints
366
+ barcode.referenceImageHeight = height
367
+ barcode.referenceImageWidth = width
398
368
  }
399
369
 
400
370
  private fun getCornerPointsAndBoundingBox(cornerPoints: List<Int>, boundingBox: BoundingBox): Pair<ArrayList<Bundle>, Bundle> {
@@ -429,15 +399,15 @@ class ExpoCameraView(
429
399
  return convertedCornerPoints to boundingBoxBundle
430
400
  }
431
401
 
432
- private fun onBarCodeScanned(barCode: BarCodeScannerResult) {
433
- if (shouldScanBarCodes) {
434
- transformBarCodeScannerResultToViewCoordinates(barCode)
435
- val (cornerPoints, boundingBox) = getCornerPointsAndBoundingBox(barCode.cornerPoints, barCode.boundingBox)
436
- onBarCodeScanned(
437
- BarCodeScannedEvent(
402
+ private fun onBarcodeScanned(barcode: BarCodeScannerResult) {
403
+ if (shouldScanBarcodes) {
404
+ transformBarcodeScannerResultToViewCoordinates(barcode)
405
+ val (cornerPoints, boundingBox) = getCornerPointsAndBoundingBox(barcode.cornerPoints, barcode.boundingBox)
406
+ onBarcodeScanned(
407
+ BarcodeScannedEvent(
438
408
  target = id,
439
- data = barCode.value,
440
- type = barCode.type,
409
+ data = barcode.value,
410
+ type = barcode.type,
441
411
  cornerPoints = cornerPoints,
442
412
  boundingBox = boundingBox
443
413
  )
@@ -450,7 +420,6 @@ class ExpoCameraView(
450
420
  override fun getPreviewSizeAsArray() = intArrayOf(previewView.width, previewView.height)
451
421
 
452
422
  init {
453
- isChildrenDrawingOrderEnabled = true
454
423
  previewView.setOnHierarchyChangeListener(object : OnHierarchyChangeListener {
455
424
  override fun onChildViewRemoved(parent: View?, child: View?) = Unit
456
425
  override fun onChildViewAdded(parent: View?, child: View?) {
@@ -462,7 +431,6 @@ class ExpoCameraView(
462
431
  }
463
432
  })
464
433
  addView(previewView)
465
- createCamera()
466
434
  }
467
435
 
468
436
  fun onPictureSaved(response: Bundle) {
@@ -1,6 +1,6 @@
1
1
  package expo.modules.camera.next
2
2
 
3
- import android.media.CamcorderProfile
3
+ import expo.modules.camera.next.records.VideoQuality
4
4
  import expo.modules.kotlin.records.Field
5
5
  import expo.modules.kotlin.records.Record
6
6
 
@@ -18,5 +18,5 @@ data class PictureOptions(
18
18
  data class RecordingOptions(
19
19
  @Field val maxDuration: Int = 0,
20
20
  @Field val maxFileSize: Int = 0,
21
- @Field val quality: Int = CamcorderProfile.QUALITY_HIGH
21
+ @Field val quality: VideoQuality?
22
22
  ) : Record
@@ -16,7 +16,7 @@ import expo.modules.interfaces.barcodescanner.BarCodeScannerResult
16
16
  import java.nio.ByteBuffer
17
17
 
18
18
  @OptIn(ExperimentalGetImage::class)
19
- class BarcodeAnalyzer(private val lensFacing: CameraType, private val formats: List<BarcodeType>, val onComplete: (BarCodeScannerResult) -> Unit) : ImageAnalysis.Analyzer {
19
+ class BarcodeAnalyzer(private val lensFacing: CameraType, formats: List<BarcodeType>, val onComplete: (BarCodeScannerResult) -> Unit) : ImageAnalysis.Analyzer {
20
20
  private val barcodeFormats = if (formats.isEmpty()) 0 else formats.map { it.mapToBarcode() }.reduce { acc, it ->
21
21
  acc or it
22
22
  }
@@ -1,7 +1,9 @@
1
1
  package expo.modules.camera.next.records
2
2
 
3
+ import android.hardware.camera2.CameraMetadata
3
4
  import androidx.camera.core.CameraSelector
4
5
  import androidx.camera.core.ImageCapture
6
+ import androidx.camera.video.Quality
5
7
  import com.google.mlkit.vision.barcode.common.Barcode
6
8
  import expo.modules.kotlin.records.Record
7
9
  import expo.modules.kotlin.types.Enumerable
@@ -14,6 +16,27 @@ enum class CameraType(val value: String) : Enumerable {
14
16
  FRONT -> CameraSelector.DEFAULT_FRONT_CAMERA
15
17
  BACK -> CameraSelector.DEFAULT_BACK_CAMERA
16
18
  }
19
+
20
+ fun mapToCharacteristic() = when (this) {
21
+ FRONT -> CameraMetadata.LENS_FACING_FRONT
22
+ BACK -> CameraMetadata.LENS_FACING_BACK
23
+ }
24
+ }
25
+
26
+ enum class VideoQuality(val value: String) : Enumerable {
27
+ VIDEO2160P("2160p"),
28
+ VIDEO1080P("1080p"),
29
+ VIDEO720P("720p"),
30
+ VIDEO480P("480p"),
31
+ VIDEO4X3("4:3");
32
+
33
+ fun mapToQuality(): Quality = when (this) {
34
+ VIDEO2160P -> Quality.UHD
35
+ VIDEO1080P -> Quality.FHD
36
+ VIDEO720P -> Quality.HD
37
+ VIDEO480P -> Quality.SD
38
+ VIDEO4X3 -> Quality.LOWEST
39
+ }
17
40
  }
18
41
 
19
42
  enum class FlashMode(val value: String) : Enumerable {
@@ -33,7 +56,7 @@ enum class CameraMode(val value: String) : Enumerable {
33
56
  VIDEO("video")
34
57
  }
35
58
 
36
- data class BarCodeSettings(
59
+ data class BarcodeSettings(
37
60
  val barcodeTypes: List<BarcodeType>,
38
61
  val interval: Double?
39
62
  ) : Record
package/build/Camera.d.ts CHANGED
@@ -102,7 +102,7 @@ export default class Camera extends React.Component<CameraProps> {
102
102
  * for an `Image` element for example. `exif` is included if the `exif` option was truthy, and is an object containing EXIF
103
103
  * data for the image--the names of its properties are EXIF tags and their values are the values for those tags.
104
104
  *
105
- * > On native platforms, the local image URI is temporary. Use [`FileSystem.copyAsync`](filesystem.md#filesystemcopyasyncoptions)
105
+ * > On native platforms, the local image URI is temporary. Use [`FileSystem.copyAsync`](filesystem/#filesystemcachedirectory)
106
106
  * > to make a permanent copy of the image.
107
107
  */
108
108
  takePictureAsync(options?: CameraPictureOptions): Promise<CameraCapturedPicture>;
@@ -134,15 +134,15 @@ export default class Camera extends React.Component<CameraProps> {
134
134
  /**
135
135
  * Stops recording if any is in progress.
136
136
  */
137
- stopRecording(): void;
137
+ stopRecording(): Promise<void>;
138
138
  /**
139
139
  * Pauses the camera preview. It is not recommended to use `takePictureAsync` when preview is paused.
140
140
  */
141
- pausePreview(): void;
141
+ pausePreview(): Promise<void>;
142
142
  /**
143
143
  * Resumes the camera preview.
144
144
  */
145
- resumePreview(): void;
145
+ resumePreview(): Promise<void>;
146
146
  _onCameraReady: () => void;
147
147
  _onMountError: ({ nativeEvent }: {
148
148
  nativeEvent: {
@@ -1 +1 @@
1
- {"version":3,"file":"Camera.d.ts","sourceRoot":"","sources":["../src/Camera.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,EACX,sBAAsB,EACtB,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,UAAU,EACX,MAAM,gBAAgB,CAAC;AAoDxB,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC;IAC9D;;;;;OAKG;WACU,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAQjD;;;OAGG;WACU,4BAA4B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IASlE;;;;OAIG;WACU,4BAA4B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAQlE,MAAM,CAAC,SAAS,EAAE,aAAa,CAQ7B;IAGF,MAAM,CAAC,gBAAgB;;;;;MAAoB;IAE3C,MAAM,CAAC,YAAY,EAAE,WAAW,CAS9B;IAGF;;;OAGG;WACU,mBAAmB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAQ/D;;;;;OAKG;WACU,uBAAuB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAQnE;;;OAGG;WACU,yBAAyB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKrE;;;;OAIG;WACU,6BAA6B,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKzE;;;;;;;;OAQG;IACH,MAAM,CAAC,oBAAoB,yLAGxB;IAGH;;;OAGG;WACU,6BAA6B,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKzE;;;;OAIG;WACU,iCAAiC,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAK7E;;;;;;;;OAQG;IACH,MAAM,CAAC,wBAAwB,yLAG5B;IAEH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;IACpC,WAAW,EAAE;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAM;IAClD,gBAAgB,EAAE;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAM;IAGrD;;;;;;;;;;;;;;;OAeG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAMtF;;;;OAIG;IACG,uBAAuB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAQlD;;;;;OAKG;IACG,6BAA6B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAOrE;;;;;;;;OAQG;IACG,WAAW,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAS7E;;OAEG;IACH,aAAa;IAQb;;OAEG;IACH,YAAY;IAQZ;;OAEG;IACH,aAAa;IAQb,cAAc,aAIZ;IAEF,aAAa;qBAAoC;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE;eAIlE;IAEF,+BAA+B;qBAGhB;YAAE,aAAa,iBAAiB,CAAA;SAAE;eAK/C;IAEF,iBAAiB,cACH,QAAQ;qBACa,GAAG;eAgBlC;IAEJ,aAAa,SAAU,MAAM,SAAS,UAapC;IAEF,MAAM;CAsBP;AAED,eAAO,MACL,SAAS,iBACT,mBAAmB,qCACnB,uBAAuB,yCACvB,yBAAyB,2CACzB,6BAA6B,+CAC7B,6BAA6B,+CAC7B,iCAAiC,iDACzB,CAAC"}
1
+ {"version":3,"file":"Camera.d.ts","sourceRoot":"","sources":["../src/Camera.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,EACX,sBAAsB,EACtB,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,UAAU,EACX,MAAM,gBAAgB,CAAC;AAoDxB,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC;IAC9D;;;;;OAKG;WACU,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAQjD;;;OAGG;WACU,4BAA4B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IASlE;;;;OAIG;WACU,4BAA4B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAQlE,MAAM,CAAC,SAAS,EAAE,aAAa,CAQ7B;IAGF,MAAM,CAAC,gBAAgB;;;;;MAAoB;IAE3C,MAAM,CAAC,YAAY,EAAE,WAAW,CAS9B;IAGF;;;OAGG;WACU,mBAAmB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAQ/D;;;;;OAKG;WACU,uBAAuB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAQnE;;;OAGG;WACU,yBAAyB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKrE;;;;OAIG;WACU,6BAA6B,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKzE;;;;;;;;OAQG;IACH,MAAM,CAAC,oBAAoB,yLAGxB;IAGH;;;OAGG;WACU,6BAA6B,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKzE;;;;OAIG;WACU,iCAAiC,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAK7E;;;;;;;;OAQG;IACH,MAAM,CAAC,wBAAwB,yLAG5B;IAEH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;IACpC,WAAW,EAAE;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAM;IAClD,gBAAgB,EAAE;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAM;IAGrD;;;;;;;;;;;;;;;OAeG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAMtF;;;;OAIG;IACG,uBAAuB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAQlD;;;;;OAKG;IACG,6BAA6B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAOrE;;;;;;;;OAQG;IACG,WAAW,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAS7E;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAQpC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAQnC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAQpC,cAAc,aAIZ;IAEF,aAAa;qBAAoC;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE;eAIlE;IAEF,+BAA+B;qBAGhB;YAAE,aAAa,iBAAiB,CAAA;SAAE;eAK/C;IAEF,iBAAiB,cACH,QAAQ;qBACa,GAAG;eAgBlC;IAEJ,aAAa,SAAU,MAAM,SAAS,UAapC;IAEF,MAAM;CAsBP;AAED,eAAO,MACL,SAAS,iBACT,mBAAmB,qCACnB,uBAAuB,yCACvB,yBAAyB,2CACzB,6BAA6B,+CAC7B,6BAA6B,+CAC7B,iCAAiC,iDACzB,CAAC"}
package/build/Camera.js CHANGED
@@ -194,7 +194,7 @@ export default class Camera extends React.Component {
194
194
  * for an `Image` element for example. `exif` is included if the `exif` option was truthy, and is an object containing EXIF
195
195
  * data for the image--the names of its properties are EXIF tags and their values are the values for those tags.
196
196
  *
197
- * > On native platforms, the local image URI is temporary. Use [`FileSystem.copyAsync`](filesystem.md#filesystemcopyasyncoptions)
197
+ * > On native platforms, the local image URI is temporary. Use [`FileSystem.copyAsync`](filesystem/#filesystemcachedirectory)
198
198
  * > to make a permanent copy of the image.
199
199
  */
200
200
  async takePictureAsync(options) {
@@ -243,29 +243,29 @@ export default class Camera extends React.Component {
243
243
  /**
244
244
  * Stops recording if any is in progress.
245
245
  */
246
- stopRecording() {
246
+ async stopRecording() {
247
247
  if (!CameraManager.stopRecording) {
248
248
  throw new UnavailabilityError('Camera', 'stopRecording');
249
249
  }
250
- CameraManager.stopRecording(this._cameraHandle);
250
+ return await CameraManager.stopRecording(this._cameraHandle);
251
251
  }
252
252
  /**
253
253
  * Pauses the camera preview. It is not recommended to use `takePictureAsync` when preview is paused.
254
254
  */
255
- pausePreview() {
255
+ async pausePreview() {
256
256
  if (!CameraManager.pausePreview) {
257
257
  throw new UnavailabilityError('Camera', 'pausePreview');
258
258
  }
259
- CameraManager.pausePreview(this._cameraHandle);
259
+ return await CameraManager.pausePreview(this._cameraHandle);
260
260
  }
261
261
  /**
262
262
  * Resumes the camera preview.
263
263
  */
264
- resumePreview() {
264
+ async resumePreview() {
265
265
  if (!CameraManager.resumePreview) {
266
266
  throw new UnavailabilityError('Camera', 'resumePreview');
267
267
  }
268
- CameraManager.resumePreview(this._cameraHandle);
268
+ return await CameraManager.resumePreview(this._cameraHandle);
269
269
  }
270
270
  _onCameraReady = () => {
271
271
  if (this.props.onCameraReady) {