1 /*
<lambda>null2  * Copyright (C) 2022 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 
18 package com.android.systemui.controls.settings
19 
20 import android.provider.Settings
21 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
22 import com.android.systemui.dagger.SysUISingleton
23 import com.android.systemui.dagger.qualifiers.Application
24 import com.android.systemui.dagger.qualifiers.Background
25 import com.android.systemui.qs.UserSettingObserver
26 import com.android.systemui.user.data.repository.UserRepository
27 import com.android.systemui.util.settings.SecureSettings
28 import javax.inject.Inject
29 import kotlinx.coroutines.CoroutineDispatcher
30 import kotlinx.coroutines.CoroutineScope
31 import kotlinx.coroutines.ExperimentalCoroutinesApi
32 import kotlinx.coroutines.channels.awaitClose
33 import kotlinx.coroutines.flow.SharingStarted
34 import kotlinx.coroutines.flow.StateFlow
35 import kotlinx.coroutines.flow.distinctUntilChanged
36 import kotlinx.coroutines.flow.flatMapLatest
37 import kotlinx.coroutines.flow.flowOn
38 import kotlinx.coroutines.flow.stateIn
39 
40 /**
41  * This implementation uses an `@Application` [CoroutineScope] to provide hot flows for the values
42  * of the tracked settings.
43  */
44 @SysUISingleton
45 class ControlsSettingsRepositoryImpl
46 @Inject
47 constructor(
48     @Application private val scope: CoroutineScope,
49     @Background private val backgroundDispatcher: CoroutineDispatcher,
50     private val userRepository: UserRepository,
51     private val secureSettings: SecureSettings
52 ) : ControlsSettingsRepository {
53 
54     override val canShowControlsInLockscreen =
55         makeFlowForSetting(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS)
56 
57     override val allowActionOnTrivialControlsInLockscreen =
58         makeFlowForSetting(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)
59 
60     @OptIn(ExperimentalCoroutinesApi::class)
61     private fun makeFlowForSetting(setting: String): StateFlow<Boolean> {
62         return userRepository.selectedUserInfo
63             .distinctUntilChanged()
64             .flatMapLatest { userInfo ->
65                 conflatedCallbackFlow {
66                         val observer =
67                             object :
68                                 UserSettingObserver(secureSettings, null, setting, userInfo.id) {
69                                 override fun handleValueChanged(
70                                     value: Int,
71                                     observedChange: Boolean
72                                 ) {
73                                     trySend(value == 1)
74                                 }
75                             }
76                         observer.isListening = true
77                         trySend(observer.value == 1)
78                         awaitClose { observer.isListening = false }
79                     }
80                     .flowOn(backgroundDispatcher)
81                     .distinctUntilChanged()
82             }
83             .stateIn(
84                 scope,
85                 started = SharingStarted.Eagerly,
86                 // When the observer starts listening, the flow will emit the current value
87                 // so the initialValue here is irrelevant.
88                 initialValue = false,
89             )
90     }
91 }
92