@@ -27,6 +27,7 @@ import com.amplifyframework.predictions.models.FaceLivenessSessionInformation
2727import com.amplifyframework.predictions.options.FaceLivenessSessionOptions
2828import com.amplifyframework.ui.liveness.camera.FrameAnalyzer
2929import com.amplifyframework.ui.liveness.ml.FaceDetector
30+ import com.amplifyframework.ui.liveness.model.LivenessCheckState
3031import com.amplifyframework.ui.liveness.state.LivenessState
3132import com.amplifyframework.ui.liveness.ui.FaceLivenessDetector
3233import io.mockk.CapturingSlot
@@ -66,7 +67,8 @@ class LivenessFlowInstrumentationTest {
6667 private lateinit var noFaceString: String
6768 private lateinit var multipleFaceString: String
6869 private lateinit var connectingString: String
69- private lateinit var countdownString: String
70+ private lateinit var moveCloserString: String
71+ private lateinit var holdStillString: String
7072
7173 @get:Rule
7274 val composeTestRule = createComposeRule()
@@ -102,8 +104,9 @@ class LivenessFlowInstrumentationTest {
102104 R .string.amplify_ui_liveness_challenge_instruction_multiple_faces_detected,
103105 )
104106 connectingString = context.getString(R .string.amplify_ui_liveness_challenge_connecting)
105- countdownString = context.getString(
106- R .string.amplify_ui_liveness_challenge_instruction_hold_face_during_countdown,
107+ moveCloserString = context.getString(R .string.amplify_ui_liveness_challenge_instruction_move_face_closer)
108+ holdStillString = context.getString(
109+ R .string.amplify_ui_liveness_challenge_instruction_hold_face_during_freshness,
107110 )
108111 }
109112
@@ -303,10 +306,11 @@ class LivenessFlowInstrumentationTest {
303306 every { faceTargetMatchingParameters.faceIouHeightThreshold }.returns(0.15f )
304307
305308 val faceTargetChallenge = mockk<FaceTargetChallenge >()
306- every { faceTargetChallenge.targetWidth }.returns(422f )
307- every { faceTargetChallenge.targetHeight }.returns(683f )
308- every { faceTargetChallenge.targetCenterX }.returns(230f )
309- every { faceTargetChallenge.targetCenterY }.returns(292f )
309+ val faceRect = RectF (19f , - 49f , 441f , 633f )
310+ every { faceTargetChallenge.targetWidth }.returns(faceRect.right - faceRect.left)
311+ every { faceTargetChallenge.targetHeight }.returns(faceRect.bottom - faceRect.top)
312+ every { faceTargetChallenge.targetCenterX }.returns((faceRect.left + faceRect.right) / 2 )
313+ every { faceTargetChallenge.targetCenterY }.returns((faceRect.top + faceRect.bottom) / 2 )
310314 every { faceTargetChallenge.faceTargetMatching }.returns(faceTargetMatchingParameters)
311315
312316 val colors = listOf (
@@ -350,23 +354,44 @@ class LivenessFlowInstrumentationTest {
350354 ),
351355 )
352356
353- composeTestRule.waitUntil(5000 ) {
354- composeTestRule.onAllNodesWithText(" asdlkfjasdf" )
357+ // update face location to show oval
358+ livenessState?.onFrameFaceUpdate(
359+ RectF (0f , 0f , 400f , 400f ),
360+ FaceDetector .Landmark (60f , 60f ),
361+ FaceDetector .Landmark (140f , 60f ),
362+ FaceDetector .Landmark (100f , 160f ),
363+ )
364+
365+ // in the same spot as it was originally, the face is too far
366+ composeTestRule.waitUntil(1000 ) {
367+ composeTestRule.onAllNodesWithText(moveCloserString)
355368 .fetchSemanticsNodes().size == 1
356369 }
357370
358371 composeTestRule.waitForIdle()
359372
373+ // update face to be inside the oval position
374+ livenessState?.onFrameFaceUpdate(
375+ faceRect,
376+ FaceDetector .Landmark (60f , 60f ),
377+ FaceDetector .Landmark (140f , 60f ),
378+ FaceDetector .Landmark (100f , 160f ),
379+ )
380+
381+ // now, the face is inside the oval. wait for the colors to finish
382+ composeTestRule.waitForIdle()
383+
384+ assertTrue(livenessState?.readyToSendFinalEvents == true )
385+ val state = livenessState?.livenessCheckState?.value
386+ assertTrue(state is LivenessCheckState .Success )
387+ assertTrue((state as LivenessCheckState .Success ).faceGuideRect == faceRect)
388+
360389 onLivenessComplete.captured.call()
361390 assertTrue(completesSuccessfully)
362391
363392 unmockkConstructor(FrameAnalyzer ::class )
364393 }
365394
366- // TODO: this gets to the camera page! next up:
367- // 1. figure out how to trigger the next step
368- // 2. test on virtual device, might be fine...
369-
370395 companion object {
371396 @BeforeClass
372397 @JvmStatic
0 commit comments