expo-camera 16.0.15 → 16.0.16

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.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,10 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 16.0.16 — 2025-02-10
14
+
15
+ _This version does not introduce any user-facing changes._
16
+
13
17
  ## 16.0.15 — 2025-02-06
14
18
 
15
19
  _This version does not introduce any user-facing changes._
@@ -36,6 +40,8 @@ _This version does not introduce any user-facing changes._
36
40
  - [Android] Fix an issue where the camera image is pixelated when using the gl integration. ([#34174](https://github.com/expo/expo/pull/34174) by [@alanjhughes](https://github.com/alanjhughes))
37
41
  - [Android] Fix setting the camera preview provider. ([#34302](https://github.com/expo/expo/pull/34302) by [@alanjhughes](https://github.com/alanjhughes))
38
42
  - [iOS] Fix initial roation when used with `react-native-screens`. ([#34721](https://github.com/expo/expo/pull/34721) by [@alanjhughes](https://github.com/alanjhughes))
43
+ - [iOS] Fix performance regression. ([#34750](https://github.com/expo/expo/pull/34750) by [@alanjhughes](https://github.com/alanjhughes))
44
+ - [Android] Attempt to fix `setLinearZoom` incompatability with some devices. ([#34757](https://github.com/expo/expo/pull/34757) by [@alanjhughes](https://github.com/alanjhughes))
39
45
 
40
46
  ## 16.0.10 — 2024-12-16
41
47
 
@@ -1,7 +1,7 @@
1
1
  apply plugin: 'com.android.library'
2
2
 
3
3
  group = 'host.exp.exponent'
4
- version = '16.0.15'
4
+ version = '16.0.16'
5
5
 
6
6
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7
7
  apply from: expoModulesCorePlugin
@@ -14,7 +14,7 @@ android {
14
14
  namespace "expo.modules.camera"
15
15
  defaultConfig {
16
16
  versionCode 32
17
- versionName "16.0.15"
17
+ versionName "16.0.16"
18
18
  }
19
19
  }
20
20
 
@@ -81,6 +81,8 @@ import kotlinx.coroutines.Dispatchers
81
81
  import kotlinx.coroutines.cancel
82
82
  import kotlinx.coroutines.launch
83
83
  import java.io.File
84
+ import java.lang.Float.max
85
+ import java.lang.Float.min
84
86
  import kotlin.math.roundToInt
85
87
  import kotlin.properties.Delegates
86
88
 
@@ -150,7 +152,7 @@ class ExpoCameraView(
150
152
  var zoom: Float = 0f
151
153
  set(value) {
152
154
  field = value
153
- camera?.cameraControl?.setLinearZoom(value.coerceIn(0f, 1f))
155
+ setCameraZoom(value)
154
156
  }
155
157
 
156
158
  var autoFocus: FocusMode = FocusMode.OFF
@@ -431,7 +433,7 @@ class ExpoCameraView(
431
433
  observeCameraState(it.cameraInfo)
432
434
  }
433
435
  // Set the previous zoom level after recreating the camera
434
- camera?.cameraControl?.setLinearZoom(zoom.coerceIn(0f, 1f))
436
+ setCameraZoom(zoom)
435
437
  this.cameraProvider = cameraProvider
436
438
  } catch (e: Exception) {
437
439
  onMountError(
@@ -544,6 +546,12 @@ class ExpoCameraView(
544
546
  }
545
547
  }
546
548
 
549
+ private fun setCameraZoom(value: Float) {
550
+ val maxZoomRatio = camera?.cameraInfo?.zoomState?.value?.maxZoomRatio ?: 1f
551
+ val targetZoomRatio = max(1f, min(maxZoomRatio, value.coerceIn(0f, 1f) * maxZoomRatio))
552
+ camera?.cameraControl?.setZoomRatio(targetZoomRatio)
553
+ }
554
+
547
555
  private fun observeCameraState(cameraInfo: CameraInfo) {
548
556
  cameraInfo.cameraState.observe(currentActivity) {
549
557
  when (it.type) {
@@ -76,27 +76,48 @@ public final class CameraViewModule: Module, ScannerResultHandler {
76
76
  if let type, view.presetCamera != type.toPosition() {
77
77
  view.presetCamera = type.toPosition()
78
78
  }
79
+ // the prop has been removed, reset to default
80
+ if type == nil && view.presetCamera != .back {
81
+ view.presetCamera = .back
82
+ }
79
83
  }
80
84
 
81
85
  Prop("flashMode") { (view, flashMode: FlashMode?) in
82
86
  if let flashMode, view.flashMode != flashMode {
83
87
  view.flashMode = flashMode
84
88
  }
89
+ if flashMode == nil && view.flashMode != .auto {
90
+ view.flashMode = .auto
91
+ }
85
92
  }
86
93
 
87
94
  Prop("enableTorch") { (view, enabled: Bool?) in
88
- view.torchEnabled = enabled ?? false
95
+ if let enabled, view.torchEnabled != enabled {
96
+ view.torchEnabled = enabled
97
+ return
98
+ }
99
+ if enabled == nil && view.torchEnabled {
100
+ view.torchEnabled = false
101
+ }
89
102
  }
90
103
 
91
104
  Prop("pictureSize") { (view, pictureSize: PictureSize?) in
92
105
  if let pictureSize, view.pictureSize != pictureSize {
93
106
  view.pictureSize = pictureSize
107
+ return
108
+ }
109
+ if pictureSize == nil && view.pictureSize != .high {
110
+ view.pictureSize = .high
94
111
  }
95
112
  }
96
113
 
97
114
  Prop("zoom") { (view, zoom: Double?) in
98
115
  if let zoom, fabs(view.zoom - zoom) > Double.ulpOfOne {
99
116
  view.zoom = zoom
117
+ return
118
+ }
119
+ if zoom == nil && view.zoom != 0 {
120
+ view.zoom = 0
100
121
  }
101
122
  }
102
123
 
@@ -104,11 +125,18 @@ public final class CameraViewModule: Module, ScannerResultHandler {
104
125
  if let mode, view.mode != mode {
105
126
  view.mode = mode
106
127
  }
128
+ if mode == nil && view.mode != .picture {
129
+ view.mode = .picture
130
+ }
107
131
  }
108
132
 
109
133
  Prop("barcodeScannerEnabled") { (view, scanBarcodes: Bool?) in
110
134
  if let scanBarcodes, view.isScanningBarcodes != scanBarcodes {
111
135
  view.isScanningBarcodes = scanBarcodes
136
+ return
137
+ }
138
+ if scanBarcodes == nil && view.isScanningBarcodes != false {
139
+ view.isScanningBarcodes = false
112
140
  }
113
141
  }
114
142
 
@@ -119,56 +147,71 @@ public final class CameraViewModule: Module, ScannerResultHandler {
119
147
  }
120
148
 
121
149
  Prop("mute") { (view, muted: Bool?) in
122
- view.isMuted = muted ?? false
150
+ if let muted, view.isMuted != muted {
151
+ view.isMuted = muted
152
+ return
153
+ }
154
+ if muted == nil && view.isMuted != false {
155
+ view.isMuted = false
156
+ }
123
157
  }
124
158
 
125
159
  Prop("animateShutter") { (view, animate: Bool?) in
160
+ // Does not call anything that immediately causes any configuration changes
161
+ // so it's fine to just set it
126
162
  view.animateShutter = animate ?? true
127
163
  }
128
164
 
129
165
  Prop("videoQuality") { (view, quality: VideoQuality?) in
130
- view.videoQuality = quality ?? .video1080p
166
+ if let quality, view.videoQuality != quality {
167
+ view.videoQuality = quality
168
+ return
169
+ }
170
+ if quality == nil && view.videoQuality != .video1080p {
171
+ view.videoQuality = .video1080p
172
+ }
131
173
  }
132
174
 
133
175
  Prop("autoFocus") { (view, focusMode: FocusMode?) in
134
- view.autoFocus = focusMode?.toAVCaptureFocusMode() ?? .continuousAutoFocus
176
+ if let focusMode, view.autoFocus != focusMode.toAVCaptureFocusMode() {
177
+ view.autoFocus = focusMode.toAVCaptureFocusMode()
178
+ return
179
+ }
180
+ if focusMode == nil && view.autoFocus != .continuousAutoFocus {
181
+ view.autoFocus = .continuousAutoFocus
182
+ }
135
183
  }
136
184
 
137
185
  Prop("responsiveOrientationWhenOrientationLocked") { (view, responsiveOrientation: Bool?) in
138
186
  if let responsiveOrientation, view.responsiveWhenOrientationLocked != responsiveOrientation {
139
187
  view.responsiveWhenOrientationLocked = responsiveOrientation
188
+ return
189
+ }
190
+ if responsiveOrientation == nil && view.responsiveWhenOrientationLocked != false {
191
+ view.responsiveWhenOrientationLocked = false
140
192
  }
141
193
  }
142
194
 
143
195
  Prop("mirror") { (view, mirror: Bool?) in
144
- if let mirror {
145
- view.mirror = mirror
146
- return
147
- }
148
- view.mirror = false
196
+ // Does not call anything that immediately causes any configuration changes
197
+ // so it's fine to just set it
198
+ view.mirror = mirror ?? false
149
199
  }
150
200
 
151
201
  Prop("active") { (view, active: Bool?) in
152
- if let active {
202
+ if let active, view.active != active {
153
203
  view.active = active
154
204
  return
155
205
  }
156
- }
157
-
158
- Prop("videoBitrate") { (view, bitrate: Int?) in
159
- if let bitrate {
160
- view.videoBitrate = bitrate
161
- return
162
- }
163
- if view.videoBitrate != nil {
164
- view.videoBitrate = nil
206
+ if active == nil && view.active != true {
207
+ view.active = true
165
208
  }
166
209
  }
167
210
 
168
- OnViewDidUpdateProps { view in
169
- Task {
170
- await view.initCamera()
171
- }
211
+ Prop("videoBitrate") { (view, bitrate: Int?) in
212
+ // Does not call anything that immediately causes any configuration changes
213
+ // so it's fine to just set it
214
+ view.videoBitrate = bitrate
172
215
  }
173
216
 
174
217
  AsyncFunction("resumePreview") { view in
@@ -108,9 +108,6 @@ actor BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
108
108
  }
109
109
 
110
110
  private func addOutputs() async {
111
- session.beginConfiguration()
112
- defer { session.commitConfiguration() }
113
-
114
111
  delegate = MetaDataDelegate(
115
112
  settings: settings,
116
113
  previewLayer: previewLayer,
@@ -118,6 +115,7 @@ actor BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
118
115
  zxingEnabled: zxingEnabled,
119
116
  metadataResultHandler: self)
120
117
 
118
+ session.beginConfiguration()
121
119
  if metadataOutput == nil {
122
120
  let output = AVCaptureMetadataOutput()
123
121
  output.setMetadataObjectsDelegate(delegate, queue: sessionQueue)
@@ -137,6 +135,7 @@ actor BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
137
135
  videoDataOutput = output
138
136
  }
139
137
  }
138
+ session.commitConfiguration()
140
139
  }
141
140
 
142
141
  private func removeOutputs() async {
@@ -26,7 +26,6 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
26
26
  mm.gyroUpdateInterval = 0.2
27
27
  return mm
28
28
  }()
29
- private var cameraShouldInit = true
30
29
  private var isSessionPaused = false
31
30
 
32
31
  // MARK: Property Observers
@@ -39,8 +38,8 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
39
38
 
40
39
  var videoQuality: VideoQuality = .video1080p {
41
40
  didSet {
42
- Task {
43
- await updateSessionPreset(preset: videoQuality.toPreset())
41
+ sessionQueue.async {
42
+ self.updateSessionPreset(preset: self.videoQuality.toPreset())
44
43
  }
45
44
  }
46
45
  }
@@ -57,7 +56,9 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
57
56
 
58
57
  var presetCamera = AVCaptureDevice.Position.back {
59
58
  didSet {
60
- updateType()
59
+ sessionQueue.async {
60
+ self.updateDevice()
61
+ }
61
62
  }
62
63
  }
63
64
 
@@ -77,31 +78,31 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
77
78
 
78
79
  var pictureSize = PictureSize.high {
79
80
  didSet {
80
- Task {
81
- await updatePictureSize()
82
- }
81
+ updatePictureSize()
83
82
  }
84
83
  }
85
84
 
86
85
  var mode = CameraMode.picture {
87
86
  didSet {
88
- Task {
89
- await setCameraMode()
87
+ sessionQueue.async {
88
+ self.setCameraMode()
90
89
  }
91
90
  }
92
91
  }
93
92
 
94
93
  var isMuted = false {
95
94
  didSet {
96
- Task {
97
- await updateSessionAudioIsMuted()
95
+ sessionQueue.async {
96
+ self.updateSessionAudioIsMuted()
98
97
  }
99
98
  }
100
99
  }
101
100
 
102
101
  var active = true {
103
102
  didSet {
104
- updateCameraIsActive()
103
+ sessionQueue.async {
104
+ self.updateCameraIsActive()
105
+ }
105
106
  }
106
107
  }
107
108
 
@@ -154,6 +155,7 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
154
155
  name: UIDevice.orientationDidChangeNotification,
155
156
  object: nil)
156
157
  lifecycleManager?.register(self)
158
+ initializeCaptureSessionInput()
157
159
  }
158
160
 
159
161
  private func setupPreview() {
@@ -161,44 +163,51 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
161
163
  previewLayer.needsDisplayOnBoundsChange = true
162
164
  }
163
165
 
164
- func initCamera() async {
165
- guard cameraShouldInit else {
166
+ private func updateDevice() {
167
+ guard let device = ExpoCameraUtils.device(with: .video, preferring: presetCamera) else {
166
168
  return
167
169
  }
168
- cameraShouldInit = false
169
- await initializeCaptureSessionInput()
170
- }
171
170
 
172
- private func updateType() {
173
- cameraShouldInit = true
171
+ session.beginConfiguration()
172
+ defer { session.commitConfiguration() }
173
+ if let captureDeviceInput {
174
+ session.removeInput(captureDeviceInput)
175
+ }
176
+
177
+ do {
178
+ let deviceInput = try AVCaptureDeviceInput(device: device)
179
+ if session.canAddInput(deviceInput) {
180
+ session.addInput(deviceInput)
181
+ captureDeviceInput = deviceInput
182
+ updateZoom()
183
+ }
184
+ } catch {
185
+ onMountError(["message": "Camera could not be started - \(error.localizedDescription)"])
186
+ }
174
187
  }
175
188
 
176
189
  public func onAppForegrounded() {
177
190
  if !session.isRunning && isSessionPaused {
178
191
  isSessionPaused = false
179
- sessionQueue.async {
180
- self.session.startRunning()
181
- self.enableTorch()
182
- }
192
+ session.startRunning()
193
+ enableTorch()
183
194
  }
184
195
  }
185
196
 
186
197
  public func onAppBackgrounded() {
187
198
  if session.isRunning && !isSessionPaused {
188
199
  isSessionPaused = true
189
- sessionQueue.async {
190
- self.session.stopRunning()
191
- }
200
+ session.stopRunning()
192
201
  }
193
202
  }
194
203
 
195
- private func updatePictureSize() async {
204
+ private func updatePictureSize() {
196
205
  #if !targetEnvironment(simulator)
197
- session.beginConfiguration()
198
- defer { session.commitConfiguration() }
199
- let preset = pictureSize.toCapturePreset()
200
- if session.canSetSessionPreset(preset) {
201
- session.sessionPreset = preset
206
+ sessionQueue.async {
207
+ let preset = self.pictureSize.toCapturePreset()
208
+ if self.session.canSetSessionPreset(preset) {
209
+ self.session.sessionPreset = preset
210
+ }
202
211
  }
203
212
  #endif
204
213
  }
@@ -236,18 +245,18 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
236
245
  device.unlockForConfiguration()
237
246
  }
238
247
 
239
- private func setCameraMode() async {
248
+ private func setCameraMode() {
240
249
  if mode == .video {
241
250
  if videoFileOutput == nil {
242
- await setupMovieFileCapture()
251
+ setupMovieFileCapture()
243
252
  }
244
- await updateSessionAudioIsMuted()
253
+ updateSessionAudioIsMuted()
245
254
  } else {
246
- await cleanupMovieFileCapture()
255
+ cleanupMovieFileCapture()
247
256
  }
248
257
  }
249
258
 
250
- private func startSession() async {
259
+ private func startSession() {
251
260
  #if targetEnvironment(simulator)
252
261
  return
253
262
  #else
@@ -262,17 +271,19 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
262
271
 
263
272
  let photoOutput = AVCapturePhotoOutput()
264
273
  photoOutput.isLivePhotoCaptureEnabled = false
274
+ session.beginConfiguration()
265
275
  if session.canAddOutput(photoOutput) {
266
276
  session.addOutput(photoOutput)
267
277
  self.photoOutput = photoOutput
268
278
  }
269
279
 
270
280
  session.sessionPreset = mode == .video ? pictureSize.toCapturePreset() : .photo
271
- addErrorNotification()
272
- await changePreviewOrientation()
273
-
274
- await barcodeScanner?.maybeStartBarcodeScanning()
275
281
  session.commitConfiguration()
282
+ addErrorNotification()
283
+ changePreviewOrientation()
284
+ Task.detached(priority: .userInitiated, operation: {
285
+ await self.barcodeScanner?.maybeStartBarcodeScanning()
286
+ })
276
287
  updateCameraIsActive()
277
288
  onCameraReady()
278
289
  enableTorch()
@@ -303,7 +314,9 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
303
314
  if !session.isRunning {
304
315
  session.startRunning()
305
316
  }
306
- await updateSessionAudioIsMuted()
317
+ sessionQueue.async {
318
+ self.updateSessionAudioIsMuted()
319
+ }
307
320
  onCameraReady()
308
321
  }
309
322
  }
@@ -593,14 +606,14 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
593
606
  self.videoCodecType = codecType
594
607
  } else {
595
608
  promise.reject(CameraRecordingException(options.codec?.rawValue))
596
- await cleanupMovieFileCapture()
609
+ cleanupMovieFileCapture()
597
610
  videoRecordedPromise = nil
598
611
  isValidVideoOptions = false
599
612
  }
600
613
  }
601
614
  }
602
615
 
603
- func updateSessionAudioIsMuted() async {
616
+ func updateSessionAudioIsMuted() {
604
617
  session.beginConfiguration()
605
618
  defer { session.commitConfiguration() }
606
619
 
@@ -629,21 +642,17 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
629
642
  }
630
643
  }
631
644
 
632
- func setupMovieFileCapture() async {
645
+ func setupMovieFileCapture() {
633
646
  let output = AVCaptureMovieFileOutput()
634
647
  if session.canAddOutput(output) {
635
- session.beginConfiguration()
636
- defer { session.commitConfiguration() }
637
648
  session.addOutput(output)
638
649
  videoFileOutput = output
639
650
  }
640
651
  }
641
652
 
642
- func cleanupMovieFileCapture() async {
653
+ func cleanupMovieFileCapture() {
643
654
  if let videoFileOutput {
644
655
  if session.outputs.contains(videoFileOutput) {
645
- session.beginConfiguration()
646
- defer { session.commitConfiguration() }
647
656
  session.removeOutput(videoFileOutput)
648
657
  self.videoFileOutput = nil
649
658
  }
@@ -659,8 +668,8 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
659
668
 
660
669
  public override func removeFromSuperview() {
661
670
  super.removeFromSuperview()
662
- Task {
663
- await stopSession()
671
+ sessionQueue.async {
672
+ self.stopSession()
664
673
  }
665
674
  lifecycleManager?.unregisterAppLifecycleListener(self)
666
675
  UIDevice.current.endGeneratingDeviceOrientationNotifications()
@@ -704,15 +713,11 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
704
713
  videoCodecType = nil
705
714
  }
706
715
 
707
- func setPresetCamera(presetCamera: AVCaptureDevice.Position) {
708
- self.presetCamera = presetCamera
709
- }
710
-
711
716
  func stopRecording() {
712
717
  videoFileOutput?.stopRecording()
713
718
  }
714
719
 
715
- func updateSessionPreset(preset: AVCaptureSession.Preset) async {
720
+ func updateSessionPreset(preset: AVCaptureSession.Preset) {
716
721
  #if !targetEnvironment(simulator)
717
722
  if session.canSetSessionPreset(preset) {
718
723
  if session.sessionPreset != preset {
@@ -720,36 +725,25 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
720
725
  defer { session.commitConfiguration() }
721
726
  session.sessionPreset = preset
722
727
  }
728
+ } else {
729
+ // The selected preset cannot be used on the current device so we fall back to the highest available.
730
+ if session.sessionPreset != .high {
731
+ session.beginConfiguration()
732
+ defer { session.commitConfiguration() }
733
+ session.sessionPreset = .high
734
+ }
723
735
  }
724
736
  #endif
725
737
  }
726
738
 
727
- func initializeCaptureSessionInput() async {
728
- session.beginConfiguration()
729
-
730
- guard let device = ExpoCameraUtils.device(with: .video, preferring: presetCamera) else {
731
- return
732
- }
733
-
734
- if let captureDeviceInput {
735
- session.removeInput(captureDeviceInput)
736
- }
737
-
738
- do {
739
- let deviceInput = try AVCaptureDeviceInput(device: device)
740
-
741
- if session.canAddInput(deviceInput) {
742
- session.addInput(deviceInput)
743
- captureDeviceInput = deviceInput
744
- updateZoom()
745
- }
746
- } catch {
747
- onMountError(["message": "Camera could not be started - \(error.localizedDescription)"])
739
+ func initializeCaptureSessionInput() {
740
+ sessionQueue.async {
741
+ self.updateDevice()
742
+ self.startSession()
748
743
  }
749
- await startSession()
750
744
  }
751
745
 
752
- private func stopSession() async {
746
+ private func stopSession() {
753
747
  #if targetEnvironment(simulator)
754
748
  return
755
749
  #else
@@ -761,7 +755,9 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
761
755
  for output in session.outputs {
762
756
  session.removeOutput(output)
763
757
  }
764
- await barcodeScanner?.stopBarcodeScanning()
758
+ Task {
759
+ await barcodeScanner?.stopBarcodeScanning()
760
+ }
765
761
  session.commitConfiguration()
766
762
 
767
763
  motionManager.stopAccelerometerUpdates()
@@ -785,13 +781,14 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
785
781
  }
786
782
  }
787
783
 
788
- @MainActor
789
- func changePreviewOrientation() async {
784
+ func changePreviewOrientation() {
790
785
  // We shouldn't access the device orientation anywhere but on the main thread
791
- let videoOrientation = ExpoCameraUtils.videoOrientation(for: deviceOrientation)
792
- if (previewLayer.connection?.isVideoOrientationSupported) == true {
793
- physicalOrientation = ExpoCameraUtils.physicalOrientation(for: deviceOrientation)
794
- previewLayer.connection?.videoOrientation = videoOrientation
786
+ Task { @MainActor in
787
+ let videoOrientation = ExpoCameraUtils.videoOrientation(for: deviceOrientation)
788
+ if (previewLayer.connection?.isVideoOrientationSupported) == true {
789
+ physicalOrientation = ExpoCameraUtils.physicalOrientation(for: deviceOrientation)
790
+ previewLayer.connection?.videoOrientation = videoOrientation
791
+ }
795
792
  }
796
793
  }
797
794
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-camera",
3
- "version": "16.0.15",
3
+ "version": "16.0.16",
4
4
  "description": "A React component that renders a preview for the device's either front or back camera. Camera's parameters like zoom, auto focus, white balance and flash mode are adjustable. With expo-camera, one can also take photos and record videos that are saved to the app's cache. Morever, the component is also capable of detecting faces and bar codes appearing on the preview.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -50,5 +50,5 @@
50
50
  "optional": true
51
51
  }
52
52
  },
53
- "gitHead": "9442f00874e0cd738030abae80e5bdef184a2581"
53
+ "gitHead": "81941fa03383e748ba1b6345d9ca0d048bb5c4d1"
54
54
  }