aws-amplify / aws-amplify/amplify-ui-android
FaceLivenessDetector fails on Android 8 (API 26-27): "no front facing camera detected" on devices with a working front camera
- Dominant language
- Kotlin
- Stars
- 25
- Forks
- 18
- Avg merge
- 7d 3h
- Merged PRs (30d)
- 1
Description
### Before creating a new issue, please confirm:
- [x] I have [searched for duplicate or closed issues](https://github.com/aws-amplify/amplify-ui-android/issues?q=is%3Aissue+).
- [x] I have read the guide for [submitting bug reports](https://github.com/aws-amplify/amplify-ui-android/blob/main/CONTRIBUTING.md#reporting-bugsfeature-requests).
### Which UI component?
Liveness
### Gradle script dependencies
implementation "com.amplifyframework.ui:liveness:$rootProject.properties.aws_liveness"
### Environment information
```
# Put output below this line
## Environment
- **Liveness SDK version:** `com.amplifyframework.ui:liveness:1.7.0` (also confirmed on `1.10.0`)
- **CameraX version (transitive):** `androidx.camera:camera-*:1.4.2`
- **Affected Android version:** Android 8.0 / 8.1 (API 26-27)
- **Not affected:** Android 9+ (API 28+)
- **Previous working version:** `com.amplifyframework.ui:liveness:1.5.0` (worked on the same device)
```
### Please include any relevant guides or documentation you're referencing
_No response_
### Describe the bug
# FaceLivenessDetector fails on Android 8 (API 26-27): "no front facing camera detected" on devices with a working front camera
## Description
`FaceLivenessDetector` throws `FaceLivenessDetectionException` with the message _"A front facing camera is required but no front facing camera detected"_ on certain Android 8 (API 26-27) devices that have a fully functional front-facing camera.
The root cause is that `LivenessCoordinator` relies on `ProcessCameraProvider.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)` to detect the front camera. `CameraSelector.DEFAULT_FRONT_CAMERA` internally checks `CameraCharacteristics.LENS_FACING == LENS_FACING_FRONT (0)`. On affected Android 8 devices, the Camera2 HAL incorrectly reports **both** cameras (front and back) as `LENS_FACING_BACK (1)`, causing the check to fail.
## Relevant SDK code
`LivenessCoordinator.kt`, `launchCamera()` method:
```kotlin
val (chosenCamera, orientation) = when (camera) {
Camera.Front -> Pair(CameraSelector.DEFAULT_FRONT_CAMERA, "front")
Camera.Back -> Pair(CameraSelector.DEFAULT_BACK_CAMERA, "back")
}
if (this.hasCamera(chosenCamera)) {
bindToLifecycle(lifecycleOwner, chosenCamera, preview, analysis)
} else {
// Error: "A front facing camera is required but no front facing camera detected."
val faceLivenessException = FaceLivenessDetectionException(
"A $orientation facing camera is required but no $orientation facing camera detected.",
"Enable a $orientation facing camera."
)
processSessionError(faceLivenessException, true)
}
```
## Evidence
We verified the issue by querying `CameraManager` directly on the affected device:
```kotlin
val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
val ids = cameraManager.cameraIdList
// ids = ["0", "1"] — two cameras exist
for (id in ids) {
val facing = cameraManager.getCameraCharacteristics(id)
.get(CameraCharacteristics.LENS_FACING)
Log.i(TAG, "camera id=$id, LENS_FACING=$facing")
}
```
**Output on affected Android 8 device:**
```
camera id=0, LENS_FACING=1 // LENS_FACING_BACK
camera id=1, LENS_FACING=1 // LENS_FACING_BACK ← should be 0 (LENS_FACING_FRONT)
```
Both cameras report `LENS_FACING_BACK(1)` despite the device having a working front camera (confirmed by other camera apps). The Camera2 HAL on this device is broken.
**Camera permission** is granted (`checkSelfPermission == PERMISSION_GRANTED`) at the time of the check.
## Expected behavior
`FaceLivenessDetector` should successfully open the front camera and start the liveness session on devices that have a physically working front camera.
## Actual behavior
`FaceLivenessDetector` immediately fails with:
```
FaceLivenessDetectionException: A front facing camera is required but no front facing camera detected.
```
## Suggested fix
Consider adding a fallback in `LivenessCoordinator.launchCamera()` for cases where `ProcessCameraProvider.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)` returns `false` but the device has multiple cameras. Possible approaches:
1. **Fallback to camera count heuristic:** If `hasCamera(DEFAULT_FRONT_CAMERA)` fails and `cameraIdList.size >= 2`, attempt to bind with `DEFAULT_FRONT_CAMERA` anyway — CameraX may still be able to open it even if `hasCamera` reports false.
2. **Use a custom CameraSelector** that selects by camera ID rather than `LENS_FACING`:
```kotlin
// Fallback: try camera ID "1" which is typically front on most devices
val fallbackSelector = CameraSelector.Builder()
.addCameraFilter { cameras -> cameras.filter { it.cameraId == "1" } }
.build()
```
3. **Document minimum supported API level:** If Android 8 support is not feasible due to Camera2 HAL inconsistencies, consider documenting API 28 (Android 9) as the minimum supported version for `FaceLivenessDetector` and failing gracefully with a clear error message.
## Current workaround
We gate the liveness feature to Android 9+ (API 28):
```kotlin
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
// Show error: face liveness not supported on this device
return
}
```
## Steps to reproduce
1. Use an Android 8 device where Camera2 HAL reports incorrect `LENS_FACING` for the front camera
2. Grant camera permission
3. Launch `FaceLivenessDetector` with a valid session ID
4. Observe the error in `onError` callback
### Reproduction steps (if applicable)
_No response_
### Code Snippet
```kotlin
// Put your code below this line.
```
### Log output
```
// Put your logs below this line
```
### Configuration File
_No response_
### Additional information and screenshots
_No response_
Contributor guide
Research direction
Start in LivenessCoordinator.kt at launchCamera(), then trace the CameraX ProcessCameraProvider.hasCamera and camera-binding path for the front selector. Reproduce on an affected Android 8 device and verify that a working front camera can start the liveness session without the no-front-camera error, while preserving behavior on Android 9+.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100