@getyoti/react-native-yoti-face-capture 3.0.1 → 4.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.
- package/README.md +4 -4
- package/android/build.gradle +34 -30
- package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/android/src/main/java/com/yoti/reactnative/facecapture/YotiFaceCaptureEvent.java +34 -0
- package/android/src/main/java/com/yoti/reactnative/facecapture/YotiFaceCaptureModule.java +55 -56
- package/android/src/main/java/com/yoti/reactnative/facecapture/YotiFaceCapturePackage.java +5 -2
- package/android/src/main/java/com/yoti/reactnative/facecapture/YotiFaceCaptureView.java +129 -73
- package/android/src/main/java/com/yoti/reactnative/facecapture/YotiFaceCaptureViewManager.java +10 -1
- package/android/src/main/res/layout/yotifacecapture.xml +3 -9
- package/lib/commonjs/RNYotiCapture.android.js +63 -94
- package/lib/commonjs/RNYotiCapture.android.js.map +1 -1
- package/lib/commonjs/RNYotiCapture.ios.js +77 -84
- package/lib/commonjs/RNYotiCapture.ios.js.map +1 -1
- package/lib/commonjs/RNYotiCaptureTypes.js +9 -17
- package/lib/commonjs/RNYotiCaptureTypes.js.map +1 -1
- package/lib/commonjs/index.js +21 -6
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/RNYotiCapture.android.js +62 -85
- package/lib/module/RNYotiCapture.android.js.map +1 -1
- package/lib/module/RNYotiCapture.ios.js +76 -75
- package/lib/module/RNYotiCapture.ios.js.map +1 -1
- package/lib/module/RNYotiCaptureTypes.js +5 -7
- package/lib/module/RNYotiCaptureTypes.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/RNYotiCapture.android.d.ts +7 -46
- package/lib/typescript/RNYotiCapture.ios.d.ts +7 -9
- package/lib/typescript/RNYotiCaptureTypes.d.ts +6 -6
- package/lib/typescript/index.d.ts +1 -0
- package/package.json +6 -8
- package/react-native-yoti-face-capture.podspec +1 -1
- package/src/RNYotiCapture.android.tsx +128 -115
- package/src/RNYotiCapture.ios.tsx +107 -80
- package/src/index.tsx +6 -0
- package/CHANGELOG.md +0 -34
package/README.md
CHANGED
|
@@ -52,14 +52,14 @@ You may then run:
|
|
|
52
52
|
|
|
53
53
|
The library employs the [bundled version approach](https://github.com/getyoti/yoti-face-capture-android#bundled-vs-unbundled) approach for the AI models.
|
|
54
54
|
### iOS Configuration
|
|
55
|
-
-
|
|
56
|
-
-
|
|
55
|
+
- Requires iOS 15.1+
|
|
56
|
+
- Requires Swift 5.3+
|
|
57
57
|
|
|
58
58
|
Make sure you've installed and are running the latest version of [Cocoapods](https://guides.cocoapods.org/using/getting-started.html).
|
|
59
59
|
Add the `use_frameworks!` declaration to your Podfile and run `pod install` from the ios directory:
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
platform :ios, '
|
|
62
|
+
platform :ios, '15.1'
|
|
63
63
|
|
|
64
64
|
target 'TargetName' do
|
|
65
65
|
use_frameworks!
|
|
@@ -286,5 +286,5 @@ protected List<ReactPackage> getPackages() {
|
|
|
286
286
|
MIT
|
|
287
287
|
|
|
288
288
|
## Support
|
|
289
|
-
|
|
289
|
+
For any questions or support please contact us here: https://support.yoti.com
|
|
290
290
|
Once we have answered your question we may contact you again to discuss Yoti products and services. If you'd prefer us not to do this, please let us know when you e-mail.
|
package/android/build.gradle
CHANGED
|
@@ -1,61 +1,65 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
|
-
apply plugin: 'kotlin-android'
|
|
3
2
|
|
|
4
3
|
def safeExtGet(prop, fallback) {
|
|
5
4
|
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
android {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
namespace "com.yoti.reactnative.facecapture"
|
|
9
|
+
|
|
10
|
+
compileSdk safeExtGet('compileSdkVersion', 35)
|
|
11
11
|
|
|
12
12
|
defaultConfig {
|
|
13
|
-
minSdkVersion safeExtGet('minSdkVersion',
|
|
14
|
-
targetSdkVersion safeExtGet('targetSdkVersion',
|
|
15
|
-
versionCode
|
|
16
|
-
versionName "
|
|
13
|
+
minSdkVersion safeExtGet('minSdkVersion', 24)
|
|
14
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 35)
|
|
15
|
+
versionCode 400
|
|
16
|
+
versionName "4.0.0"
|
|
17
17
|
}
|
|
18
18
|
buildTypes {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
debug {
|
|
20
|
+
matchingFallbacks = ['release']
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
packagingOptions {
|
|
24
|
+
exclude 'META-INF/*.kotlin_module'
|
|
25
|
+
exclude "**/kotlin/**"
|
|
26
|
+
}
|
|
27
|
+
compileOptions {
|
|
28
|
+
sourceCompatibility = '1.8'
|
|
29
|
+
targetCompatibility = '1.8'
|
|
25
30
|
}
|
|
26
31
|
}
|
|
27
32
|
|
|
33
|
+
dependencies {
|
|
34
|
+
implementation "com.facebook.react:react-native:+"
|
|
35
|
+
implementation 'com.yoti.mobile.android:face-capture-bundled:4.8.1'
|
|
36
|
+
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
|
37
|
+
implementation 'androidx.appcompat:appcompat:1.2.0'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
28
41
|
buildscript {
|
|
29
42
|
ext {
|
|
30
|
-
kotlinVersion = '1.
|
|
43
|
+
kotlinVersion = '1.7.20'
|
|
31
44
|
}
|
|
32
45
|
repositories {
|
|
33
|
-
jcenter()
|
|
34
46
|
google()
|
|
35
47
|
mavenCentral()
|
|
36
48
|
}
|
|
37
49
|
dependencies {
|
|
38
|
-
classpath 'com.android.tools.build:gradle:
|
|
50
|
+
classpath 'com.android.tools.build:gradle:8.13.2'
|
|
39
51
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${project.ext.kotlinVersion}"
|
|
40
52
|
}
|
|
41
53
|
}
|
|
42
54
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
allprojects {
|
|
56
|
+
repositories {
|
|
57
|
+
google()
|
|
58
|
+
mavenCentral()
|
|
59
|
+
maven {
|
|
60
|
+
url "https://jitpack.io"
|
|
61
|
+
}
|
|
50
62
|
}
|
|
51
63
|
}
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
//noinspection GradleDynamicVersion
|
|
55
|
-
implementation "com.facebook.react:react-native:+" // From node_modules
|
|
56
|
-
implementation "org.jetbrains.kotlin:kotlin-stdlib:${project.ext.kotlinVersion}"
|
|
57
|
-
implementation 'com.yoti.mobile.android:face-capture-bundled:4.0.0'
|
|
58
|
-
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
|
59
|
-
implementation 'androidx.appcompat:appcompat:1.2.0'
|
|
60
|
-
implementation 'com.google.android.material:material:1.2.1'
|
|
61
|
-
}
|
|
65
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
distributionBase=GRADLE_USER_HOME
|
|
2
2
|
distributionPath=wrapper/dists
|
|
3
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-
|
|
3
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
|
4
4
|
zipStoreBase=GRADLE_USER_HOME
|
|
5
5
|
zipStorePath=wrapper/dists
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
package com.yoti.reactnative.facecapture;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
|
|
6
|
+
import com.facebook.react.bridge.WritableMap;
|
|
7
|
+
import com.facebook.react.uimanager.events.Event;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Custom event class for YotiFaceCapture events.
|
|
11
|
+
* This is compatible with both the old architecture and the new Fabric architecture.
|
|
12
|
+
*/
|
|
13
|
+
public class YotiFaceCaptureEvent extends Event<YotiFaceCaptureEvent> {
|
|
14
|
+
private final String eventName;
|
|
15
|
+
private final WritableMap eventData;
|
|
16
|
+
|
|
17
|
+
public YotiFaceCaptureEvent(int surfaceId, int viewTag, String eventName, @Nullable WritableMap eventData) {
|
|
18
|
+
super(surfaceId, viewTag);
|
|
19
|
+
this.eventName = eventName;
|
|
20
|
+
this.eventData = eventData;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@NonNull
|
|
24
|
+
@Override
|
|
25
|
+
public String getEventName() {
|
|
26
|
+
return eventName;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Nullable
|
|
30
|
+
@Override
|
|
31
|
+
protected WritableMap getEventData() {
|
|
32
|
+
return eventData;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
package com.yoti.reactnative.facecapture;
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
import androidx.annotation.Nullable;
|
|
4
7
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
5
|
-
import com.facebook.react.bridge.ReactContext;
|
|
6
8
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
7
9
|
import com.facebook.react.bridge.ReactMethod;
|
|
8
|
-
import com.facebook.react.
|
|
9
|
-
import com.facebook.react.
|
|
10
|
-
import com.facebook.react.uimanager.
|
|
10
|
+
import com.facebook.react.bridge.UIManager;
|
|
11
|
+
import com.facebook.react.bridge.UiThreadUtil;
|
|
12
|
+
import com.facebook.react.uimanager.UIManagerHelper;
|
|
13
|
+
import com.facebook.react.uimanager.common.UIManagerType;
|
|
11
14
|
import com.yoti.mobile.android.capture.face.ui.models.face.ImageQuality;
|
|
12
15
|
|
|
13
16
|
import java.util.Map;
|
|
@@ -18,6 +21,7 @@ public class YotiFaceCaptureModule extends ReactContextBaseJavaModule {
|
|
|
18
21
|
super(context);
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
@NonNull
|
|
21
25
|
@Override
|
|
22
26
|
public String getName() {
|
|
23
27
|
return "YotiFaceCaptureModule";
|
|
@@ -32,78 +36,73 @@ public class YotiFaceCaptureModule extends ReactContextBaseJavaModule {
|
|
|
32
36
|
return constants;
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
@
|
|
36
|
-
|
|
39
|
+
@Nullable
|
|
40
|
+
private YotiFaceCaptureView resolveView(int viewTag) {
|
|
37
41
|
final ReactApplicationContext context = getReactApplicationContext();
|
|
38
|
-
|
|
39
|
-
uiManager
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
UIManager uiManager = UIManagerHelper.getUIManager(context, UIManagerType.FABRIC);
|
|
43
|
+
if (uiManager == null) {
|
|
44
|
+
uiManager = UIManagerHelper.getUIManager(context, UIManagerType.DEFAULT);
|
|
45
|
+
}
|
|
46
|
+
if (uiManager == null) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
View view = uiManager.resolveView(viewTag);
|
|
51
|
+
if (view instanceof YotiFaceCaptureView) {
|
|
52
|
+
return (YotiFaceCaptureView) view;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@ReactMethod
|
|
59
|
+
public void startCamera(final int viewTag) {
|
|
60
|
+
UiThreadUtil.runOnUiThread(() -> {
|
|
61
|
+
try {
|
|
62
|
+
YotiFaceCaptureView faceCaptureView = resolveView(viewTag);
|
|
63
|
+
|
|
64
|
+
faceCaptureView.startCamera();
|
|
65
|
+
} catch (Exception e) {
|
|
66
|
+
e.printStackTrace();
|
|
50
67
|
}
|
|
51
68
|
});
|
|
52
69
|
}
|
|
53
70
|
|
|
54
71
|
@ReactMethod
|
|
55
72
|
public void stopCamera(final int viewTag) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
@Override
|
|
60
|
-
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
|
61
|
-
final YotiFaceCaptureView faceCaptureView;
|
|
73
|
+
UiThreadUtil.runOnUiThread(() -> {
|
|
74
|
+
try {
|
|
75
|
+
YotiFaceCaptureView faceCaptureView = resolveView(viewTag);
|
|
62
76
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
} catch (Exception e) {
|
|
67
|
-
e.printStackTrace();
|
|
68
|
-
}
|
|
77
|
+
faceCaptureView.stopCamera();
|
|
78
|
+
} catch (Exception e) {
|
|
79
|
+
e.printStackTrace();
|
|
69
80
|
}
|
|
70
81
|
});
|
|
71
82
|
}
|
|
72
83
|
|
|
73
84
|
@ReactMethod
|
|
74
85
|
public void startAnalyzing(final int viewTag) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
faceCaptureView = (YotiFaceCaptureView) nativeViewHierarchyManager.resolveView(viewTag);
|
|
84
|
-
faceCaptureView.startAnalyzing();
|
|
85
|
-
} catch (Exception e) {
|
|
86
|
-
e.printStackTrace();
|
|
87
|
-
}
|
|
86
|
+
UiThreadUtil.runOnUiThread(() -> {
|
|
87
|
+
try {
|
|
88
|
+
YotiFaceCaptureView faceCaptureView = resolveView(viewTag);
|
|
89
|
+
|
|
90
|
+
faceCaptureView.startAnalyzing();
|
|
91
|
+
} catch (Exception e) {
|
|
92
|
+
e.printStackTrace();
|
|
88
93
|
}
|
|
89
94
|
});
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
@ReactMethod
|
|
93
98
|
public void stopAnalyzing(final int viewTag) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
faceCaptureView = (YotiFaceCaptureView) nativeViewHierarchyManager.resolveView(viewTag);
|
|
103
|
-
faceCaptureView.stopAnalyzing();
|
|
104
|
-
} catch (Exception e) {
|
|
105
|
-
e.printStackTrace();
|
|
106
|
-
}
|
|
99
|
+
UiThreadUtil.runOnUiThread(() -> {
|
|
100
|
+
try {
|
|
101
|
+
YotiFaceCaptureView faceCaptureView = resolveView(viewTag);
|
|
102
|
+
|
|
103
|
+
faceCaptureView.stopAnalyzing();
|
|
104
|
+
} catch (Exception e) {
|
|
105
|
+
e.printStackTrace();
|
|
107
106
|
}
|
|
108
107
|
});
|
|
109
108
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package com.yoti.reactnative.facecapture;
|
|
2
2
|
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
3
4
|
import com.facebook.react.ReactPackage;
|
|
4
5
|
import com.facebook.react.bridge.NativeModule;
|
|
5
6
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
@@ -9,13 +10,15 @@ import java.util.Arrays;
|
|
|
9
10
|
import java.util.List;
|
|
10
11
|
|
|
11
12
|
public class YotiFaceCapturePackage implements ReactPackage {
|
|
13
|
+
@NonNull
|
|
12
14
|
@Override
|
|
13
|
-
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
|
15
|
+
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
|
|
14
16
|
return Arrays.<NativeModule>asList(new YotiFaceCaptureModule(reactContext));
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
@NonNull
|
|
17
20
|
@Override
|
|
18
|
-
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
|
21
|
+
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
|
|
19
22
|
return Arrays.<ViewManager>asList(new YotiFaceCaptureViewManager());
|
|
20
23
|
}
|
|
21
24
|
}
|
|
@@ -4,8 +4,9 @@ import android.graphics.PointF;
|
|
|
4
4
|
import android.util.Base64;
|
|
5
5
|
import android.view.Choreographer;
|
|
6
6
|
import android.view.View;
|
|
7
|
-
import android.widget.
|
|
7
|
+
import android.widget.FrameLayout;
|
|
8
8
|
|
|
9
|
+
import androidx.annotation.Nullable;
|
|
9
10
|
import androidx.lifecycle.LifecycleOwner;
|
|
10
11
|
|
|
11
12
|
import com.facebook.react.bridge.Arguments;
|
|
@@ -13,20 +14,17 @@ import com.facebook.react.bridge.ReactContext;
|
|
|
13
14
|
import com.facebook.react.bridge.ReadableArray;
|
|
14
15
|
import com.facebook.react.bridge.WritableMap;
|
|
15
16
|
import com.facebook.react.uimanager.ThemedReactContext;
|
|
16
|
-
|
|
17
|
-
import com.facebook.react.uimanager.events.
|
|
17
|
+
import com.facebook.react.uimanager.UIManagerHelper;
|
|
18
|
+
import com.facebook.react.uimanager.events.EventDispatcher;
|
|
18
19
|
import com.yoti.mobile.android.capture.face.ui.FaceCapture;
|
|
19
20
|
import com.yoti.mobile.android.capture.face.ui.FaceCaptureListener;
|
|
20
|
-
import com.yoti.mobile.android.capture.face.ui.models.camera.CameraState;
|
|
21
21
|
import com.yoti.mobile.android.capture.face.ui.models.camera.CameraStateListener;
|
|
22
22
|
import com.yoti.mobile.android.capture.face.ui.models.face.FaceCaptureConfiguration;
|
|
23
|
-
import com.yoti.mobile.android.capture.face.ui.models.face.FaceCaptureResult;
|
|
24
23
|
import com.yoti.mobile.android.capture.face.ui.models.face.FaceCaptureState;
|
|
25
24
|
import com.yoti.mobile.android.capture.face.ui.models.face.ImageQuality;
|
|
25
|
+
import java.util.Objects;
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
public class YotiFaceCaptureView extends LinearLayout {
|
|
27
|
+
public class YotiFaceCaptureView extends FrameLayout {
|
|
30
28
|
private final ThemedReactContext context;
|
|
31
29
|
private final FaceCapture mFaceCapture;
|
|
32
30
|
private ImageQuality mImageQuality;
|
|
@@ -35,61 +33,60 @@ public class YotiFaceCaptureView extends LinearLayout {
|
|
|
35
33
|
private boolean mRequireBrightEnvironment = true;
|
|
36
34
|
private int mRequiredStableFrames;
|
|
37
35
|
private ReadableArray mFaceCenter;
|
|
38
|
-
private
|
|
36
|
+
private boolean isCleanedUp = false;
|
|
37
|
+
|
|
38
|
+
private final Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() {
|
|
39
39
|
@Override
|
|
40
|
-
public void
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"onCameraStateChange",
|
|
47
|
-
event);
|
|
40
|
+
public void doFrame(long frameTimeNanos) {
|
|
41
|
+
if (!isCleanedUp) {
|
|
42
|
+
manuallyLayoutChildren();
|
|
43
|
+
getViewTreeObserver().dispatchOnGlobalLayout();
|
|
44
|
+
Choreographer.getInstance().postFrameCallback(this);
|
|
45
|
+
}
|
|
48
46
|
}
|
|
49
47
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
getId(),
|
|
90
|
-
"onFaceCaptureResult",
|
|
91
|
-
event);
|
|
48
|
+
|
|
49
|
+
private final CameraStateListener mCameraStateListener = cameraState -> {
|
|
50
|
+
WritableMap event = Arguments.createMap();
|
|
51
|
+
event.putString("state", cameraState.getClass().getSimpleName());
|
|
52
|
+
sendEvent("onCameraStateChange", event);
|
|
53
|
+
};
|
|
54
|
+
private final FaceCaptureListener mFaceCaptureListener = faceCaptureResult -> {
|
|
55
|
+
WritableMap event = Arguments.createMap();
|
|
56
|
+
event.putString("originalImage", Base64.encodeToString(faceCaptureResult.getOriginalImage().getData(), Base64.DEFAULT));
|
|
57
|
+
event.putString("state", faceCaptureResult.getState().getClass().getSimpleName());
|
|
58
|
+
|
|
59
|
+
FaceCaptureState s = faceCaptureResult.getState();
|
|
60
|
+
if (s instanceof FaceCaptureState.InvalidFace) {
|
|
61
|
+
event.putString("cause", ((FaceCaptureState.InvalidFace) s).getCause().getClass().getSimpleName());
|
|
62
|
+
}
|
|
63
|
+
if (s instanceof FaceCaptureState.ValidFace) {
|
|
64
|
+
int croppedFaceBoundingBoxLeft = ((FaceCaptureState.ValidFace) s).getCroppedFaceBoundingBox().left;
|
|
65
|
+
int croppedFaceBoundingBoxTop = ((FaceCaptureState.ValidFace) s).getCroppedFaceBoundingBox().top;
|
|
66
|
+
int croppedFaceBoundingBoxRight = ((FaceCaptureState.ValidFace) s).getCroppedFaceBoundingBox().right;
|
|
67
|
+
int croppedFaceBoundingBoxBottom = ((FaceCaptureState.ValidFace) s).getCroppedFaceBoundingBox().bottom;
|
|
68
|
+
WritableMap croppedFaceBoundingBox = Arguments.createMap();
|
|
69
|
+
croppedFaceBoundingBox.putInt("x", croppedFaceBoundingBoxLeft);
|
|
70
|
+
croppedFaceBoundingBox.putInt("y", croppedFaceBoundingBoxTop);
|
|
71
|
+
croppedFaceBoundingBox.putInt("width", croppedFaceBoundingBoxRight - croppedFaceBoundingBoxLeft);
|
|
72
|
+
croppedFaceBoundingBox.putInt("height", croppedFaceBoundingBoxBottom - croppedFaceBoundingBoxTop);
|
|
73
|
+
|
|
74
|
+
int faceBoundingBoxLeft = ((FaceCaptureState.ValidFace) s).getFaceBoundingBox().left;
|
|
75
|
+
int faceBoundingBoxTop = ((FaceCaptureState.ValidFace) s).getFaceBoundingBox().top;
|
|
76
|
+
int faceBoundingBoxRight = ((FaceCaptureState.ValidFace) s).getFaceBoundingBox().right;
|
|
77
|
+
int faceBoundingBoxBottom = ((FaceCaptureState.ValidFace) s).getFaceBoundingBox().bottom;
|
|
78
|
+
WritableMap faceBoundingBox = Arguments.createMap();
|
|
79
|
+
faceBoundingBox.putInt("x", faceBoundingBoxLeft);
|
|
80
|
+
faceBoundingBox.putInt("y", faceBoundingBoxTop);
|
|
81
|
+
faceBoundingBox.putInt("width", faceBoundingBoxRight - faceBoundingBoxLeft);
|
|
82
|
+
faceBoundingBox.putInt("height", faceBoundingBoxBottom - faceBoundingBoxTop);
|
|
83
|
+
|
|
84
|
+
event.putString("croppedImage", Base64.encodeToString(((FaceCaptureState.ValidFace) s).getCroppedImage(), Base64.DEFAULT));
|
|
85
|
+
event.putMap("croppedFaceBoundingBox", croppedFaceBoundingBox);
|
|
86
|
+
event.putMap("faceBoundingBox", faceBoundingBox);
|
|
92
87
|
}
|
|
88
|
+
|
|
89
|
+
sendEvent("onFaceCaptureResult", event);
|
|
93
90
|
};
|
|
94
91
|
|
|
95
92
|
YotiFaceCaptureView(ThemedReactContext context) {
|
|
@@ -97,14 +94,25 @@ public class YotiFaceCaptureView extends LinearLayout {
|
|
|
97
94
|
this.context = context;
|
|
98
95
|
inflate(context, R.layout.yotifacecapture, this);
|
|
99
96
|
mFaceCapture = findViewById(R.id.faceCapture);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
97
|
+
|
|
98
|
+
// Add layout change listener to handle React Native new architecture layout
|
|
99
|
+
addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
|
100
|
+
int width = right - left;
|
|
101
|
+
int height = bottom - top;
|
|
102
|
+
if (width > 0 && height > 0) {
|
|
103
|
+
// Force all children to match parent size
|
|
104
|
+
for (int i = 0; i < getChildCount(); i++) {
|
|
105
|
+
View child = getChildAt(i);
|
|
106
|
+
child.measure(
|
|
107
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
108
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
109
|
+
);
|
|
110
|
+
child.layout(0, 0, width, height);
|
|
111
|
+
}
|
|
106
112
|
}
|
|
107
113
|
});
|
|
114
|
+
|
|
115
|
+
Choreographer.getInstance().postFrameCallback(frameCallback);
|
|
108
116
|
}
|
|
109
117
|
|
|
110
118
|
void manuallyLayoutChildren() {
|
|
@@ -119,13 +127,38 @@ public class YotiFaceCaptureView extends LinearLayout {
|
|
|
119
127
|
@Override
|
|
120
128
|
public void requestLayout() {
|
|
121
129
|
super.requestLayout();
|
|
130
|
+
// This is needed to ensure layout happens properly in React Native 0.7x+
|
|
131
|
+
// Without this, the view may have 0 width/height causing black screen
|
|
132
|
+
post(measureAndLayout);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private final Runnable measureAndLayout = () -> {
|
|
136
|
+
measure(
|
|
137
|
+
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
|
|
138
|
+
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
|
|
139
|
+
layout(getLeft(), getTop(), getRight(), getBottom());
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Send events to React Native using the modern EventDispatcher API.
|
|
144
|
+
* This is compatible with both the old architecture and the new Fabric architecture.
|
|
145
|
+
*/
|
|
146
|
+
private void sendEvent(String eventName, @Nullable WritableMap event) {
|
|
147
|
+
ReactContext reactContext = (ReactContext) getContext();
|
|
148
|
+
int surfaceId = UIManagerHelper.getSurfaceId(reactContext);
|
|
149
|
+
EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, getId());
|
|
150
|
+
if (eventDispatcher != null) {
|
|
151
|
+
eventDispatcher.dispatchEvent(
|
|
152
|
+
new YotiFaceCaptureEvent(surfaceId, getId(), eventName, event)
|
|
153
|
+
);
|
|
154
|
+
}
|
|
122
155
|
}
|
|
123
156
|
|
|
124
|
-
public void setFaceCenter(ReadableArray faceCenter)
|
|
157
|
+
public void setFaceCenter(ReadableArray faceCenter) {
|
|
125
158
|
mFaceCenter = faceCenter;
|
|
126
159
|
}
|
|
127
160
|
|
|
128
|
-
public void setImageQuality(String imageQuality)
|
|
161
|
+
public void setImageQuality(String imageQuality) {
|
|
129
162
|
if (imageQuality.equals(ImageQuality.LOW.toString())) {
|
|
130
163
|
mImageQuality = ImageQuality.LOW;
|
|
131
164
|
return;
|
|
@@ -168,13 +201,21 @@ public class YotiFaceCaptureView extends LinearLayout {
|
|
|
168
201
|
public void startAnalyzing() {
|
|
169
202
|
PointF faceCenter = new PointF((float) mFaceCenter.getDouble(0), (float) mFaceCenter.getDouble(1));
|
|
170
203
|
|
|
204
|
+
// Configuration flags not available for FCM variant
|
|
205
|
+
final boolean isSelfCheckoutMode = false;
|
|
206
|
+
final boolean provideLandmarks = false;
|
|
207
|
+
final boolean provideSmileScore = false;
|
|
208
|
+
|
|
171
209
|
FaceCaptureConfiguration configuration = new FaceCaptureConfiguration(
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
210
|
+
faceCenter,
|
|
211
|
+
mImageQuality,
|
|
212
|
+
mRequireValidAngle,
|
|
213
|
+
mRequireEyesOpen,
|
|
214
|
+
mRequireBrightEnvironment,
|
|
215
|
+
mRequiredStableFrames,
|
|
216
|
+
provideLandmarks,
|
|
217
|
+
provideSmileScore,
|
|
218
|
+
isSelfCheckoutMode
|
|
178
219
|
);
|
|
179
220
|
mFaceCapture.startAnalysing(configuration, mFaceCaptureListener);
|
|
180
221
|
}
|
|
@@ -182,4 +223,19 @@ public class YotiFaceCaptureView extends LinearLayout {
|
|
|
182
223
|
public void stopAnalyzing() {
|
|
183
224
|
mFaceCapture.stopAnalysing();
|
|
184
225
|
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Clean up resources when the view is dropped.
|
|
229
|
+
* Called from ViewManager.onDropViewInstance()
|
|
230
|
+
*/
|
|
231
|
+
public void cleanup() {
|
|
232
|
+
isCleanedUp = true;
|
|
233
|
+
Choreographer.getInstance().removeFrameCallback(frameCallback);
|
|
234
|
+
try {
|
|
235
|
+
mFaceCapture.stopAnalysing();
|
|
236
|
+
mFaceCapture.stopCamera();
|
|
237
|
+
} catch (Exception e) {
|
|
238
|
+
// Ignore cleanup errors
|
|
239
|
+
}
|
|
240
|
+
}
|
|
185
241
|
}
|
package/android/src/main/java/com/yoti/reactnative/facecapture/YotiFaceCaptureViewManager.java
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package com.yoti.reactnative.facecapture;
|
|
2
2
|
|
|
3
3
|
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
4
5
|
|
|
5
6
|
import com.facebook.react.bridge.ReadableArray;
|
|
6
7
|
import com.facebook.react.common.MapBuilder;
|
|
@@ -21,10 +22,12 @@ public class YotiFaceCaptureViewManager extends SimpleViewManager<YotiFaceCaptur
|
|
|
21
22
|
|
|
22
23
|
@Override
|
|
23
24
|
@NonNull
|
|
24
|
-
public YotiFaceCaptureView createViewInstance(ThemedReactContext reactContext) {
|
|
25
|
+
public YotiFaceCaptureView createViewInstance(@NonNull ThemedReactContext reactContext) {
|
|
25
26
|
return new YotiFaceCaptureView(reactContext);
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
@Override
|
|
30
|
+
@Nullable
|
|
28
31
|
public Map getExportedCustomBubblingEventTypeConstants() {
|
|
29
32
|
return MapBuilder.builder()
|
|
30
33
|
.put(
|
|
@@ -40,6 +43,12 @@ public class YotiFaceCaptureViewManager extends SimpleViewManager<YotiFaceCaptur
|
|
|
40
43
|
.build();
|
|
41
44
|
}
|
|
42
45
|
|
|
46
|
+
@Override
|
|
47
|
+
public void onDropViewInstance(@NonNull YotiFaceCaptureView view) {
|
|
48
|
+
view.cleanup();
|
|
49
|
+
super.onDropViewInstance(view);
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
@ReactProp(name = "faceCenter")
|
|
44
53
|
public void setFaceCenter(YotiFaceCaptureView view, ReadableArray faceCenter) throws Exception {
|
|
45
54
|
try {
|