google / google/jetpack-camera-app
[Bug] Settings screen renders blank after process recreation due to uninitialized CameraSystemConstraints
- Dominant language
- Kotlin
- Stars
- 341
- Forks
- 71
- Avg merge
- 4d 17h
- Merged PRs (30d)
- 7
Description
When the app process is terminated while in the background on the Settings screen (e.g., via OS memory reclamation, developer options "Don't keep activities", or when revoking a permission in System Settings), returning to the app restores `SettingsScreen` from the navigation backstack, but all settings items fail to render. The user is presented with a blank screen showing only the top header ("Settings") and the back button.
Navigating back to `PreviewScreen` and returning to `SettingsScreen` recovers the UI.
## Steps to Reproduce
1. Open the app and navigate to the **Settings** screen.
2. Background the app.
3. Terminate the app process in the background (e.g., revoke any permission in Android System Settings, enable "Don't keep activities" in Developer Options, or run `adb shell am kill com.google.jetpackcamera`).
4. Reopen the app from Recents.
5. Observe the `SettingsScreen`.
## Expected Behavior
`SettingsScreen` should render all available settings options upon process recreation, or display a loading indicator while fetching hardware constraints. Furthermore, if a critical permission (such as `CAMERA`) was revoked while backgrounded, the app should guard navigation and route back to the permissions onboarding flow.
## Actual Behavior
The settings list is completely empty; only the top app bar is drawn.
## Root Cause
1. **Coupled Constraints Lifecycle**: `SettingsViewModel` combines with `constraintsRepository.systemConstraints.filterNotNull()` to construct `SettingsUiState.Enabled`.
2. **In-Memory Singleton Reset**: `SettableConstraintsRepositoryImpl` is an in-memory singleton whose `_systemConstraints` initializes to `null` on new process creation.
3. **Bypassed Preview Initialization**: `constraintsRepository.updateSystemConstraints(...)` is currently only called inside `PreviewViewModel.init` when the viewfinder is active. Because Compose Navigation restores `SettingsScreen` as the top backstack destination after process death, `PreviewScreen` and `PreviewViewModel` never run.
4. **Permanent Flow Suspension**: `constraintsRepository.systemConstraints.filterNotNull()` suspends indefinitely waiting for a non-null emission. `SettingsViewModel.settingsUiState` remains stuck on its initial `SettingsUiState.Disabled` state, which renders an empty `Column` in `SettingsScreen`.
5. **Missing Mandatory Permission Guard**: If `CAMERA` permission was revoked during process termination, `SettingsScreen` has no top-level guard checking whether baseline permissions are still held.
## Proposed Solutions
1. **Decouple Constraint Discovery from the Preview Lifecycle**:
- Allow `ConstraintsRepository` (or `CameraSystem`) to query camera characteristics directly via `ProcessCameraProvider` on demand in the background. Querying camera characteristics (lenses, supported resolutions, flash, video capabilities) does not require active camera streaming or runtime camera permissions.
2. **Handle Loading / Fallback States in Settings**:
- Add a proper `Loading` state or display default/fallback constraints in `SettingsViewModel` rather than hanging indefinitely on an empty `SettingsUiState.Disabled`.
3. **Root Navigation Permission Guard**:
- On process restoration, verify baseline mandatory permissions (`CAMERA`). If missing, clear the backstack and route to `PermissionsRoute` to prevent child screens from restoring in an unexecutable state.
Contributor guide
Assessment
This issue has not been assessed yet.