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.
- package/CHANGELOG.md +23 -2
- package/README.md +1 -1
- package/android/build.gradle +22 -19
- package/android/src/main/java/expo/modules/camera/CameraModule.kt +217 -0
- package/android/src/main/java/expo/modules/camera/CameraPackage.kt +10 -0
- package/android/src/main/java/expo/modules/camera/CameraViewHelper.kt +139 -0
- package/android/src/main/java/expo/modules/camera/CameraViewManager.kt +116 -0
- package/android/src/main/java/expo/modules/camera/Constants.kt +184 -0
- package/android/src/main/java/expo/modules/camera/ExpoCameraView.kt +329 -0
- package/android/src/main/java/expo/modules/camera/events/BarCodeScannedEvent.kt +50 -0
- package/android/src/main/java/expo/modules/camera/events/CameraMountErrorEvent.kt +33 -0
- package/android/src/main/java/expo/modules/camera/events/CameraReadyEvent.kt +23 -0
- package/android/src/main/java/expo/modules/camera/events/FaceDetectionErrorEvent.kt +39 -0
- package/android/src/main/java/expo/modules/camera/events/FacesDetectedEvent.kt +46 -0
- package/android/src/main/java/expo/modules/camera/events/PictureSavedEvent.kt +41 -0
- package/android/src/main/java/expo/modules/camera/tasks/BarCodeScannerAsyncTask.kt +26 -0
- package/android/src/main/java/expo/modules/camera/tasks/BarCodeScannerAsyncTaskDelegate.kt +8 -0
- package/android/src/main/java/expo/modules/camera/tasks/FaceDetectorAsyncTaskDelegate.kt +10 -0
- package/android/src/main/java/expo/modules/camera/tasks/FaceDetectorTask.kt +34 -0
- package/android/src/main/java/expo/modules/camera/tasks/PictureSavedDelegate.kt +7 -0
- package/android/src/main/java/expo/modules/camera/tasks/ResolveTakenPictureAsyncTask.kt +231 -0
- package/android/src/main/java/expo/modules/camera/utils/FileSystemUtils.kt +23 -0
- package/android/src/main/java/expo/modules/camera/utils/ImageDimensions.kt +14 -0
- package/build/ExponentCameraManager.web.js +3 -1
- package/build/ExponentCameraManager.web.js.map +1 -1
- package/ios/EXCamera.xcframework/ios-arm64/EXCamera.framework/EXCamera +0 -0
- package/ios/EXCamera.xcframework/ios-arm64/EXCamera.framework/Info.plist +0 -0
- package/ios/EXCamera.xcframework/ios-arm64_x86_64-simulator/EXCamera.framework/EXCamera +0 -0
- package/ios/EXCamera.xcframework/ios-arm64_x86_64-simulator/EXCamera.framework/Info.plist +0 -0
- package/package.json +7 -5
- package/plugin/build/withCamera.d.ts +2 -1
- package/plugin/build/withCamera.js +50 -30
- package/plugin/src/withCamera.ts +66 -27
- package/src/ExponentCameraManager.web.ts +3 -2
- package/src/{types → ts-declarations}/image-capture.d.ts +0 -0
- package/src/ts-declarations/lib.dom.d.ts +34 -0
- package/android/src/main/java/expo/modules/camera/CameraModule.java +0 -359
- package/android/src/main/java/expo/modules/camera/CameraPackage.java +0 -23
- package/android/src/main/java/expo/modules/camera/CameraViewHelper.java +0 -294
- package/android/src/main/java/expo/modules/camera/CameraViewManager.java +0 -142
- package/android/src/main/java/expo/modules/camera/ExpoCameraView.java +0 -376
- package/android/src/main/java/expo/modules/camera/events/BarCodeScannedEvent.java +0 -59
- package/android/src/main/java/expo/modules/camera/events/CameraMountErrorEvent.java +0 -38
- package/android/src/main/java/expo/modules/camera/events/CameraReadyEvent.java +0 -30
- package/android/src/main/java/expo/modules/camera/events/FaceDetectionErrorEvent.java +0 -50
- package/android/src/main/java/expo/modules/camera/events/FacesDetectedEvent.java +0 -63
- package/android/src/main/java/expo/modules/camera/events/PictureSavedEvent.java +0 -53
- package/android/src/main/java/expo/modules/camera/tasks/BarCodeScannerAsyncTask.java +0 -47
- package/android/src/main/java/expo/modules/camera/tasks/BarCodeScannerAsyncTaskDelegate.java +0 -8
- package/android/src/main/java/expo/modules/camera/tasks/FaceDetectorAsyncTaskDelegate.java +0 -13
- package/android/src/main/java/expo/modules/camera/tasks/FaceDetectorTask.java +0 -53
- package/android/src/main/java/expo/modules/camera/tasks/PictureSavedDelegate.java +0 -7
- package/android/src/main/java/expo/modules/camera/tasks/ResolveTakenPictureAsyncTask.java +0 -288
- package/android/src/main/java/expo/modules/camera/utils/FileSystemUtils.java +0 -21
- 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
|
+
}
|