1 /*
2  * Copyright (C) 2023 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.retail.data.repository
18 
19 import android.database.ContentObserver
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.util.settings.GlobalSettings
26 import javax.inject.Inject
27 import kotlinx.coroutines.CoroutineDispatcher
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.flowOn
33 import kotlinx.coroutines.flow.map
34 import kotlinx.coroutines.flow.onStart
35 import kotlinx.coroutines.flow.stateIn
36 
37 /** Repository to track if the device is in Retail mode */
38 interface RetailModeRepository {
39     /** Flow of whether the device is currently in retail mode. */
40     val retailMode: StateFlow<Boolean>
41 
42     /** Last value of whether the device is in retail mode. */
43     val inRetailMode: Boolean
44         get() = retailMode.value
45 }
46 
47 /**
48  * Tracks [Settings.Global.DEVICE_DEMO_MODE].
49  *
50  * @see UserManager.isDeviceInDemoMode
51  */
52 @SysUISingleton
53 class RetailModeSettingsRepository
54 @Inject
55 constructor(
56     globalSettings: GlobalSettings,
57     @Background backgroundDispatcher: CoroutineDispatcher,
58     @Application scope: CoroutineScope,
59 ) : RetailModeRepository {
60     override val retailMode =
<lambda>null61         conflatedCallbackFlow {
62                 val observer =
63                     object : ContentObserver(null) {
64                         override fun onChange(selfChange: Boolean) {
65                             trySend(Unit)
66                         }
67                     }
68 
69                 globalSettings.registerContentObserverSync(RETAIL_MODE_SETTING, observer)
70 
71                 awaitClose { globalSettings.unregisterContentObserverSync(observer) }
72             }
<lambda>null73             .onStart { emit(Unit) }
<lambda>null74             .map { globalSettings.getInt(RETAIL_MODE_SETTING, 0) != 0 }
75             .flowOn(backgroundDispatcher)
76             .stateIn(scope, SharingStarted.Eagerly, false)
77 
78     companion object {
79         private const val RETAIL_MODE_SETTING = Settings.Global.DEVICE_DEMO_MODE
80     }
81 }
82