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.volume.dialog.domain.interactor
18
19 import android.util.SparseArray
20 import androidx.core.util.keyIterator
21 import com.android.systemui.plugins.VolumeDialogController
22 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPlugin
23 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
24 import com.android.systemui.volume.dialog.data.repository.VolumeDialogStateRepository
25 import com.android.systemui.volume.dialog.domain.model.VolumeDialogEventModel
26 import com.android.systemui.volume.dialog.shared.model.VolumeDialogCsdWarningModel
27 import com.android.systemui.volume.dialog.shared.model.VolumeDialogSafetyWarningModel
28 import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel
29 import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
30 import javax.inject.Inject
31 import kotlin.time.Duration.Companion.milliseconds
32 import kotlinx.coroutines.CoroutineScope
33 import kotlinx.coroutines.flow.Flow
34 import kotlinx.coroutines.flow.launchIn
35 import kotlinx.coroutines.flow.onEach
36
37 /**
38 * Exposes [VolumeDialogController.getState] in the [volumeDialogState].
39 *
40 * @see [VolumeDialogController]
41 */
42 @VolumeDialogPluginScope
43 class VolumeDialogStateInteractor
44 @Inject
45 constructor(
46 volumeDialogCallbacksInteractor: VolumeDialogCallbacksInteractor,
47 private val volumeDialogController: VolumeDialogController,
48 private val volumeDialogStateRepository: VolumeDialogStateRepository,
49 @VolumeDialogPlugin private val coroutineScope: CoroutineScope,
50 ) {
51
52 init {
53 volumeDialogCallbacksInteractor.event
54 .onEach { event ->
55 when (event) {
56 is VolumeDialogEventModel.StateChanged -> {
57 volumeDialogStateRepository.updateState { oldState ->
58 event.state.copyIntoModel(oldState)
59 }
60 }
61 is VolumeDialogEventModel.AccessibilityModeChanged -> {
62 volumeDialogStateRepository.updateState { oldState ->
63 oldState.copy(shouldShowA11ySlider = event.showA11yStream)
64 }
65 }
66 is VolumeDialogEventModel.ShowSafetyWarning -> {
67 setSafetyWarning(VolumeDialogSafetyWarningModel.Visible(event.flags))
68 }
69 is VolumeDialogEventModel.ShowCsdWarning -> {
70 setCsdWarning(
71 VolumeDialogCsdWarningModel.Visible(
72 warning = event.csdWarning,
73 duration = event.durationMs.milliseconds,
74 )
75 )
76 }
77 is VolumeDialogEventModel.SubscribedToEvents -> {
78 volumeDialogController.getState()
79 }
80 else -> {
81 // do nothing
82 }
83 }
84 }
85 .launchIn(coroutineScope)
86 }
87
88 val volumeDialogState: Flow<VolumeDialogStateModel> = volumeDialogStateRepository.state
89
90 fun setSafetyWarning(model: VolumeDialogSafetyWarningModel) {
91 volumeDialogStateRepository.updateState { it.copy(isShowingSafetyWarning = model) }
92 }
93
94 fun setCsdWarning(model: VolumeDialogCsdWarningModel) {
95 volumeDialogStateRepository.updateState { it.copy(isShowingCsdWarning = model) }
96 }
97
98 fun setHovering(isHovering: Boolean) {
99 volumeDialogStateRepository.updateState { it.copy(isHovering = isHovering) }
100 }
101
102 /** Returns a copy of [model] filled with the values from [VolumeDialogController.State]. */
103 private fun VolumeDialogController.State.copyIntoModel(
104 model: VolumeDialogStateModel
105 ): VolumeDialogStateModel {
106 return model.copy(
107 streamModels =
108 states.mapToMap { stream, streamState ->
109 VolumeDialogStreamModel(
110 stream = stream,
111 isActive = stream == activeStream,
112 legacyState = streamState,
113 )
114 },
115 ringerModeInternal = ringerModeInternal,
116 ringerModeExternal = ringerModeExternal,
117 zenMode = zenMode,
118 effectsSuppressor = effectsSuppressor,
119 effectsSuppressorName = effectsSuppressorName,
120 activeStream = activeStream,
121 disallowAlarms = disallowAlarms,
122 disallowMedia = disallowMedia,
123 disallowSystem = disallowSystem,
124 disallowRinger = disallowRinger,
125 )
126 }
127 }
128
mapToMapnull129 private fun <INPUT, OUTPUT> SparseArray<INPUT>.mapToMap(
130 map: (Int, INPUT) -> OUTPUT
131 ): Map<Int, OUTPUT> {
132 val resultMap = mutableMapOf<Int, OUTPUT>()
133 for (key in keyIterator()) {
134 val mappedValue: OUTPUT = map(key, get(key)!!)
135 resultMap[key] = mappedValue
136 }
137 return resultMap
138 }
139