expo-camera 12.0.2 → 12.1.2

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 (55) hide show
  1. package/CHANGELOG.md +23 -2
  2. package/README.md +1 -1
  3. package/android/build.gradle +22 -19
  4. package/android/src/main/java/expo/modules/camera/CameraModule.kt +217 -0
  5. package/android/src/main/java/expo/modules/camera/CameraPackage.kt +10 -0
  6. package/android/src/main/java/expo/modules/camera/CameraViewHelper.kt +139 -0
  7. package/android/src/main/java/expo/modules/camera/CameraViewManager.kt +116 -0
  8. package/android/src/main/java/expo/modules/camera/Constants.kt +184 -0
  9. package/android/src/main/java/expo/modules/camera/ExpoCameraView.kt +329 -0
  10. package/android/src/main/java/expo/modules/camera/events/BarCodeScannedEvent.kt +50 -0
  11. package/android/src/main/java/expo/modules/camera/events/CameraMountErrorEvent.kt +33 -0
  12. package/android/src/main/java/expo/modules/camera/events/CameraReadyEvent.kt +23 -0
  13. package/android/src/main/java/expo/modules/camera/events/FaceDetectionErrorEvent.kt +39 -0
  14. package/android/src/main/java/expo/modules/camera/events/FacesDetectedEvent.kt +46 -0
  15. package/android/src/main/java/expo/modules/camera/events/PictureSavedEvent.kt +41 -0
  16. package/android/src/main/java/expo/modules/camera/tasks/BarCodeScannerAsyncTask.kt +26 -0
  17. package/android/src/main/java/expo/modules/camera/tasks/BarCodeScannerAsyncTaskDelegate.kt +8 -0
  18. package/android/src/main/java/expo/modules/camera/tasks/FaceDetectorAsyncTaskDelegate.kt +10 -0
  19. package/android/src/main/java/expo/modules/camera/tasks/FaceDetectorTask.kt +34 -0
  20. package/android/src/main/java/expo/modules/camera/tasks/PictureSavedDelegate.kt +7 -0
  21. package/android/src/main/java/expo/modules/camera/tasks/ResolveTakenPictureAsyncTask.kt +231 -0
  22. package/android/src/main/java/expo/modules/camera/utils/FileSystemUtils.kt +23 -0
  23. package/android/src/main/java/expo/modules/camera/utils/ImageDimensions.kt +14 -0
  24. package/build/ExponentCameraManager.web.js +3 -1
  25. package/build/ExponentCameraManager.web.js.map +1 -1
  26. package/ios/EXCamera.xcframework/ios-arm64/EXCamera.framework/EXCamera +0 -0
  27. package/ios/EXCamera.xcframework/ios-arm64/EXCamera.framework/Info.plist +0 -0
  28. package/ios/EXCamera.xcframework/ios-arm64_x86_64-simulator/EXCamera.framework/EXCamera +0 -0
  29. package/ios/EXCamera.xcframework/ios-arm64_x86_64-simulator/EXCamera.framework/Info.plist +0 -0
  30. package/package.json +7 -5
  31. package/plugin/build/withCamera.d.ts +2 -1
  32. package/plugin/build/withCamera.js +50 -30
  33. package/plugin/src/withCamera.ts +66 -27
  34. package/src/ExponentCameraManager.web.ts +3 -2
  35. package/src/{types → ts-declarations}/image-capture.d.ts +0 -0
  36. package/src/ts-declarations/lib.dom.d.ts +34 -0
  37. package/android/src/main/java/expo/modules/camera/CameraModule.java +0 -359
  38. package/android/src/main/java/expo/modules/camera/CameraPackage.java +0 -23
  39. package/android/src/main/java/expo/modules/camera/CameraViewHelper.java +0 -294
  40. package/android/src/main/java/expo/modules/camera/CameraViewManager.java +0 -142
  41. package/android/src/main/java/expo/modules/camera/ExpoCameraView.java +0 -376
  42. package/android/src/main/java/expo/modules/camera/events/BarCodeScannedEvent.java +0 -59
  43. package/android/src/main/java/expo/modules/camera/events/CameraMountErrorEvent.java +0 -38
  44. package/android/src/main/java/expo/modules/camera/events/CameraReadyEvent.java +0 -30
  45. package/android/src/main/java/expo/modules/camera/events/FaceDetectionErrorEvent.java +0 -50
  46. package/android/src/main/java/expo/modules/camera/events/FacesDetectedEvent.java +0 -63
  47. package/android/src/main/java/expo/modules/camera/events/PictureSavedEvent.java +0 -53
  48. package/android/src/main/java/expo/modules/camera/tasks/BarCodeScannerAsyncTask.java +0 -47
  49. package/android/src/main/java/expo/modules/camera/tasks/BarCodeScannerAsyncTaskDelegate.java +0 -8
  50. package/android/src/main/java/expo/modules/camera/tasks/FaceDetectorAsyncTaskDelegate.java +0 -13
  51. package/android/src/main/java/expo/modules/camera/tasks/FaceDetectorTask.java +0 -53
  52. package/android/src/main/java/expo/modules/camera/tasks/PictureSavedDelegate.java +0 -7
  53. package/android/src/main/java/expo/modules/camera/tasks/ResolveTakenPictureAsyncTask.java +0 -288
  54. package/android/src/main/java/expo/modules/camera/utils/FileSystemUtils.java +0 -21
  55. package/android/src/main/java/expo/modules/camera/utils/ImageDimensions.java +0 -64
@@ -0,0 +1,184 @@
1
+ package expo.modules.camera
2
+
3
+ import androidx.exifinterface.media.ExifInterface
4
+ import com.google.android.cameraview.Constants
5
+
6
+ const val REACT_CLASS = "ExponentCamera"
7
+ const val TAG = "ExponentCameraModule"
8
+ const val ERROR_TAG = "E_CAMERA"
9
+
10
+ const val VIDEO_2160P = 0
11
+ const val VIDEO_1080P = 1
12
+ const val VIDEO_720P = 2
13
+ const val VIDEO_480P = 3
14
+ const val VIDEO_4x3 = 4
15
+
16
+ val typeConstants = mapOf(
17
+ "front" to Constants.FACING_FRONT,
18
+ "back" to Constants.FACING_BACK
19
+ )
20
+
21
+ val flashModeConstants = mapOf(
22
+ "off" to Constants.FLASH_OFF,
23
+ "on" to Constants.FLASH_ON,
24
+ "auto" to Constants.FLASH_AUTO,
25
+ "torch" to Constants.FLASH_TORCH
26
+ )
27
+
28
+ val autoFocusConstants = mapOf(
29
+ "on" to true,
30
+ "off" to false
31
+ )
32
+
33
+ val whiteBalanceConstants = mapOf(
34
+ "auto" to Constants.WB_AUTO,
35
+ "cloudy" to Constants.WB_CLOUDY,
36
+ "sunny" to Constants.WB_SUNNY,
37
+ "shadow" to Constants.WB_SHADOW,
38
+ "fluorescent" to Constants.WB_FLUORESCENT,
39
+ "incandescent" to Constants.WB_INCANDESCENT
40
+ )
41
+
42
+ val videoQualityConstants = mapOf(
43
+ "2160p" to VIDEO_2160P,
44
+ "1080p" to VIDEO_1080P,
45
+ "720p" to VIDEO_720P,
46
+ "480p" to VIDEO_480P,
47
+ "4:3" to VIDEO_4x3
48
+ )
49
+
50
+ val exifTags = arrayOf(
51
+ arrayOf("string", ExifInterface.TAG_ARTIST),
52
+ arrayOf("int", ExifInterface.TAG_BITS_PER_SAMPLE),
53
+ arrayOf("int", ExifInterface.TAG_COMPRESSION),
54
+ arrayOf("string", ExifInterface.TAG_COPYRIGHT),
55
+ arrayOf("string", ExifInterface.TAG_DATETIME),
56
+ arrayOf("string", ExifInterface.TAG_IMAGE_DESCRIPTION),
57
+ arrayOf("int", ExifInterface.TAG_IMAGE_LENGTH),
58
+ arrayOf("int", ExifInterface.TAG_IMAGE_WIDTH),
59
+ arrayOf("int", ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT),
60
+ arrayOf("int", ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH),
61
+ arrayOf("string", ExifInterface.TAG_MAKE),
62
+ arrayOf("string", ExifInterface.TAG_MODEL),
63
+ arrayOf("int", ExifInterface.TAG_ORIENTATION),
64
+ arrayOf("int", ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION),
65
+ arrayOf("int", ExifInterface.TAG_PLANAR_CONFIGURATION),
66
+ arrayOf("double", ExifInterface.TAG_PRIMARY_CHROMATICITIES),
67
+ arrayOf("double", ExifInterface.TAG_REFERENCE_BLACK_WHITE),
68
+ arrayOf("int", ExifInterface.TAG_RESOLUTION_UNIT),
69
+ arrayOf("int", ExifInterface.TAG_ROWS_PER_STRIP),
70
+ arrayOf("int", ExifInterface.TAG_SAMPLES_PER_PIXEL),
71
+ arrayOf("string", ExifInterface.TAG_SOFTWARE),
72
+ arrayOf("int", ExifInterface.TAG_STRIP_BYTE_COUNTS),
73
+ arrayOf("int", ExifInterface.TAG_STRIP_OFFSETS),
74
+ arrayOf("int", ExifInterface.TAG_TRANSFER_FUNCTION),
75
+ arrayOf("double", ExifInterface.TAG_WHITE_POINT),
76
+ arrayOf("double", ExifInterface.TAG_X_RESOLUTION),
77
+ arrayOf("double", ExifInterface.TAG_Y_CB_CR_COEFFICIENTS),
78
+ arrayOf("int", ExifInterface.TAG_Y_CB_CR_POSITIONING),
79
+ arrayOf("int", ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING),
80
+ arrayOf("double", ExifInterface.TAG_Y_RESOLUTION),
81
+ arrayOf("double", ExifInterface.TAG_APERTURE_VALUE),
82
+ arrayOf("double", ExifInterface.TAG_BRIGHTNESS_VALUE),
83
+ arrayOf("string", ExifInterface.TAG_CFA_PATTERN),
84
+ arrayOf("int", ExifInterface.TAG_COLOR_SPACE),
85
+ arrayOf("string", ExifInterface.TAG_COMPONENTS_CONFIGURATION),
86
+ arrayOf("double", ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL),
87
+ arrayOf("int", ExifInterface.TAG_CONTRAST),
88
+ arrayOf("int", ExifInterface.TAG_CUSTOM_RENDERED),
89
+ arrayOf("string", ExifInterface.TAG_DATETIME_DIGITIZED),
90
+ arrayOf("string", ExifInterface.TAG_DATETIME_ORIGINAL),
91
+ arrayOf("string", ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION),
92
+ arrayOf("double", ExifInterface.TAG_DIGITAL_ZOOM_RATIO),
93
+ arrayOf("string", ExifInterface.TAG_EXIF_VERSION),
94
+ arrayOf("double", ExifInterface.TAG_EXPOSURE_BIAS_VALUE),
95
+ arrayOf("double", ExifInterface.TAG_EXPOSURE_INDEX),
96
+ arrayOf("int", ExifInterface.TAG_EXPOSURE_MODE),
97
+ arrayOf("int", ExifInterface.TAG_EXPOSURE_PROGRAM),
98
+ arrayOf("double", ExifInterface.TAG_EXPOSURE_TIME),
99
+ arrayOf("double", ExifInterface.TAG_F_NUMBER),
100
+ arrayOf("string", ExifInterface.TAG_FILE_SOURCE),
101
+ arrayOf("int", ExifInterface.TAG_FLASH),
102
+ arrayOf("double", ExifInterface.TAG_FLASH_ENERGY),
103
+ arrayOf("string", ExifInterface.TAG_FLASHPIX_VERSION),
104
+ arrayOf("double", ExifInterface.TAG_FOCAL_LENGTH),
105
+ arrayOf("int", ExifInterface.TAG_FOCAL_LENGTH_IN_35MM_FILM),
106
+ arrayOf("int", ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT),
107
+ arrayOf("double", ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION),
108
+ arrayOf("double", ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION),
109
+ arrayOf("int", ExifInterface.TAG_GAIN_CONTROL),
110
+ arrayOf("int", ExifInterface.TAG_ISO_SPEED_RATINGS),
111
+ arrayOf("string", ExifInterface.TAG_IMAGE_UNIQUE_ID),
112
+ arrayOf("int", ExifInterface.TAG_LIGHT_SOURCE),
113
+ arrayOf("string", ExifInterface.TAG_MAKER_NOTE),
114
+ arrayOf("double", ExifInterface.TAG_MAX_APERTURE_VALUE),
115
+ arrayOf("int", ExifInterface.TAG_METERING_MODE),
116
+ arrayOf("int", ExifInterface.TAG_NEW_SUBFILE_TYPE),
117
+ arrayOf("string", ExifInterface.TAG_OECF),
118
+ arrayOf("int", ExifInterface.TAG_PIXEL_X_DIMENSION),
119
+ arrayOf("int", ExifInterface.TAG_PIXEL_Y_DIMENSION),
120
+ arrayOf("string", ExifInterface.TAG_RELATED_SOUND_FILE),
121
+ arrayOf("int", ExifInterface.TAG_SATURATION),
122
+ arrayOf("int", ExifInterface.TAG_SCENE_CAPTURE_TYPE),
123
+ arrayOf("string", ExifInterface.TAG_SCENE_TYPE),
124
+ arrayOf("int", ExifInterface.TAG_SENSING_METHOD),
125
+ arrayOf("int", ExifInterface.TAG_SHARPNESS),
126
+ arrayOf("double", ExifInterface.TAG_SHUTTER_SPEED_VALUE),
127
+ arrayOf("string", ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE),
128
+ arrayOf("string", ExifInterface.TAG_SPECTRAL_SENSITIVITY),
129
+ arrayOf("int", ExifInterface.TAG_SUBFILE_TYPE),
130
+ arrayOf("string", ExifInterface.TAG_SUBSEC_TIME),
131
+ arrayOf("string", ExifInterface.TAG_SUBSEC_TIME_DIGITIZED),
132
+ arrayOf("string", ExifInterface.TAG_SUBSEC_TIME_ORIGINAL),
133
+ arrayOf("int", ExifInterface.TAG_SUBJECT_AREA),
134
+ arrayOf("double", ExifInterface.TAG_SUBJECT_DISTANCE),
135
+ arrayOf("int", ExifInterface.TAG_SUBJECT_DISTANCE_RANGE),
136
+ arrayOf("int", ExifInterface.TAG_SUBJECT_LOCATION),
137
+ arrayOf("string", ExifInterface.TAG_USER_COMMENT),
138
+ arrayOf("int", ExifInterface.TAG_WHITE_BALANCE),
139
+ arrayOf("double", ExifInterface.TAG_GPS_ALTITUDE),
140
+ arrayOf("int", ExifInterface.TAG_GPS_ALTITUDE_REF),
141
+ arrayOf("string", ExifInterface.TAG_GPS_AREA_INFORMATION),
142
+ arrayOf("double", ExifInterface.TAG_GPS_DOP),
143
+ arrayOf("string", ExifInterface.TAG_GPS_DATESTAMP),
144
+ arrayOf("double", ExifInterface.TAG_GPS_DEST_BEARING),
145
+ arrayOf("string", ExifInterface.TAG_GPS_DEST_BEARING_REF),
146
+ arrayOf("double", ExifInterface.TAG_GPS_DEST_DISTANCE),
147
+ arrayOf("string", ExifInterface.TAG_GPS_DEST_DISTANCE_REF),
148
+ arrayOf("double", ExifInterface.TAG_GPS_DEST_LATITUDE),
149
+ arrayOf("string", ExifInterface.TAG_GPS_DEST_LATITUDE_REF),
150
+ arrayOf("double", ExifInterface.TAG_GPS_DEST_LONGITUDE),
151
+ arrayOf("string", ExifInterface.TAG_GPS_DEST_LONGITUDE_REF),
152
+ arrayOf("int", ExifInterface.TAG_GPS_DIFFERENTIAL),
153
+ arrayOf("string", ExifInterface.TAG_GPS_H_POSITIONING_ERROR),
154
+ arrayOf("double", ExifInterface.TAG_GPS_IMG_DIRECTION),
155
+ arrayOf("string", ExifInterface.TAG_GPS_IMG_DIRECTION_REF),
156
+ arrayOf("double", ExifInterface.TAG_GPS_LATITUDE),
157
+ arrayOf("string", ExifInterface.TAG_GPS_LATITUDE_REF),
158
+ arrayOf("double", ExifInterface.TAG_GPS_LONGITUDE),
159
+ arrayOf("string", ExifInterface.TAG_GPS_LONGITUDE_REF),
160
+ arrayOf("string", ExifInterface.TAG_GPS_MAP_DATUM),
161
+ arrayOf("string", ExifInterface.TAG_GPS_MEASURE_MODE),
162
+ arrayOf("string", ExifInterface.TAG_GPS_PROCESSING_METHOD),
163
+ arrayOf("string", ExifInterface.TAG_GPS_SATELLITES),
164
+ arrayOf("double", ExifInterface.TAG_GPS_SPEED),
165
+ arrayOf("string", ExifInterface.TAG_GPS_SPEED_REF),
166
+ arrayOf("string", ExifInterface.TAG_GPS_STATUS),
167
+ arrayOf("string", ExifInterface.TAG_GPS_TIMESTAMP),
168
+ arrayOf("double", ExifInterface.TAG_GPS_TRACK),
169
+ arrayOf("string", ExifInterface.TAG_GPS_TRACK_REF),
170
+ arrayOf("string", ExifInterface.TAG_GPS_VERSION_ID),
171
+ arrayOf("string", ExifInterface.TAG_INTEROPERABILITY_INDEX),
172
+ arrayOf("int", ExifInterface.TAG_THUMBNAIL_IMAGE_LENGTH),
173
+ arrayOf("int", ExifInterface.TAG_THUMBNAIL_IMAGE_WIDTH),
174
+ arrayOf("int", ExifInterface.TAG_DNG_VERSION),
175
+ arrayOf("int", ExifInterface.TAG_DEFAULT_CROP_SIZE),
176
+ arrayOf("int", ExifInterface.TAG_ORF_PREVIEW_IMAGE_START),
177
+ arrayOf("int", ExifInterface.TAG_ORF_PREVIEW_IMAGE_LENGTH),
178
+ arrayOf("int", ExifInterface.TAG_ORF_ASPECT_FRAME),
179
+ arrayOf("int", ExifInterface.TAG_RW2_SENSOR_BOTTOM_BORDER),
180
+ arrayOf("int", ExifInterface.TAG_RW2_SENSOR_LEFT_BORDER),
181
+ arrayOf("int", ExifInterface.TAG_RW2_SENSOR_RIGHT_BORDER),
182
+ arrayOf("int", ExifInterface.TAG_RW2_SENSOR_TOP_BORDER),
183
+ arrayOf("int", ExifInterface.TAG_RW2_ISO)
184
+ )
@@ -0,0 +1,329 @@
1
+ package expo.modules.camera
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.Context
5
+ import android.graphics.Color
6
+ import android.Manifest
7
+ import android.media.CamcorderProfile
8
+ import android.net.Uri
9
+ import android.os.Build
10
+ import android.os.Bundle
11
+ import android.view.View
12
+
13
+ import com.google.android.cameraview.CameraView
14
+
15
+ import expo.modules.camera.CameraViewHelper.emitCameraReadyEvent
16
+ import expo.modules.camera.CameraViewHelper.emitMountErrorEvent
17
+ import expo.modules.camera.CameraViewHelper.getCorrectCameraRotation
18
+ import expo.modules.camera.CameraViewHelper.emitPictureSavedEvent
19
+ import expo.modules.camera.CameraViewHelper.getCamcorderProfile
20
+ import expo.modules.camera.CameraViewHelper.emitBarCodeReadEvent
21
+ import expo.modules.camera.CameraViewHelper.emitFacesDetectedEvent
22
+ import expo.modules.camera.CameraViewHelper.emitFaceDetectionErrorEvent
23
+ import expo.modules.camera.tasks.BarCodeScannerAsyncTaskDelegate
24
+ import expo.modules.camera.tasks.FaceDetectorAsyncTaskDelegate
25
+ import expo.modules.camera.tasks.PictureSavedDelegate
26
+ import expo.modules.camera.tasks.ResolveTakenPictureAsyncTask
27
+ import expo.modules.camera.tasks.BarCodeScannerAsyncTask
28
+ import expo.modules.camera.tasks.FaceDetectorTask
29
+ import expo.modules.camera.utils.FileSystemUtils
30
+ import expo.modules.camera.utils.ImageDimensions
31
+ import expo.modules.core.ModuleRegistryDelegate
32
+ import expo.modules.core.Promise
33
+ import expo.modules.core.interfaces.LifecycleEventListener
34
+ import expo.modules.core.interfaces.services.UIManager
35
+ import expo.modules.core.interfaces.services.EventEmitter
36
+ import expo.modules.interfaces.camera.CameraViewInterface
37
+ import expo.modules.interfaces.barcodescanner.BarCodeScannerInterface
38
+ import expo.modules.interfaces.facedetector.FaceDetectorInterface
39
+ import expo.modules.interfaces.barcodescanner.BarCodeScannerProviderInterface
40
+ import expo.modules.interfaces.barcodescanner.BarCodeScannerSettings
41
+ import expo.modules.interfaces.barcodescanner.BarCodeScannerResult
42
+ import expo.modules.interfaces.facedetector.FaceDetectorProviderInterface
43
+ import expo.modules.interfaces.permissions.Permissions
44
+
45
+ import java.io.File
46
+ import java.io.IOException
47
+ import java.lang.Exception
48
+ import java.util.*
49
+ import java.util.concurrent.ConcurrentHashMap
50
+ import java.util.concurrent.ConcurrentLinkedQueue
51
+
52
+ private const val MUTE_KEY = "mute"
53
+ private const val QUALITY_KEY = "quality"
54
+ private const val FAST_MODE_KEY = "fastMode"
55
+ private const val MAX_DURATION_KEY = "maxDuration"
56
+ private const val MAX_FILE_SIZE_KEY = "maxFileSize"
57
+ private const val VIDEO_BITRATE_KEY = "videoBitrate"
58
+
59
+ class ExpoCameraView(
60
+ themedReactContext: Context,
61
+ private val moduleRegistryDelegate: ModuleRegistryDelegate = ModuleRegistryDelegate()
62
+ ) : CameraView(themedReactContext, true),
63
+ LifecycleEventListener,
64
+ BarCodeScannerAsyncTaskDelegate,
65
+ FaceDetectorAsyncTaskDelegate,
66
+ PictureSavedDelegate,
67
+ CameraViewInterface {
68
+
69
+ private inline fun <reified T> moduleRegistry() = moduleRegistryDelegate.getFromModuleRegistry<T>()
70
+ private val pictureTakenPromises: Queue<Promise> = ConcurrentLinkedQueue()
71
+ private val pictureTakenOptions: MutableMap<Promise, Map<String, Any>> = ConcurrentHashMap()
72
+ private val pictureTakenDirectories: MutableMap<Promise, File> = ConcurrentHashMap()
73
+ private var videoRecordedPromise: Promise? = null
74
+ private var isPaused = false
75
+ private var isNew = true
76
+ private val eventEmitter: EventEmitter by moduleRegistry()
77
+
78
+ // Concurrency lock for scanners to avoid flooding the runtime
79
+ @Volatile
80
+ var barCodeScannerTaskLock = false
81
+
82
+ @Volatile
83
+ var faceDetectorTaskLock = false
84
+
85
+ // Scanning-related properties
86
+ private var barCodeScanner: BarCodeScannerInterface? = null
87
+ private var faceDetector: FaceDetectorInterface? = null
88
+ private var pendingFaceDetectorSettings: Map<String, Any>? = null
89
+ private var shouldDetectFaces = false
90
+ private var mShouldScanBarCodes = false
91
+
92
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
93
+ val preview = view ?: return
94
+ setBackgroundColor(Color.BLACK)
95
+ val width = right - left
96
+ val height = bottom - top
97
+ preview.layout(0, 0, width, height)
98
+ }
99
+
100
+ @SuppressLint("MissingSuperCall")
101
+ override fun requestLayout() {
102
+ // React handles this for us, so we don't need to call super.requestLayout();
103
+ }
104
+
105
+ override fun onViewAdded(child: View) {
106
+ // react adds children to containers at the beginning of children list and that moves pre-react added preview to the end of that list
107
+ // above would cause preview (TextureView that covers all available space) to be rendered at the top of children stack
108
+ // while we need this preview to be rendered last beneath all other children
109
+
110
+ // child is not preview
111
+ if (this.view === child || this.view == null) {
112
+ return
113
+ }
114
+
115
+ // bring to front all non-preview children
116
+ val childrenToBeReordered = mutableListOf<View>()
117
+ for (i in 0 until this.childCount) {
118
+ val childView = getChildAt(i)
119
+ if (i == 0 && childView === this.view) {
120
+ // preview is already first in children list - do not reorder anything
121
+ return
122
+ }
123
+ if (childView !== this.view) {
124
+ childrenToBeReordered.add(childView)
125
+ }
126
+ }
127
+ for (childView in childrenToBeReordered) {
128
+ bringChildToFront(childView)
129
+ }
130
+ requestLayout()
131
+ invalidate()
132
+ }
133
+
134
+ fun takePicture(options: Map<String, Any>, promise: Promise, cacheDirectory: File) {
135
+ pictureTakenPromises.add(promise)
136
+ pictureTakenOptions[promise] = options
137
+ pictureTakenDirectories[promise] = cacheDirectory
138
+ try {
139
+ super.takePicture()
140
+ } catch (e: Exception) {
141
+ pictureTakenPromises.remove(promise)
142
+ pictureTakenOptions.remove(promise)
143
+ pictureTakenDirectories.remove(promise)
144
+ throw e
145
+ }
146
+ }
147
+
148
+ override fun onPictureSaved(response: Bundle) {
149
+ emitPictureSavedEvent(eventEmitter, this, response)
150
+ }
151
+
152
+ fun record(options: Map<String?, Any?>, promise: Promise, cacheDirectory: File) {
153
+ try {
154
+ val path = FileSystemUtils.generateOutputPath(cacheDirectory, "Camera", ".mp4")
155
+ val maxDuration = options[MAX_DURATION_KEY]?.let { it as Double } ?: -1.0
156
+ val maxFileSize = options[MAX_FILE_SIZE_KEY]?.let { it as Double } ?: -1.0
157
+ val profile = if (options[QUALITY_KEY] != null) {
158
+ getCamcorderProfile(cameraId, (options[QUALITY_KEY] as Double).toInt())
159
+ } else {
160
+ CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_HIGH)
161
+ }
162
+ options[VIDEO_BITRATE_KEY]?.let { profile.videoBitRate = (it as Double).toInt() }
163
+ val muteValue = options[MUTE_KEY] as Boolean?
164
+ val recordAudio = muteValue != true
165
+ if (super.record(path, maxDuration.toInt() * 1000, maxFileSize.toInt(), recordAudio, profile)) {
166
+ videoRecordedPromise = promise
167
+ } else {
168
+ promise.reject("E_RECORDING_FAILED", "Starting video recording failed. Another recording might be in progress.")
169
+ }
170
+ } catch (e: IOException) {
171
+ promise.reject("E_RECORDING_FAILED", "Starting video recording failed - could not create video file.")
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Initialize the barcode scanner.
177
+ * Supports all iOS codes except [code138, code39mod43, itf14]
178
+ * Additionally supports [codabar, code128, maxicode, rss14, rssexpanded, upc_a, upc_ean]
179
+ */
180
+ private fun initBarCodeScanner() {
181
+ val barCodeScannerProvider: BarCodeScannerProviderInterface? by moduleRegistry()
182
+ barCodeScanner = barCodeScannerProvider?.createBarCodeDetectorWithContext(context)
183
+ }
184
+
185
+ fun setShouldScanBarCodes(shouldScanBarCodes: Boolean) {
186
+ mShouldScanBarCodes = shouldScanBarCodes
187
+ scanning = mShouldScanBarCodes || shouldDetectFaces
188
+ }
189
+
190
+ fun setBarCodeScannerSettings(settings: BarCodeScannerSettings) {
191
+ barCodeScanner?.setSettings(settings)
192
+ }
193
+
194
+ override fun onBarCodeScanned(barCode: BarCodeScannerResult) {
195
+ if (mShouldScanBarCodes) {
196
+ emitBarCodeReadEvent(eventEmitter, this, barCode)
197
+ }
198
+ }
199
+
200
+ override fun onBarCodeScanningTaskCompleted() {
201
+ barCodeScannerTaskLock = false
202
+ }
203
+
204
+ override fun getPreviewSizeAsArray() = intArrayOf(previewSize.width, previewSize.height)
205
+
206
+ override fun onHostResume() {
207
+ if (hasCameraPermissions()) {
208
+ if (isPaused && !isCameraOpened || isNew) {
209
+ isPaused = false
210
+ isNew = false
211
+ if (!Build.FINGERPRINT.contains("generic")) {
212
+ start()
213
+ val faceDetectorProvider: FaceDetectorProviderInterface? by moduleRegistry()
214
+ faceDetector = faceDetectorProvider?.createFaceDetectorWithContext(context)
215
+ pendingFaceDetectorSettings.let {
216
+ faceDetector?.setSettings(it)
217
+ pendingFaceDetectorSettings = null
218
+ }
219
+ }
220
+ }
221
+ } else {
222
+ emitMountErrorEvent(eventEmitter, this, "Camera permissions not granted - component could not be rendered.")
223
+ }
224
+ }
225
+
226
+ override fun onHostPause() {
227
+ if (!isPaused && isCameraOpened) {
228
+ faceDetector?.release()
229
+ isPaused = true
230
+ stop()
231
+ }
232
+ }
233
+
234
+ override fun onHostDestroy() {
235
+ faceDetector?.release()
236
+ stop()
237
+ }
238
+
239
+ private fun hasCameraPermissions(): Boolean {
240
+ val permissionsManager: Permissions by moduleRegistry()
241
+ return permissionsManager.hasGrantedPermissions(Manifest.permission.CAMERA)
242
+ }
243
+
244
+ fun setShouldDetectFaces(shouldDetectFaces: Boolean) {
245
+ this.shouldDetectFaces = shouldDetectFaces
246
+ scanning = mShouldScanBarCodes || shouldDetectFaces
247
+ }
248
+
249
+ fun setFaceDetectorSettings(settings: Map<String, Any>?) {
250
+ faceDetector?.setSettings(settings) ?: run {
251
+ pendingFaceDetectorSettings = settings
252
+ }
253
+ }
254
+
255
+ override fun onFacesDetected(faces: List<Bundle>) {
256
+ if (shouldDetectFaces) {
257
+ emitFacesDetectedEvent(eventEmitter, this, faces)
258
+ }
259
+ }
260
+
261
+ override fun onFaceDetectionError(faceDetector: FaceDetectorInterface) {
262
+ faceDetectorTaskLock = false
263
+ if (shouldDetectFaces) {
264
+ emitFaceDetectionErrorEvent(eventEmitter, this, faceDetector)
265
+ }
266
+ }
267
+
268
+ override fun onFaceDetectingTaskCompleted() {
269
+ faceDetectorTaskLock = false
270
+ }
271
+
272
+ init {
273
+ initBarCodeScanner()
274
+ isChildrenDrawingOrderEnabled = true
275
+ val uIManager: UIManager by moduleRegistry()
276
+ uIManager.registerLifecycleEventListener(this)
277
+ addCallback(object : Callback() {
278
+ override fun onCameraOpened(cameraView: CameraView) {
279
+ emitCameraReadyEvent(eventEmitter, cameraView)
280
+ }
281
+
282
+ override fun onMountError(cameraView: CameraView) {
283
+ emitMountErrorEvent(eventEmitter, cameraView, "Camera component could not be rendered - is there any other instance running?")
284
+ }
285
+
286
+ override fun onPictureTaken(cameraView: CameraView, data: ByteArray) {
287
+ val promise = pictureTakenPromises.poll()
288
+ val cacheDirectory = pictureTakenDirectories.remove(promise)
289
+ val options = pictureTakenOptions.remove(promise) as MutableMap
290
+ if (options.containsKey(FAST_MODE_KEY) && options[FAST_MODE_KEY] as Boolean) {
291
+ promise.resolve(null)
292
+ }
293
+ cacheDirectory?.let {
294
+ ResolveTakenPictureAsyncTask(data, promise, options, it, this@ExpoCameraView).execute()
295
+ }
296
+ }
297
+
298
+ override fun onVideoRecorded(cameraView: CameraView, path: String) {
299
+ videoRecordedPromise?.let {
300
+ it.resolve(
301
+ Bundle().apply {
302
+ putString("uri", Uri.fromFile(File(path)).toString())
303
+ }
304
+ )
305
+ videoRecordedPromise = null
306
+ }
307
+ }
308
+
309
+ override fun onFramePreview(cameraView: CameraView, data: ByteArray, width: Int, height: Int, rotation: Int) {
310
+ val correctRotation = getCorrectCameraRotation(rotation, facing)
311
+ if (mShouldScanBarCodes && !barCodeScannerTaskLock && cameraView is BarCodeScannerAsyncTaskDelegate) {
312
+ barCodeScannerTaskLock = true
313
+ val delegate = cameraView as BarCodeScannerAsyncTaskDelegate
314
+ barCodeScanner?.let { BarCodeScannerAsyncTask(delegate, it, data, width, height, rotation).execute() }
315
+ }
316
+ if (shouldDetectFaces && !faceDetectorTaskLock && cameraView is FaceDetectorAsyncTaskDelegate) {
317
+ faceDetectorTaskLock = true
318
+ val density = cameraView.resources.displayMetrics.density
319
+ val dimensions = ImageDimensions(width, height, correctRotation, facing)
320
+ val scaleX = cameraView.width.toDouble() / (dimensions.width * density)
321
+ val scaleY = cameraView.height.toDouble() / (dimensions.height * density)
322
+ val delegate = cameraView as FaceDetectorAsyncTaskDelegate
323
+ val task = faceDetector?.let { FaceDetectorTask(delegate, it, data, width, height, correctRotation, facing == FACING_FRONT, scaleX, scaleY) }
324
+ task?.execute()
325
+ }
326
+ }
327
+ })
328
+ }
329
+ }
@@ -0,0 +1,50 @@
1
+ package expo.modules.camera.events
2
+
3
+ import android.os.Bundle
4
+ import androidx.core.util.Pools
5
+
6
+ import expo.modules.camera.CameraViewManager
7
+ import expo.modules.core.interfaces.services.EventEmitter.BaseEvent
8
+ import expo.modules.interfaces.barcodescanner.BarCodeScannerResult
9
+
10
+ class BarCodeScannedEvent private constructor() : BaseEvent() {
11
+ private lateinit var barCode: BarCodeScannerResult
12
+ private var viewTag = 0
13
+
14
+ private fun init(viewTag: Int, barCode: BarCodeScannerResult) {
15
+ this.viewTag = viewTag
16
+ this.barCode = barCode
17
+ }
18
+
19
+ /**
20
+ * We want every distinct barcode to be reported to the JS listener.
21
+ * If we return some static value as a coalescing key there may be two barcode events
22
+ * containing two different barcodes waiting to be transmitted to JS
23
+ * that would get coalesced (because both of them would have the same coalescing key).
24
+ * So let's differentiate them with a hash of the contents (mod short's max value).
25
+ */
26
+ override fun getCoalescingKey(): Short {
27
+ val hashCode = barCode.value.hashCode() % Short.MAX_VALUE
28
+ return hashCode.toShort()
29
+ }
30
+
31
+ override fun getEventName() = CameraViewManager.Events.EVENT_ON_BAR_CODE_SCANNED.toString()
32
+
33
+ override fun getEventBody() = Bundle().apply {
34
+ putInt("target", viewTag)
35
+ putString("data", barCode.value)
36
+ putInt("type", barCode.type)
37
+ }
38
+
39
+ companion object {
40
+ private val EVENTS_POOL = Pools.SynchronizedPool<BarCodeScannedEvent>(3)
41
+ fun obtain(viewTag: Int, barCode: BarCodeScannerResult): BarCodeScannedEvent {
42
+ var event = EVENTS_POOL.acquire()
43
+ if (event == null) {
44
+ event = BarCodeScannedEvent()
45
+ }
46
+ event.init(viewTag, barCode)
47
+ return event
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,33 @@
1
+ package expo.modules.camera.events
2
+
3
+ import androidx.core.util.Pools
4
+ import android.os.Bundle
5
+
6
+ import expo.modules.camera.CameraViewManager
7
+ import expo.modules.core.interfaces.services.EventEmitter.BaseEvent
8
+
9
+ class CameraMountErrorEvent private constructor() : BaseEvent() {
10
+ private lateinit var message: String
11
+
12
+ private fun init(message: String) {
13
+ this.message = message
14
+ }
15
+
16
+ override fun getEventName() = CameraViewManager.Events.EVENT_ON_MOUNT_ERROR.toString()
17
+
18
+ override fun getEventBody() = Bundle().apply {
19
+ putString("message", message)
20
+ }
21
+
22
+ companion object {
23
+ private val EVENTS_POOL = Pools.SynchronizedPool<CameraMountErrorEvent>(3)
24
+ fun obtain(message: String): CameraMountErrorEvent {
25
+ var event = EVENTS_POOL.acquire()
26
+ if (event == null) {
27
+ event = CameraMountErrorEvent()
28
+ }
29
+ event.init(message)
30
+ return event
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,23 @@
1
+ package expo.modules.camera.events
2
+
3
+ import android.os.Bundle
4
+ import androidx.core.util.Pools
5
+ import expo.modules.camera.CameraViewManager
6
+ import expo.modules.core.interfaces.services.EventEmitter.BaseEvent
7
+
8
+ class CameraReadyEvent private constructor() : BaseEvent() {
9
+ override fun getEventName() = CameraViewManager.Events.EVENT_CAMERA_READY.toString()
10
+
11
+ override fun getEventBody(): Bundle = Bundle.EMPTY
12
+
13
+ companion object {
14
+ private val EVENTS_POOL = Pools.SynchronizedPool<CameraReadyEvent>(3)
15
+ fun obtain(): CameraReadyEvent {
16
+ var event = EVENTS_POOL.acquire()
17
+ if (event == null) {
18
+ event = CameraReadyEvent()
19
+ }
20
+ return event
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,39 @@
1
+ package expo.modules.camera.events
2
+
3
+ import android.os.Bundle
4
+ import androidx.core.util.Pools
5
+
6
+ import expo.modules.core.interfaces.services.EventEmitter.BaseEvent
7
+ import expo.modules.interfaces.facedetector.FaceDetectorInterface
8
+ import expo.modules.camera.CameraViewManager
9
+
10
+ class FaceDetectionErrorEvent private constructor() : BaseEvent() {
11
+ private var faceDetector: FaceDetectorInterface? = null
12
+
13
+ private fun init(faceDetector: FaceDetectorInterface) {
14
+ this.faceDetector = faceDetector
15
+ }
16
+
17
+ override fun getCoalescingKey(): Short = 0
18
+
19
+ override fun getEventName() = CameraViewManager.Events.EVENT_ON_MOUNT_ERROR.toString()
20
+
21
+ override fun getEventBody() = Bundle().apply {
22
+ putBoolean("isOperational", isFaceDetectorOperational)
23
+ }
24
+
25
+ private val isFaceDetectorOperational: Boolean
26
+ get() = faceDetector != null
27
+
28
+ companion object {
29
+ private val EVENTS_POOL = Pools.SynchronizedPool<FaceDetectionErrorEvent>(3)
30
+ fun obtain(faceDetector: FaceDetectorInterface): FaceDetectionErrorEvent {
31
+ var event = EVENTS_POOL.acquire()
32
+ if (event == null) {
33
+ event = FaceDetectionErrorEvent()
34
+ }
35
+ event.init(faceDetector)
36
+ return event
37
+ }
38
+ }
39
+ }