Skip to content

Commit 5d469c1

Browse files
tjleingThomas Leing
andauthored
fix(liveness): Screen rotation saves/loads correctly; lifecycle not destroyed at time of use (#65)
Co-authored-by: Thomas Leing <[email protected]>
1 parent b640361 commit 5d469c1

File tree

3 files changed

+59
-47
lines changed

3 files changed

+59
-47
lines changed

liveness/src/main/java/com/amplifyframework/ui/liveness/camera/LivenessCoordinator.kt

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import androidx.camera.core.ImageAnalysis
2626
import androidx.camera.core.Preview
2727
import androidx.camera.lifecycle.ProcessCameraProvider
2828
import androidx.core.content.ContextCompat
29+
import androidx.lifecycle.Lifecycle
2930
import androidx.lifecycle.LifecycleOwner
3031
import com.amplifyframework.auth.AWSCredentials
3132
import com.amplifyframework.auth.AWSCredentialsProvider
@@ -136,20 +137,22 @@ internal class LivenessCoordinator(
136137
init {
137138
MainScope().launch {
138139
getCameraProvider(context).apply {
139-
unbindAll()
140-
if (this.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)) {
141-
bindToLifecycle(
142-
lifecycleOwner,
143-
CameraSelector.DEFAULT_FRONT_CAMERA,
144-
preview,
145-
analysis
146-
)
147-
} else {
148-
val faceLivenessException = FaceLivenessDetectionException(
149-
"A front facing camera is required but no front facing camera detected.",
150-
"Enable a front facing camera."
151-
)
152-
processSessionError(faceLivenessException, true)
140+
if (lifecycleOwner.lifecycle.currentState != Lifecycle.State.DESTROYED) {
141+
unbindAll()
142+
if (this.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)) {
143+
bindToLifecycle(
144+
lifecycleOwner,
145+
CameraSelector.DEFAULT_FRONT_CAMERA,
146+
preview,
147+
analysis
148+
)
149+
} else {
150+
val faceLivenessException = FaceLivenessDetectionException(
151+
"A front facing camera is required but no front facing camera detected.",
152+
"Enable a front facing camera."
153+
)
154+
processSessionError(faceLivenessException, true)
155+
}
153156
}
154157
}
155158
}

liveness/src/main/java/com/amplifyframework/ui/liveness/ui/FaceLivenessDetector.kt

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -109,33 +109,35 @@ fun FaceLivenessDetector(
109109
}
110110

111111
// Locks portrait orientation for duration of challenge and resets on complete
112-
LockPortraitOrientation()
113-
114-
Surface(color = MaterialTheme.colorScheme.background) {
115-
if (showReadyView) {
116-
GetReadyView {
117-
showReadyView = false
118-
}
119-
} else {
120-
AlwaysOnMaxBrightnessScreen()
121-
ChallengeView(
122-
key = key,
123-
sessionId = sessionId,
124-
region,
125-
credentialsProvider = credentialsProvider,
126-
onChallengeComplete = {
127-
scope.launch {
128-
isFinished = true
129-
currentOnComplete.call()
130-
}
131-
},
132-
onChallengeFailed = {
133-
scope.launch {
134-
isFinished = true
135-
currentOnError.accept(it)
136-
}
112+
LockPortraitOrientation { resetOrientation ->
113+
Surface(color = MaterialTheme.colorScheme.background) {
114+
if (showReadyView) {
115+
GetReadyView {
116+
showReadyView = false
137117
}
138-
)
118+
} else {
119+
AlwaysOnMaxBrightnessScreen()
120+
ChallengeView(
121+
key = key,
122+
sessionId = sessionId,
123+
region,
124+
credentialsProvider = credentialsProvider,
125+
onChallengeComplete = {
126+
scope.launch {
127+
isFinished = true
128+
resetOrientation()
129+
currentOnComplete.call()
130+
}
131+
},
132+
onChallengeFailed = {
133+
scope.launch {
134+
isFinished = true
135+
resetOrientation()
136+
currentOnError.accept(it)
137+
}
138+
}
139+
)
140+
}
139141
}
140142
}
141143
}
@@ -191,7 +193,6 @@ internal fun ChallengeView(
191193
)
192194
}
193195
) {
194-
195196
val videoViewportSize = livenessState.videoViewportSize
196197

197198
if (videoViewportSize != null) {

liveness/src/main/java/com/amplifyframework/ui/liveness/ui/LockPortraitOrientation.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,28 @@ package com.amplifyframework.ui.liveness.ui
1717

1818
import android.annotation.SuppressLint
1919
import android.content.pm.ActivityInfo
20+
import android.content.res.Configuration.ORIENTATION_PORTRAIT
2021
import androidx.compose.runtime.Composable
21-
import androidx.compose.runtime.DisposableEffect
22+
import androidx.compose.runtime.SideEffect
23+
import androidx.compose.runtime.getValue
24+
import androidx.compose.runtime.mutableStateOf
25+
import androidx.compose.runtime.saveable.rememberSaveable
2226
import androidx.compose.ui.platform.LocalContext
2327
import com.amplifyframework.ui.liveness.util.findActivity
2428

2529
@SuppressLint("SourceLockedOrientationActivity")
2630
@Composable
27-
internal fun LockPortraitOrientation() {
31+
internal fun LockPortraitOrientation(content: @Composable (resetOrientation: () -> Unit) -> Unit) {
2832
val context = LocalContext.current
29-
DisposableEffect(Unit) {
30-
val activity = context.findActivity() ?: return@DisposableEffect onDispose {}
31-
val originalOrientation = activity.requestedOrientation
33+
val activity = context.findActivity() ?: return content {}
34+
val originalOrientation by rememberSaveable { mutableStateOf(activity.requestedOrientation) }
35+
SideEffect {
3236
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
33-
onDispose {
37+
}
38+
39+
// wait until screen is rotated correctly
40+
if (activity.resources.configuration.orientation == ORIENTATION_PORTRAIT) {
41+
content {
3442
activity.requestedOrientation = originalOrientation
3543
}
3644
}

0 commit comments

Comments
 (0)