• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.jetpackcamera.feature.preview
17 
18 import android.util.Size
19 import com.google.jetpackcamera.core.camera.VideoRecordingState
20 import com.google.jetpackcamera.feature.preview.ui.ImageWellUiState
21 import com.google.jetpackcamera.feature.preview.ui.SnackbarData
22 import com.google.jetpackcamera.feature.preview.ui.ToastMessage
23 import com.google.jetpackcamera.settings.model.CameraAppSettings
24 import com.google.jetpackcamera.settings.model.CaptureMode
25 import com.google.jetpackcamera.settings.model.FlashMode
26 import com.google.jetpackcamera.settings.model.StabilizationMode
27 import com.google.jetpackcamera.settings.model.SystemConstraints
28 import com.google.jetpackcamera.settings.model.VideoQuality
29 
30 /**
31  * Defines the current state of the [PreviewScreen].
32  */
33 sealed interface PreviewUiState {
34     data object NotReady : PreviewUiState
35 
36     data class Ready(
37         // "quick" settings
38         val currentCameraSettings: CameraAppSettings = CameraAppSettings(),
39         val systemConstraints: SystemConstraints = SystemConstraints(),
40         val zoomScale: Float = 1f,
41         val videoRecordingState: VideoRecordingState = VideoRecordingState.Inactive(),
42         val quickSettingsIsOpen: Boolean = false,
43 
44         // todo: remove after implementing post capture screen
45         val toastMessageToShow: ToastMessage? = null,
46         val snackBarToShow: SnackbarData? = null,
47         val lastBlinkTimeStamp: Long = 0,
<lambda>null48         val previewMode: PreviewMode = PreviewMode.StandardMode {},
49         val captureModeToggleUiState: CaptureModeToggleUiState = CaptureModeToggleUiState.Invisible,
50         val sessionFirstFrameTimestamp: Long = 0L,
51         val currentPhysicalCameraId: String? = null,
52         val currentLogicalCameraId: String? = null,
53         val debugUiState: DebugUiState = DebugUiState(),
54         val stabilizationUiState: StabilizationUiState = StabilizationUiState.Disabled,
55         val flashModeUiState: FlashModeUiState = FlashModeUiState.Unavailable,
56         val videoQuality: VideoQuality = VideoQuality.UNSPECIFIED,
57         val audioUiState: AudioUiState = AudioUiState.Disabled,
58         val elapsedTimeUiState: ElapsedTimeUiState = ElapsedTimeUiState.Unavailable,
59         val captureButtonUiState: CaptureButtonUiState = CaptureButtonUiState.Unavailable,
60         val imageWellUiState: ImageWellUiState = ImageWellUiState.NoPreviousCapture
61     ) : PreviewUiState
62 }
63 
64 data class DebugUiState(
65     val cameraPropertiesJSON: String = "",
66     val videoResolution: Size? = null,
67     val isDebugMode: Boolean = false,
68     val isDebugOverlayOpen: Boolean = false
69 )
70 val DEFAULT_CAPTURE_BUTTON_STATE = CaptureButtonUiState.Enabled.Idle(CaptureMode.STANDARD)
71 
72 sealed interface CaptureButtonUiState {
73     data object Unavailable : CaptureButtonUiState
74     sealed interface Enabled : CaptureButtonUiState {
75         data class Idle(val captureMode: CaptureMode) : Enabled
76 
77         sealed interface Recording : Enabled {
78             data object PressedRecording : Recording
79             data object LockedRecording : Recording
80         }
81     }
82 }
83 sealed interface ElapsedTimeUiState {
84     data object Unavailable : ElapsedTimeUiState
85 
86     data class Enabled(val elapsedTimeNanos: Long) : ElapsedTimeUiState
87 }
88 
89 sealed interface AudioUiState {
90     val amplitude: Double
91 
92     sealed interface Enabled : AudioUiState {
93         data class On(override val amplitude: Double) : Enabled
94         data object Mute : Enabled {
95             override val amplitude = 0.0
96         }
97     }
98 
99     // todo give a disabledreason when audio permission is not granted
100     data object Disabled : AudioUiState {
101         override val amplitude = 0.0
102     }
103 }
104 
105 sealed interface StabilizationUiState {
106     data object Disabled : StabilizationUiState
107 
108     sealed interface Enabled : StabilizationUiState {
109         val stabilizationMode: StabilizationMode
110         val active: Boolean
111     }
112 
113     data class Specific(
114         override val stabilizationMode: StabilizationMode,
115         override val active: Boolean = true
116     ) : Enabled {
117         init {
<lambda>null118             require(stabilizationMode != StabilizationMode.AUTO) {
119                 "Specific StabilizationUiState cannot have AUTO stabilization mode."
120             }
121         }
122     }
123 
124     data class Auto(override val stabilizationMode: StabilizationMode) : Enabled {
125         override val active = true
126     }
127 }
128 
129 sealed class FlashModeUiState {
130     data object Unavailable : FlashModeUiState()
131 
132     data class Available(
133         val selectedFlashMode: FlashMode,
134         val availableFlashModes: List<FlashMode>,
135         val isActive: Boolean
136     ) : FlashModeUiState() {
137         init {
<lambda>null138             check(selectedFlashMode in availableFlashModes) {
139                 "Selected flash mode of $selectedFlashMode not in available modes: " +
140                     "$availableFlashModes"
141             }
142         }
143     }
144 
145     companion object {
146         private val ORDERED_UI_SUPPORTED_FLASH_MODES = listOf(
147             FlashMode.OFF,
148             FlashMode.ON,
149             FlashMode.AUTO,
150             FlashMode.LOW_LIGHT_BOOST
151         )
152 
153         /**
154          * Creates a FlashModeUiState from a selected flash mode and a set of supported flash modes
155          * that may not include flash modes supported by the UI.
156          */
createFromnull157         fun createFrom(
158             selectedFlashMode: FlashMode,
159             supportedFlashModes: Set<FlashMode>
160         ): FlashModeUiState {
161             // Ensure we at least support one flash mode
162             check(supportedFlashModes.isNotEmpty()) {
163                 "No flash modes supported. Should at least support OFF."
164             }
165 
166             // Convert available flash modes to list we support in the UI in our desired order
167             val availableModes = ORDERED_UI_SUPPORTED_FLASH_MODES.filter {
168                 it in supportedFlashModes
169             }
170 
171             return if (availableModes.isEmpty() || availableModes == listOf(FlashMode.OFF)) {
172                 // If we only support OFF, then return "Unavailable".
173                 Unavailable
174             } else {
175                 Available(
176                     selectedFlashMode = selectedFlashMode,
177                     availableFlashModes = availableModes,
178                     isActive = false
179                 )
180             }
181         }
182     }
183 }
184