Skip to content

Commit 985b67c

Browse files
committed
Add code for error scenarios
1 parent d66363f commit 985b67c

File tree

7 files changed

+48
-15
lines changed

7 files changed

+48
-15
lines changed

HostApp/HostApp.xcodeproj/project.pbxproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
9070FFBD285112B5009867D5 /* HostAppUITests */,
132132
9070FFA1285112B4009867D5 /* Products */,
133133
90215EED291E9FB60050F2AD /* Frameworks */,
134+
A5A9AF5054D0FF13505B212A /* AmplifyConfig */,
134135
);
135136
sourceTree = "<group>";
136137
};
@@ -213,6 +214,15 @@
213214
path = Model;
214215
sourceTree = "<group>";
215216
};
217+
A5A9AF5054D0FF13505B212A /* AmplifyConfig */ = {
218+
isa = PBXGroup;
219+
children = (
220+
973619242BA378690003A590 /* awsconfiguration.json */,
221+
973619232BA378690003A590 /* amplifyconfiguration.json */,
222+
);
223+
name = AmplifyConfig;
224+
sourceTree = "<group>";
225+
};
216226
/* End PBXGroup section */
217227

218228
/* Begin PBXNativeTarget section */

HostApp/HostApp/Views/ExampleLivenessView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ struct ExampleLivenessView: View {
2323
FaceLivenessDetectorView(
2424
sessionID: viewModel.sessionID,
2525
region: "us-east-1",
26-
cameraPosition: .front,
26+
cameraPosition: .back,
2727
isPresented: Binding(
2828
get: { viewModel.presentationState == .liveness },
2929
set: { _ in }

Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionError.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ public struct FaceLivenessDetectionError: Error, Equatable {
125125
message: "The signature on the request is invalid.",
126126
recoverySuggestion: "Ensure the device time is correct and try again."
127127
)
128+
129+
public static let invalidCameraPositionSelected = FaceLivenessDetectionError(
130+
code: 18,
131+
message: "The camera position selected is incompatible with the liveness challenge type requested.",
132+
recoverySuggestion: "Please ensure the camera position is supported for the liveness challenge type requested."
133+
)
128134

129135
public static let cameraNotAvailable = FaceLivenessDetectionError(
130136
code: 18,

Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionView.swift

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public struct FaceLivenessDetectorView: View {
3030
credentialsProvider: AWSCredentialsProvider? = nil,
3131
region: String,
3232
disableStartView: Bool = false,
33-
cameraPosition: LivenessCaptureDevicePosition,
33+
cameraPosition: LivenessCaptureDevicePosition = .front,
3434
isPresented: Binding<Bool>,
3535
onCompletion: @escaping (Result<Void, FaceLivenessDetectionError>) -> Void
3636
) {
@@ -59,15 +59,14 @@ public struct FaceLivenessDetectorView: View {
5959
assetWriterDelegate: VideoChunker.AssetWriterDelegate(),
6060
assetWriterInput: LivenessAVAssetWriterInput()
6161
)
62-
63-
let avCpatureDevice = AVCaptureDevice.DiscoverySession(
64-
deviceTypes: [.builtInWideAngleCamera],
65-
mediaType: .video,
66-
position: cameraPosition == .front ? .front : .back
67-
).devices.first
62+
63+
let avCaptureDevice = AVCaptureDevice.default(
64+
.builtInWideAngleCamera,
65+
for: .video,
66+
position: cameraPosition == .front ? .front : .back)
6867

6968
let captureSession = LivenessCaptureSession(
70-
captureDevice: .init(avCaptureDevice: avCpatureDevice),
69+
captureDevice: .init(avCaptureDevice: avCaptureDevice),
7170
outputDelegate: OutputSampleBufferCapturer(
7271
faceDetector: faceDetector,
7372
videoChunker: videoChunker
@@ -82,7 +81,8 @@ public struct FaceLivenessDetectorView: View {
8281
videoChunker: videoChunker,
8382
closeButtonAction: { onCompletion(.failure(.userCancelled)) },
8483
sessionID: sessionID,
85-
isPreviewScreenEnabled: !disableStartView
84+
isPreviewScreenEnabled: !disableStartView,
85+
cameraPosition: cameraPosition
8686
)
8787
)
8888
}
@@ -124,7 +124,8 @@ public struct FaceLivenessDetectorView: View {
124124
videoChunker: captureSession.outputSampleBufferCapturer!.videoChunker,
125125
closeButtonAction: { onCompletion(.failure(.userCancelled)) },
126126
sessionID: sessionID,
127-
isPreviewScreenEnabled: !disableStartView
127+
isPreviewScreenEnabled: !disableStartView,
128+
cameraPosition: cameraPosition
128129
)
129130
)
130131
}

Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel.swift

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class FaceLivenessDetectionViewModel: ObservableObject {
4444
var initialClientEvent: InitialClientEvent?
4545
var faceMatchedTimestamp: UInt64?
4646
var noFitStartTime: Date?
47+
let cameraPosition: LivenessCaptureDevicePosition
4748

4849
static var attemptCount: Int = 0
4950
static var attemptIdTimeStamp: Date = Date()
@@ -64,7 +65,8 @@ class FaceLivenessDetectionViewModel: ObservableObject {
6465
stateMachine: LivenessStateMachine = .init(state: .initial),
6566
closeButtonAction: @escaping () -> Void,
6667
sessionID: String,
67-
isPreviewScreenEnabled: Bool
68+
isPreviewScreenEnabled: Bool,
69+
cameraPosition: LivenessCaptureDevicePosition
6870
) {
6971
self.closeButtonAction = closeButtonAction
7072
self.videoChunker = videoChunker
@@ -74,6 +76,7 @@ class FaceLivenessDetectionViewModel: ObservableObject {
7476
self.faceDetector = faceDetector
7577
self.faceInOvalMatching = faceInOvalMatching
7678
self.isPreviewScreenEnabled = isPreviewScreenEnabled
79+
self.cameraPosition = cameraPosition
7780

7881
self.closeButtonAction = { [weak self] in
7982
guard let self else { return }
@@ -124,7 +127,18 @@ class FaceLivenessDetectionViewModel: ObservableObject {
124127
livenessService?.register(
125128
listener: { [weak self] _challenge in
126129
self?.challenge = _challenge
127-
onChallengeTypeReceived(_challenge)
130+
guard _challenge.type == .faceMovementAndLightChallenge,
131+
self?.cameraPosition == .back else {
132+
onChallengeTypeReceived(_challenge)
133+
return
134+
}
135+
136+
// incompatible camera position with challenge type
137+
// return error
138+
DispatchQueue.main.async {
139+
self?.livenessState
140+
.unrecoverableStateEncountered(.invalidCameraPositionSelecteed)
141+
}
128142
},
129143
on: .challenge)
130144
}

Tests/FaceLivenessTests/CredentialsProviderTestCase.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ final class CredentialsProviderTestCase: XCTestCase {
4242
videoChunker: videoChunker,
4343
closeButtonAction: {},
4444
sessionID: UUID().uuidString,
45-
isPreviewScreenEnabled: false
45+
isPreviewScreenEnabled: false,
46+
cameraPosition: .front
4647
)
4748

4849
self.videoChunker = videoChunker

Tests/FaceLivenessTests/LivenessTests.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ final class FaceLivenessDetectionViewModelTestCase: XCTestCase {
3333
videoChunker: videoChunker,
3434
closeButtonAction: {},
3535
sessionID: UUID().uuidString,
36-
isPreviewScreenEnabled: false
36+
isPreviewScreenEnabled: false,
37+
cameraPosition: .front
3738
)
3839

3940
self.videoChunker = videoChunker

0 commit comments

Comments
 (0)