• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 
17 package com.android.systemui.brightness.ui.viewmodel
18 
19 import android.content.Context
20 import androidx.annotation.DrawableRes
21 import androidx.annotation.FloatRange
22 import androidx.annotation.StringRes
23 import androidx.compose.runtime.getValue
24 import com.android.systemui.brightness.domain.interactor.BrightnessPolicyEnforcementInteractor
25 import com.android.systemui.brightness.domain.interactor.ScreenBrightnessInteractor
26 import com.android.systemui.brightness.shared.model.GammaBrightness
27 import com.android.systemui.classifier.Classifier
28 import com.android.systemui.classifier.domain.interactor.FalsingInteractor
29 import com.android.systemui.common.shared.model.Icon
30 import com.android.systemui.common.shared.model.asIcon
31 import com.android.systemui.graphics.ImageLoader
32 import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
33 import com.android.systemui.lifecycle.ExclusiveActivatable
34 import com.android.systemui.lifecycle.Hydrator
35 import com.android.systemui.res.R
36 import com.android.systemui.settings.brightness.domain.interactor.BrightnessMirrorShowingInteractor
37 import com.android.systemui.settings.brightness.ui.BrightnessWarningToast
38 import com.android.systemui.utils.PolicyRestriction
39 import dagger.assisted.Assisted
40 import dagger.assisted.AssistedFactory
41 import dagger.assisted.AssistedInject
42 
43 /**
44  * View Model for a brightness slider.
45  *
46  * If this brightness slider supports mirroring (show on top of current activity while dragging),
47  * then:
48  * * [showMirror] will be true while dragging
49  * * [BrightnessMirrorShowingInteractor.isShowing] will track if the mirror should show (for (other
50  *   parts of SystemUI to act accordingly).
51  */
52 class BrightnessSliderViewModel
53 @AssistedInject
54 constructor(
55     private val screenBrightnessInteractor: ScreenBrightnessInteractor,
56     private val brightnessPolicyEnforcementInteractor: BrightnessPolicyEnforcementInteractor,
57     val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
58     private val brightnessMirrorShowingInteractor: BrightnessMirrorShowingInteractor,
59     private val falsingInteractor: FalsingInteractor,
60     @Assisted private val supportsMirroring: Boolean,
61     private val brightnessWarningToast: BrightnessWarningToast,
62     private val imageLoader: ImageLoader,
63 ) : ExclusiveActivatable() {
64 
65     private val hydrator = Hydrator("BrightnessSliderViewModel.hydrator")
66 
67     val currentBrightness by
68         hydrator.hydratedStateOf(
69             "currentBrightness",
70             initialValue,
71             screenBrightnessInteractor.gammaBrightness,
72         )
73 
74     val maxBrightness = screenBrightnessInteractor.maxGammaBrightness
75     val minBrightness = screenBrightnessInteractor.minGammaBrightness
76 
77     val policyRestriction = brightnessPolicyEnforcementInteractor.brightnessPolicyRestriction
78 
showPolicyRestrictionDialognull79     fun showPolicyRestrictionDialog(restriction: PolicyRestriction.Restricted) {
80         brightnessPolicyEnforcementInteractor.startAdminSupportDetailsDialog(restriction)
81     }
82 
83     val brightnessOverriddenByWindow = screenBrightnessInteractor.brightnessOverriddenByWindow
84 
showToastnull85     fun showToast(viewContext: Context, @StringRes resId: Int) {
86         if (brightnessWarningToast.isToastActive()) {
87             return
88         }
89         brightnessWarningToast.show(viewContext, resId)
90     }
91 
emitBrightnessTouchForFalsingnull92     fun emitBrightnessTouchForFalsing() {
93         falsingInteractor.isFalseTouch(Classifier.BRIGHTNESS_SLIDER)
94     }
95 
loadImagenull96     suspend fun loadImage(@DrawableRes resId: Int, context: Context): Icon.Loaded {
97         return imageLoader
98             .loadDrawable(
99                 android.graphics.drawable.Icon.createWithResource(context, resId),
100                 maxHeight = 200,
101                 maxWidth = 200,
102             )!!
103             .asIcon(null, resId)
104     }
105 
106     /**
107      * As a brightness slider is dragged, the corresponding events should be sent using this method.
108      */
onDragnull109     suspend fun onDrag(drag: Drag) {
110         when (drag) {
111             is Drag.Dragging -> screenBrightnessInteractor.setTemporaryBrightness(drag.brightness)
112             is Drag.Stopped -> screenBrightnessInteractor.setBrightness(drag.brightness)
113         }
114     }
115 
setIsDraggingnull116     fun setIsDragging(dragging: Boolean) {
117         brightnessMirrorShowingInteractor.setMirrorShowing(dragging && supportsMirroring)
118     }
119 
120     val showMirror by
121         hydrator.hydratedStateOf("showMirror", brightnessMirrorShowingInteractor.isShowing)
122 
onActivatednull123     override suspend fun onActivated(): Nothing {
124         hydrator.activate()
125     }
126 
127     @AssistedFactory
128     interface Factory {
createnull129         fun create(supportsMirroring: Boolean): BrightnessSliderViewModel
130     }
131 
132     companion object {
133         val initialValue = GammaBrightness(-1)
134 
135         private val icons =
136             BrightnessIcons(
137                 brightnessLow = R.drawable.ic_brightness_low,
138                 brightnessMid = R.drawable.ic_brightness_medium,
139                 brightnessHigh = R.drawable.ic_brightness_full,
140             )
141 
142         @DrawableRes
143         fun getIconForPercentage(@FloatRange(0.0, 100.0) percentage: Float): Int {
144             return when {
145                 percentage <= 20f -> icons.brightnessLow
146                 percentage >= 80f -> icons.brightnessHigh
147                 else -> icons.brightnessMid
148             }
149         }
150     }
151 }
152 
BrightnessSliderViewModelnull153 fun BrightnessSliderViewModel.Factory.create() = create(supportsMirroring = true)
154 
155 /** Represents a drag event in a brightness slider. */
156 sealed interface Drag {
157     val brightness: GammaBrightness
158 
159     @JvmInline value class Dragging(override val brightness: GammaBrightness) : Drag
160 
161     @JvmInline value class Stopped(override val brightness: GammaBrightness) : Drag
162 }
163 
164 private data class BrightnessIcons(
165     @DrawableRes val brightnessLow: Int,
166     @DrawableRes val brightnessMid: Int,
167     @DrawableRes val brightnessHigh: Int,
168 )
169