1 /*
<lambda>null2  * 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.plugins
18 
19 import android.media.AudioManager
20 import android.media.AudioManager.CsdWarning
21 import android.os.Handler
22 import android.os.VibrationEffect
23 import androidx.core.util.getOrElse
24 import java.util.concurrent.CopyOnWriteArraySet
25 
26 class FakeVolumeDialogController(private val audioManager: AudioManager) : VolumeDialogController {
27 
28     var isVisible: Boolean = false
29         private set
30 
31     var hasScheduledTouchFeedback: Boolean = false
32         private set
33 
34     var vibrationEffect: VibrationEffect? = null
35         private set
36 
37     var hasUserActivity: Boolean = false
38         private set
39 
40     private val callbacks = CopyOnWriteArraySet<VolumeDialogController.Callbacks>()
41 
42     private var hasVibrator: Boolean = true
43     private var state = VolumeDialogController.State()
44 
45     override fun setActiveStream(stream: Int) {
46         updateState {
47             // ensure streamState existence for the active stream`
48             states.getOrElse(stream) {
49                 VolumeDialogController.StreamState().also { streamState ->
50                     state.states.put(stream, streamState)
51                 }
52             }
53             activeStream = stream
54         }
55     }
56 
57     override fun setStreamVolume(stream: Int, userLevel: Int) {
58         updateState {
59             val streamState =
60                 states.getOrElse(stream) {
61                     VolumeDialogController.StreamState().also { streamState ->
62                         states.put(stream, streamState)
63                     }
64                 }
65             streamState.level = userLevel.coerceIn(streamState.levelMin, streamState.levelMax)
66         }
67     }
68 
69     override fun setRingerMode(ringerModeNormal: Int, external: Boolean) {
70         updateState {
71             if (external) {
72                 ringerModeExternal = ringerModeNormal
73             } else {
74                 ringerModeInternal = ringerModeNormal
75             }
76         }
77     }
78 
79     fun setHasVibrator(hasVibrator: Boolean) {
80         this.hasVibrator = hasVibrator
81     }
82 
83     override fun hasVibrator(): Boolean = hasVibrator
84 
85     override fun vibrate(effect: VibrationEffect) {
86         vibrationEffect = effect
87     }
88 
89     override fun scheduleTouchFeedback() {
90         hasScheduledTouchFeedback = true
91     }
92 
93     fun resetScheduledTouchFeedback() {
94         hasScheduledTouchFeedback = false
95     }
96 
97     override fun getAudioManager(): AudioManager = audioManager
98 
99     override fun notifyVisible(visible: Boolean) {
100         isVisible = visible
101     }
102 
103     override fun addCallback(callbacks: VolumeDialogController.Callbacks?, handler: Handler?) {
104         this.callbacks.add(callbacks)
105     }
106 
107     override fun removeCallback(callbacks: VolumeDialogController.Callbacks?) {
108         this.callbacks.remove(callbacks)
109     }
110 
111     override fun userActivity() {
112         hasUserActivity = true
113     }
114 
115     fun resetUserActivity() {
116         hasUserActivity = false
117     }
118 
119     fun updateState(update: VolumeDialogController.State.() -> Unit) {
120         state = state.copy().apply(update)
121         getState()
122     }
123 
124     override fun getState() {
125         callbacks.sendEvent { it.onStateChanged(state) }
126     }
127 
128     /** @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onShowRequested */
129     fun onShowRequested(reason: Int, keyguardLocked: Boolean, lockTaskModeState: Int) {
130         callbacks.sendEvent { it.onShowRequested(reason, keyguardLocked, lockTaskModeState) }
131     }
132 
133     /** @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onDismissRequested */
134     fun onDismissRequested(reason: Int) {
135         callbacks.sendEvent { it.onDismissRequested(reason) }
136     }
137 
138     /**
139      * @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onLayoutDirectionChanged
140      */
141     fun onLayoutDirectionChanged(layoutDirection: Int) {
142         callbacks.sendEvent { it.onLayoutDirectionChanged(layoutDirection) }
143     }
144 
145     /** @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onConfigurationChanged */
146     fun onConfigurationChanged() {
147         callbacks.sendEvent { it.onConfigurationChanged() }
148     }
149 
150     /** @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onShowVibrateHint */
151     fun onShowVibrateHint() {
152         callbacks.sendEvent { it.onShowVibrateHint() }
153     }
154 
155     /** @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onShowSilentHint */
156     fun onShowSilentHint() {
157         callbacks.sendEvent { it.onShowSilentHint() }
158     }
159 
160     /** @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onScreenOff */
161     fun onScreenOff() {
162         callbacks.sendEvent { it.onScreenOff() }
163     }
164 
165     /** @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onShowSafetyWarning */
166     fun onShowSafetyWarning(flags: Int) {
167         callbacks.sendEvent { it.onShowSafetyWarning(flags) }
168     }
169 
170     /**
171      * @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onAccessibilityModeChanged
172      */
173     fun onAccessibilityModeChanged(showA11yStream: Boolean?) {
174         callbacks.sendEvent { it.onAccessibilityModeChanged(showA11yStream) }
175     }
176 
177     /** @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onShowCsdWarning */
178     fun onShowCsdWarning(@CsdWarning csdWarning: Int, durationMs: Int) {
179         callbacks.sendEvent { it.onShowCsdWarning(csdWarning, durationMs) }
180     }
181 
182     /** @see com.android.systemui.plugins.VolumeDialogController.Callbacks.onVolumeChangedFromKey */
183     fun onVolumeChangedFromKey() {
184         callbacks.sendEvent { it.onVolumeChangedFromKey() }
185     }
186 
187     override fun getCaptionsEnabledState(checkForSwitchState: Boolean) {
188         error("Unsupported for the new Volume Dialog")
189     }
190 
191     override fun setCaptionsEnabledState(enabled: Boolean) {
192         error("Unsupported for the new Volume Dialog")
193     }
194 
195     override fun getCaptionsComponentState(fromTooltip: Boolean) {
196         error("Unsupported for the new Volume Dialog")
197     }
198 }
199 
sendEventnull200 private inline fun CopyOnWriteArraySet<VolumeDialogController.Callbacks>.sendEvent(
201     event: (callback: VolumeDialogController.Callbacks) -> Unit
202 ) {
203     for (callback in this) {
204         event(callback)
205     }
206 }
207