From bebdb60823db5d2a2880255aa46ac4972a61f692 Mon Sep 17 00:00:00 2001 From: Tuan Pham <103537251+phantumcode@users.noreply.github.com> Date: Thu, 7 Dec 2023 13:08:55 -0600 Subject: [PATCH 1/2] chore: update integration test to match latest UX updates (#91) --- .../LivenessIntegrationUITests.swift | 13 ++++--------- .../IntegrationTestAppUITests/UIConstants.swift | 9 ++++----- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Tests/IntegrationTestApp/IntegrationTestAppUITests/LivenessIntegrationUITests.swift b/Tests/IntegrationTestApp/IntegrationTestAppUITests/LivenessIntegrationUITests.swift index 237dafec..95db95bc 100644 --- a/Tests/IntegrationTestApp/IntegrationTestAppUITests/LivenessIntegrationUITests.swift +++ b/Tests/IntegrationTestApp/IntegrationTestAppUITests/LivenessIntegrationUITests.swift @@ -26,11 +26,9 @@ class CreateLivenessSessionUITests: XCTestCase { Thread.sleep(forTimeInterval: 2) XCTAssert(app!.buttons[UIConstants.BeginCheck.primaryButton].exists) XCTAssertFalse(app!.buttons[UIConstants.primaryButton].exists) - let scrollViewsQuery = app!.scrollViews - let elementsQuery = scrollViewsQuery.otherElements - XCTAssertEqual(elementsQuery.staticTexts.element(boundBy: 1).label, UIConstants.BeginCheck.description) - XCTAssert(elementsQuery.buttons[UIConstants.BeginCheck.warning].exists) - XCTAssert(elementsQuery.staticTexts[UIConstants.BeginCheck.instruction].exists) + XCTAssert(app!.staticTexts[UIConstants.BeginCheck.warningTitle].exists) + XCTAssert(app!.staticTexts[UIConstants.BeginCheck.warningDescription].exists) + XCTAssert(app!.staticTexts[UIConstants.BeginCheck.instruction].exists) } func testStartLivenessIntegration() throws { @@ -40,14 +38,11 @@ class CreateLivenessSessionUITests: XCTestCase { app?.buttons[UIConstants.primaryButton].tap() Thread.sleep(forTimeInterval: 2) XCTAssert(app!.buttons[UIConstants.BeginCheck.primaryButton].exists) - XCTAssertFalse(app!.buttons[UIConstants.primaryButton].exists) app!.buttons[UIConstants.BeginCheck.primaryButton].tap() Thread.sleep(forTimeInterval: 2) - XCTAssert(app!.staticTexts[UIConstants.LivenessCheck.countdownInstruction].exists) XCTAssert(app!.buttons[UIConstants.LivenessCheck.closeButton].exists) - Thread.sleep(forTimeInterval: 3) XCTAssert(app!.staticTexts[UIConstants.LivenessCheck.moveInstruction].exists) - Thread.sleep(forTimeInterval: 3) + Thread.sleep(forTimeInterval: 4) XCTAssert(app!.staticTexts[UIConstants.LivenessCheck.holdInstruction].exists) Thread.sleep(forTimeInterval: 8) XCTAssert(app!.buttons[UIConstants.LivenessResult.primaryButton].exists) diff --git a/Tests/IntegrationTestApp/IntegrationTestAppUITests/UIConstants.swift b/Tests/IntegrationTestApp/IntegrationTestAppUITests/UIConstants.swift index 12b8e392..04a5db64 100644 --- a/Tests/IntegrationTestApp/IntegrationTestAppUITests/UIConstants.swift +++ b/Tests/IntegrationTestApp/IntegrationTestAppUITests/UIConstants.swift @@ -10,14 +10,13 @@ struct UIConstants { static let primaryButton = "Create Liveness Session" struct BeginCheck { - static let primaryButton = "Begin Check" - static let description = "You will go through a face verification process to prove that you are a real person. Your screen's brightness will temporarily be set to 100% for highest accuracy." - static let warning = "Photosensitivity Warning, This check displays colored lights. Use caution if you are photosensitive." - static let instruction = "Follow the instructions to complete the check:" + static let primaryButton = "Start video check" + static let warningTitle = "Photosensitivity Warning" + static let warningDescription = "This check flashes different colors. Use caution if you are photosensitive." + static let instruction = "Center your face" } struct LivenessCheck { - static let countdownInstruction = "Hold face position during countdown." static let moveInstruction = "Move closer" static let holdInstruction = "Hold still" static let closeButton = "Close" From b28c192d1b6505b57f0d290f6349cf296cc24f6c Mon Sep 17 00:00:00 2001 From: Tuan Pham <103537251+phantumcode@users.noreply.github.com> Date: Wed, 10 Jan 2024 16:14:43 +0000 Subject: [PATCH 2/2] fix: resolve race condition when starting AVCaptureSession (#93) --- Sources/FaceLiveness/AV/LivenessCaptureSession.swift | 7 +++---- .../Views/Liveness/FaceLivenessDetectionView.swift | 3 +++ .../Views/Liveness/LivenessViewController.swift | 7 +++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Sources/FaceLiveness/AV/LivenessCaptureSession.swift b/Sources/FaceLiveness/AV/LivenessCaptureSession.swift index 9cd8eccf..f8400262 100644 --- a/Sources/FaceLiveness/AV/LivenessCaptureSession.swift +++ b/Sources/FaceLiveness/AV/LivenessCaptureSession.swift @@ -11,6 +11,7 @@ import AVFoundation class LivenessCaptureSession { let captureDevice: LivenessCaptureDevice private let captureQueue = DispatchQueue(label: "com.amazonaws.faceliveness.cameracapturequeue") + private let configurationQueue = DispatchQueue(label: "com.amazonaws.faceliveness.sessionconfiguration", qos: .userInitiated) let outputDelegate: AVCaptureVideoDataOutputSampleBufferDelegate var captureSession: AVCaptureSession? @@ -43,6 +44,7 @@ class LivenessCaptureSession { else { throw LivenessCaptureSessionError.cameraUnavailable } let cameraInput = try AVCaptureDeviceInput(device: camera) + let videoOutput = AVCaptureVideoDataOutput() teardownExistingSession(input: cameraInput) captureSession = AVCaptureSession() @@ -53,13 +55,10 @@ class LivenessCaptureSession { try setupInput(cameraInput, for: captureSession) captureSession.sessionPreset = captureDevice.preset - - let videoOutput = AVCaptureVideoDataOutput() try setupOutput(videoOutput, for: captureSession) - try captureDevice.configure() - DispatchQueue.global().async { + configurationQueue.async { captureSession.startRunning() } diff --git a/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionView.swift b/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionView.swift index 64098e5f..320da58e 100644 --- a/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionView.swift +++ b/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionView.swift @@ -172,6 +172,9 @@ public struct FaceLivenessDetectorView: View { UIScreen.main.brightness = 1.0 } } + .onDisappear() { + viewModel.stopRecording() + } .onReceive(viewModel.$livenessState) { output in switch output.state { case .completed: diff --git a/Sources/FaceLiveness/Views/Liveness/LivenessViewController.swift b/Sources/FaceLiveness/Views/Liveness/LivenessViewController.swift index 0189c3c8..5e5111a7 100644 --- a/Sources/FaceLiveness/Views/Liveness/LivenessViewController.swift +++ b/Sources/FaceLiveness/Views/Liveness/LivenessViewController.swift @@ -37,6 +37,12 @@ final class _LivenessViewController: UIViewController { } } } + + deinit { + self.previewLayer.removeFromSuperlayer() + (self.previewLayer as? AVCaptureVideoPreviewLayer)?.session = nil + self.previewLayer = nil + } override func viewDidLoad() { super.viewDidLoad() @@ -110,6 +116,7 @@ extension _LivenessViewController: FaceLivenessViewControllerPresenter { imageView.frame = self.previewLayer.frame self.view.addSubview(imageView) self.previewLayer.removeFromSuperlayer() + (self.previewLayer as? AVCaptureVideoPreviewLayer)?.session = nil self.viewModel.stopRecording() } }