1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.systemui.statusbar.disableflags.data.repository
16 
17 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
18 import com.android.systemui.dagger.SysUISingleton
19 import com.android.systemui.dagger.qualifiers.Application
20 import com.android.systemui.dagger.qualifiers.DisplayId
21 import com.android.systemui.log.LogBuffer
22 import com.android.systemui.log.dagger.DisableFlagsRepositoryLog
23 import com.android.systemui.statusbar.CommandQueue
24 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
25 import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
26 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler
27 import javax.inject.Inject
28 import kotlinx.coroutines.CoroutineScope
29 import kotlinx.coroutines.channels.awaitClose
30 import kotlinx.coroutines.flow.SharingStarted
31 import kotlinx.coroutines.flow.StateFlow
32 import kotlinx.coroutines.flow.distinctUntilChanged
33 import kotlinx.coroutines.flow.onEach
34 import kotlinx.coroutines.flow.stateIn
35 
36 /** Repository for the disable flags received from external systems. See [IStatusBar.disable]. */
37 interface DisableFlagsRepository {
38     /** A model of the disable flags last received from [IStatusBar]. */
39     val disableFlags: StateFlow<DisableFlagsModel>
40 }
41 
42 @SysUISingleton
43 class DisableFlagsRepositoryImpl
44 @Inject
45 constructor(
46     commandQueue: CommandQueue,
47     @DisplayId private val thisDisplayId: Int,
48     @Application scope: CoroutineScope,
49     remoteInputQuickSettingsDisabler: RemoteInputQuickSettingsDisabler,
50     @DisableFlagsRepositoryLog private val logBuffer: LogBuffer,
51     private val disableFlagsLogger: DisableFlagsLogger,
52 ) : DisableFlagsRepository {
53     override val disableFlags: StateFlow<DisableFlagsModel> =
<lambda>null54         conflatedCallbackFlow {
55                 val callback =
56                     object : CommandQueue.Callbacks {
57                         override fun disable(
58                             displayId: Int,
59                             state1: Int,
60                             state2: Int,
61                             animate: Boolean,
62                         ) {
63                             if (displayId != thisDisplayId) {
64                                 return
65                             }
66                             trySend(
67                                 DisableFlagsModel(
68                                     state1,
69                                     // Ideally, [RemoteInputQuickSettingsDisabler] should instead
70                                     // expose a flow that gets `combine`d with this [disableFlags]
71                                     // flow in a [DisableFlagsInteractor] or
72                                     // [QuickSettingsInteractor]-type class. However, that's out of
73                                     // scope for the CentralSurfaces removal project.
74                                     remoteInputQuickSettingsDisabler.adjustDisableFlags(state2),
75                                 )
76                             )
77                         }
78                     }
79                 commandQueue.addCallback(callback)
80                 awaitClose { commandQueue.removeCallback(callback) }
81             }
82             .distinctUntilChanged()
<lambda>null83             .onEach { it.logChange(logBuffer, disableFlagsLogger) }
84             // Use Eagerly because we always need to know about disable flags
85             .stateIn(scope, SharingStarted.Eagerly, DisableFlagsModel())
86 }
87