• 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.volume.dialog.domain.interactor
18 
19 import android.annotation.SuppressLint
20 import android.media.AudioManager.RINGER_MODE_NORMAL
21 import android.media.AudioManager.RINGER_MODE_SILENT
22 import android.os.Handler
23 import com.android.systemui.dagger.qualifiers.Background
24 import com.android.systemui.plugins.VolumeDialogController
25 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPlugin
26 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
27 import com.android.systemui.volume.dialog.domain.model.VolumeDialogEventModel
28 import javax.inject.Inject
29 import kotlinx.coroutines.CoroutineScope
30 import kotlinx.coroutines.channels.BufferOverflow
31 import kotlinx.coroutines.channels.ProducerScope
32 import kotlinx.coroutines.channels.awaitClose
33 import kotlinx.coroutines.flow.Flow
34 import kotlinx.coroutines.flow.SharingStarted
35 import kotlinx.coroutines.flow.buffer
36 import kotlinx.coroutines.flow.callbackFlow
37 import kotlinx.coroutines.flow.onStart
38 import kotlinx.coroutines.flow.shareIn
39 
40 private const val BUFFER_CAPACITY = 16
41 
42 /**
43  * Exposes [VolumeDialogController] callback events in the [event].
44  *
45  * @see VolumeDialogController.Callbacks
46  */
47 @VolumeDialogPluginScope
48 class VolumeDialogCallbacksInteractor
49 @Inject
50 constructor(
51     private val volumeDialogController: VolumeDialogController,
52     @VolumeDialogPlugin private val coroutineScope: CoroutineScope,
53     @Background private val bgHandler: Handler?,
54 ) {
55 
56     @SuppressLint("SharedFlowCreation") // event-bus needed
57     val event: Flow<VolumeDialogEventModel> =
<lambda>null58         callbackFlow {
59                 val producer = VolumeDialogEventModelProducer(this)
60                 volumeDialogController.addCallback(producer, bgHandler)
61                 send(VolumeDialogEventModel.SubscribedToEvents)
62                 awaitClose { volumeDialogController.removeCallback(producer) }
63             }
64             .buffer(capacity = BUFFER_CAPACITY, onBufferOverflow = BufferOverflow.DROP_OLDEST)
65             .shareIn(replay = 0, scope = coroutineScope, started = SharingStarted.Eagerly)
<lambda>null66             .onStart { emit(VolumeDialogEventModel.SubscribedToEvents) }
67 
68     private inner class VolumeDialogEventModelProducer(
69         private val scope: ProducerScope<VolumeDialogEventModel>
70     ) : VolumeDialogController.Callbacks {
onShowRequestednull71         override fun onShowRequested(reason: Int, keyguardLocked: Boolean, lockTaskModeState: Int) {
72             scope.trySend(
73                 VolumeDialogEventModel.ShowRequested(
74                     reason = reason,
75                     keyguardLocked = keyguardLocked,
76                     lockTaskModeState = lockTaskModeState,
77                 )
78             )
79         }
80 
onDismissRequestednull81         override fun onDismissRequested(reason: Int) {
82             scope.trySend(VolumeDialogEventModel.DismissRequested(reason))
83         }
84 
onStateChangednull85         override fun onStateChanged(state: VolumeDialogController.State?) {
86             if (state != null) {
87                 scope.trySend(VolumeDialogEventModel.StateChanged(state))
88             }
89         }
90 
onLayoutDirectionChangednull91         override fun onLayoutDirectionChanged(layoutDirection: Int) {
92             scope.trySend(VolumeDialogEventModel.LayoutDirectionChanged(layoutDirection))
93         }
94 
95         // Configuration change is never emitted by the VolumeDialogControllerImpl now.
onConfigurationChangednull96         override fun onConfigurationChanged() = Unit
97 
98         override fun onScreenOff() {
99             scope.trySend(VolumeDialogEventModel.ScreenOff)
100         }
101 
onShowSafetyWarningnull102         override fun onShowSafetyWarning(flags: Int) {
103             scope.trySend(VolumeDialogEventModel.ShowSafetyWarning(flags))
104         }
105 
onAccessibilityModeChangednull106         override fun onAccessibilityModeChanged(showA11yStream: Boolean?) {
107             scope.trySend(VolumeDialogEventModel.AccessibilityModeChanged(showA11yStream == true))
108         }
109 
onShowCsdWarningnull110         override fun onShowCsdWarning(csdWarning: Int, durationMs: Int) {
111             scope.trySend(
112                 VolumeDialogEventModel.ShowCsdWarning(
113                     csdWarning = csdWarning,
114                     durationMs = durationMs,
115                 )
116             )
117         }
118 
onVolumeChangedFromKeynull119         override fun onVolumeChangedFromKey() {
120             scope.trySend(VolumeDialogEventModel.VolumeChangedFromKey)
121         }
122 
123         // This should've been handled in side the controller itself.
onShowVibrateHintnull124         override fun onShowVibrateHint() {
125             volumeDialogController.setRingerMode(RINGER_MODE_SILENT, false)
126         }
127 
128         // This should've been handled in side the controller itself.
onShowSilentHintnull129         override fun onShowSilentHint() {
130             volumeDialogController.setRingerMode(RINGER_MODE_NORMAL, false)
131         }
132 
133         // Captions button is remove from the Volume Dialog
onCaptionComponentStateChangednull134         override fun onCaptionComponentStateChanged(
135             isComponentEnabled: Boolean,
136             fromTooltip: Boolean,
137         ) = Unit
138 
139         // Captions button is remove from the Volume Dialog
140         override fun onCaptionEnabledStateChanged(isEnabled: Boolean, checkBeforeSwitch: Boolean) =
141             Unit
142     }
143 }
144