• 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.settings
17 
18 import com.google.jetpackcamera.settings.DisabledRationale.DeviceUnsupportedRationale
19 import com.google.jetpackcamera.settings.DisabledRationale.LensUnsupportedRationale
20 import com.google.jetpackcamera.settings.model.AspectRatio
21 import com.google.jetpackcamera.settings.model.DEFAULT_CAMERA_APP_SETTINGS
22 import com.google.jetpackcamera.settings.model.DarkMode
23 import com.google.jetpackcamera.settings.model.FlashMode
24 import com.google.jetpackcamera.settings.model.LensFacing
25 import com.google.jetpackcamera.settings.model.StabilizationMode
26 import com.google.jetpackcamera.settings.model.StreamConfig
27 import com.google.jetpackcamera.settings.model.VideoQuality
28 import com.google.jetpackcamera.settings.ui.DEVICE_UNSUPPORTED_TAG
29 import com.google.jetpackcamera.settings.ui.FPS_UNSUPPORTED_TAG
30 import com.google.jetpackcamera.settings.ui.LENS_UNSUPPORTED_TAG
31 import com.google.jetpackcamera.settings.ui.PERMISSION_RECORD_AUDIO_NOT_GRANTED_TAG
32 import com.google.jetpackcamera.settings.ui.STABILIZATION_UNSUPPORTED_TAG
33 import com.google.jetpackcamera.settings.ui.VIDEO_QUALITY_UNSUPPORTED_TAG
34 
35 // seconds duration in millis
36 const val UNLIMITED_VIDEO_DURATION = 0L
37 const val FIVE_SECONDS_DURATION = 5_000L
38 const val TEN_SECONDS_DURATION = 10_000L
39 const val THIRTY_SECONDS_DURATION = 30_000L
40 const val SIXTY_SECONDS_DURATION = 60_000L
41 
42 /**
43  * Defines the current state of the [SettingsScreen].
44  */
45 sealed interface SettingsUiState {
46     data object Disabled : SettingsUiState
47     data class Enabled(
48         val aspectRatioUiState: AspectRatioUiState,
49         val streamConfigUiState: StreamConfigUiState,
50         val darkModeUiState: DarkModeUiState,
51         val flashUiState: FlashUiState,
52         val fpsUiState: FpsUiState,
53         val lensFlipUiState: FlipLensUiState,
54         val stabilizationUiState: StabilizationUiState,
55         val maxVideoDurationUiState: MaxVideoDurationUiState.Enabled,
56         val videoQualityUiState: VideoQualityUiState,
57         val audioUiState: AudioUiState
58     ) : SettingsUiState
59 }
60 
61 /** State for the individual options on Popup dialog settings */
62 sealed interface SingleSelectableState {
63     data object Selectable : SingleSelectableState
64     data class Disabled(val disabledRationale: DisabledRationale) : SingleSelectableState
65 }
66 
67 /** Contains information on why a setting is disabled */
68 // TODO(b/360921588): Display information on UI regarding disabled rationale
69 sealed interface DisabledRationale {
70     val affectedSettingNameResId: Int
71     val reasonTextResId: Int
72     val testTag: String
73 
74     data class PermissionRecordAudioNotGrantedRationale(
75         override val affectedSettingNameResId: Int
76     ) : DisabledRationale {
77         override val reasonTextResId: Int = R.string.permission_record_audio_unsupported
78         override val testTag = PERMISSION_RECORD_AUDIO_NOT_GRANTED_TAG
79     }
80 
81     /**
82      * Text will be [affectedSettingNameResId] is [R.string.device_unsupported]
83      */
84     data class DeviceUnsupportedRationale(override val affectedSettingNameResId: Int) :
85         DisabledRationale {
86         override val reasonTextResId: Int = R.string.device_unsupported
87         override val testTag = DEVICE_UNSUPPORTED_TAG
88     }
89 
90     data class FpsUnsupportedRationale(
91         override val affectedSettingNameResId: Int,
92         val currentFps: Int
93     ) : DisabledRationale {
94         override val reasonTextResId: Int = R.string.fps_unsupported
95         override val testTag = FPS_UNSUPPORTED_TAG
96     }
97 
98     data class StabilizationUnsupportedRationale(override val affectedSettingNameResId: Int) :
99         DisabledRationale {
100         override val reasonTextResId = R.string.stabilization_unsupported
101         override val testTag = STABILIZATION_UNSUPPORTED_TAG
102     }
103 
104     data class VideoQualityUnsupportedRationale(
105         override val affectedSettingNameResId: Int,
106         val currentDynamicRange: Int = R.string.video_quality_rationale_suffix_default
107     ) : DisabledRationale {
108         override val reasonTextResId = R.string.video_quality_unsupported
109         override val testTag = VIDEO_QUALITY_UNSUPPORTED_TAG
110     }
111 
112     sealed interface LensUnsupportedRationale : DisabledRationale {
113         data class FrontLensUnsupportedRationale(override val affectedSettingNameResId: Int) :
114             LensUnsupportedRationale {
115             override val reasonTextResId: Int = R.string.front_lens_unsupported
116             override val testTag = LENS_UNSUPPORTED_TAG
117         }
118 
119         data class RearLensUnsupportedRationale(override val affectedSettingNameResId: Int) :
120             LensUnsupportedRationale {
121             override val reasonTextResId: Int = R.string.rear_lens_unsupported
122             override val testTag = LENS_UNSUPPORTED_TAG
123         }
124     }
125 }
126 
getLensUnsupportedRationalenull127 fun getLensUnsupportedRationale(
128     lensFacing: LensFacing,
129     affectedSettingNameResId: Int
130 ): LensUnsupportedRationale = when (lensFacing) {
131     LensFacing.BACK -> LensUnsupportedRationale.RearLensUnsupportedRationale(
132         affectedSettingNameResId
133     )
134 
135     LensFacing.FRONT -> LensUnsupportedRationale.FrontLensUnsupportedRationale(
136         affectedSettingNameResId
137     )
138 }
139 
140 // ////////////////////////////////////////////////////////////
141 //
142 // Settings that currently depend on constraints
143 //
144 // ////////////////////////////////////////////////////////////
145 
146 sealed interface FpsUiState {
147     data class Enabled(
148         val currentSelection: Int,
149         val fpsAutoState: SingleSelectableState,
150         val fpsFifteenState: SingleSelectableState,
151         val fpsThirtyState: SingleSelectableState,
152         val fpsSixtyState: SingleSelectableState,
153         // Contains text like "Selected FPS only supported by rear lens"
154         val additionalContext: String = ""
155     ) : FpsUiState
156 
157     // FPS selection completely disabled. Cannot open dialog.
158     data class Disabled(val disabledRationale: DisabledRationale) : FpsUiState
159 }
160 
161 sealed interface FlipLensUiState {
162     val currentLensFacing: LensFacing
163 
164     data class Enabled(override val currentLensFacing: LensFacing) : FlipLensUiState
165 
166     data class Disabled(
167         override val currentLensFacing: LensFacing,
168         val disabledRationale: DisabledRationale
169     ) : FlipLensUiState
170 }
171 
172 sealed interface StabilizationUiState {
173     data class Enabled(
174         val currentStabilizationMode: StabilizationMode,
175         val stabilizationAutoState: SingleSelectableState,
176         val stabilizationOnState: SingleSelectableState,
177         val stabilizationHighQualityState: SingleSelectableState,
178         val stabilizationOpticalState: SingleSelectableState,
179         // Contains text like "Selected stabilization mode only supported by rear lens"
180         val additionalContext: String = ""
181     ) : StabilizationUiState
182 
183     // Stabilization selection completely disabled. Cannot open dialog.
184     data class Disabled(val disabledRationale: DisabledRationale) : StabilizationUiState
185 }
186 
187 sealed interface AudioUiState {
188 
189     sealed interface Enabled : AudioUiState {
190         val additionalContext: String
191 
192         data class On(override val additionalContext: String = "") : Enabled
193         data class Mute(override val additionalContext: String = "") : Enabled
194     }
195 
196     data class Disabled(val disabledRationale: DisabledRationale) : AudioUiState
197 }
198 
199 sealed interface FlashUiState {
200     data class Enabled(
201         val currentFlashMode: FlashMode,
202         val onSelectableState: SingleSelectableState,
203         val autoSelectableState: SingleSelectableState,
204         val lowLightSelectableState: SingleSelectableState,
205         val additionalContext: String = ""
206     ) : FlashUiState
207 
208     data class Disabled(val disabledRationale: DisabledRationale) : FlashUiState
209 }
210 
211 // ////////////////////////////////////////////////////////////
212 //
213 // Settings that DON'T currently depend on constraints
214 //
215 // ////////////////////////////////////////////////////////////
216 
217 sealed interface AspectRatioUiState {
218     data class Enabled(val currentAspectRatio: AspectRatio, val additionalContext: String = "") :
219         AspectRatioUiState
220 }
221 
222 sealed interface StreamConfigUiState {
223     data class Enabled(val currentStreamConfig: StreamConfig, val additionalContext: String = "") :
224         StreamConfigUiState
225 }
226 
227 sealed interface DarkModeUiState {
228     data class Enabled(val currentDarkMode: DarkMode, val additionalContext: String = "") :
229         DarkModeUiState
230 }
231 
232 sealed interface MaxVideoDurationUiState {
233     data class Enabled(val currentMaxDurationMillis: Long, val additionalContext: String = "") :
234         MaxVideoDurationUiState
235 }
236 
237 sealed interface VideoQualityUiState {
238     data class Enabled(
239         val currentVideoQuality: VideoQuality,
240         val videoQualityAutoState: SingleSelectableState,
241         val videoQualitySDState: SingleSelectableState,
242         val videoQualityHDState: SingleSelectableState,
243         val videoQualityFHDState: SingleSelectableState,
244         val videoQualityUHDState: SingleSelectableState
245     ) : VideoQualityUiState {
getSelectableStatenull246         fun getSelectableState(videoQuality: VideoQuality): SingleSelectableState =
247             when (videoQuality) {
248                 VideoQuality.UNSPECIFIED -> this.videoQualityAutoState
249                 VideoQuality.SD -> this.videoQualitySDState
250                 VideoQuality.HD -> this.videoQualityHDState
251                 VideoQuality.FHD -> this.videoQualityFHDState
252                 VideoQuality.UHD -> this.videoQualityUHDState
253             }
254     }
255 
256     data class Disabled(val disabledRationale: DisabledRationale) : VideoQualityUiState
257 }
258 
259 /**
260  * Settings Ui State for testing, based on Typical System Constraints.
261  * @see[com.google.jetpackcamera.settings.model.SystemConstraints]
262  */
263 val TYPICAL_SETTINGS_UISTATE = SettingsUiState.Enabled(
264     aspectRatioUiState = AspectRatioUiState.Enabled(DEFAULT_CAMERA_APP_SETTINGS.aspectRatio),
265     streamConfigUiState = StreamConfigUiState.Enabled(DEFAULT_CAMERA_APP_SETTINGS.streamConfig),
266     darkModeUiState = DarkModeUiState.Enabled(DEFAULT_CAMERA_APP_SETTINGS.darkMode),
267     audioUiState = if (DEFAULT_CAMERA_APP_SETTINGS.audioEnabled) {
268         AudioUiState.Enabled.On()
269     } else {
270         AudioUiState.Enabled.Mute()
271     },
272     flashUiState =
273     FlashUiState.Enabled(
274         currentFlashMode = DEFAULT_CAMERA_APP_SETTINGS.flashMode,
275         autoSelectableState = SingleSelectableState.Selectable,
276         onSelectableState = SingleSelectableState.Selectable,
277         lowLightSelectableState = SingleSelectableState.Disabled(
278             DeviceUnsupportedRationale(R.string.flash_llb_rationale_prefix)
279         )
280     ),
281     fpsUiState = FpsUiState.Enabled(
282         currentSelection = DEFAULT_CAMERA_APP_SETTINGS.targetFrameRate,
283         fpsAutoState = SingleSelectableState.Selectable,
284         fpsFifteenState = SingleSelectableState.Selectable,
285         fpsThirtyState = SingleSelectableState.Selectable,
286         fpsSixtyState = SingleSelectableState.Disabled(
287             DeviceUnsupportedRationale(R.string.fps_rationale_prefix)
288         )
289     ),
290     lensFlipUiState = FlipLensUiState.Enabled(DEFAULT_CAMERA_APP_SETTINGS.cameraLensFacing),
291     maxVideoDurationUiState = MaxVideoDurationUiState.Enabled(UNLIMITED_VIDEO_DURATION),
292     stabilizationUiState =
293     StabilizationUiState.Disabled(
294         DeviceUnsupportedRationale(R.string.stabilization_rationale_prefix)
295     ),
296     videoQualityUiState = VideoQualityUiState.Disabled(
297         DisabledRationale.VideoQualityUnsupportedRationale(R.string.video_quality_rationale_prefix)
298     )
299 )
300