1 /*
2  * Copyright (C) 2021 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.statusbar.policy
18 
19 import android.content.Context
20 import android.content.pm.UserInfo
21 import android.database.ContentObserver
22 import android.net.Uri
23 import android.os.Handler
24 import android.os.HandlerExecutor
25 import android.os.UserHandle
26 import android.provider.Settings
27 import android.util.ArraySet
28 import android.util.SparseBooleanArray
29 import androidx.annotation.GuardedBy
30 import androidx.annotation.WorkerThread
31 import com.android.systemui.Dumpable
32 import com.android.systemui.dagger.SysUISingleton
33 import com.android.systemui.dagger.qualifiers.Background
34 import com.android.systemui.dagger.qualifiers.Main
35 import com.android.systemui.dump.DumpManager
36 import com.android.systemui.settings.UserTracker
37 import com.android.systemui.util.settings.GlobalSettings
38 import com.android.systemui.util.settings.SecureSettings
39 import java.io.PrintWriter
40 import java.util.concurrent.Executor
41 import java.util.concurrent.atomic.AtomicBoolean
42 import javax.inject.Inject
43 
44 @SysUISingleton
45 open class DeviceProvisionedControllerImpl
46 @Inject
47 constructor(
48     private val secureSettings: SecureSettings,
49     private val globalSettings: GlobalSettings,
50     private val userTracker: UserTracker,
51     private val dumpManager: DumpManager,
52     @Background private val backgroundHandler: Handler,
53     @Main private val mainExecutor: Executor
54 ) : DeviceProvisionedController, DeviceProvisionedController.DeviceProvisionedListener, Dumpable {
55 
56     companion object {
57         private const val ALL_USERS = -1
58         private const val NO_USERS = -2
59         protected const val TAG = "DeviceProvisionedControllerImpl"
60     }
61 
62     private val deviceProvisionedUri = globalSettings.getUriFor(Settings.Global.DEVICE_PROVISIONED)
63     private val userSetupUri = secureSettings.getUriFor(Settings.Secure.USER_SETUP_COMPLETE)
64 
65     private val deviceProvisioned = AtomicBoolean(false)
66     @GuardedBy("lock") private val userSetupComplete = SparseBooleanArray()
67     @GuardedBy("lock")
68     private val listeners = ArraySet<DeviceProvisionedController.DeviceProvisionedListener>()
69 
70     private val lock = Any()
71 
72     private val backgroundExecutor = HandlerExecutor(backgroundHandler)
73 
74     private val initted = AtomicBoolean(false)
75 
76     private val _currentUser: Int
77         get() = userTracker.userId
78 
getCurrentUsernull79     override fun getCurrentUser(): Int {
80         return _currentUser
81     }
82 
83     private val observer =
84         object : ContentObserver(backgroundHandler) {
onChangenull85             override fun onChange(
86                 selfChange: Boolean,
87                 uris: MutableCollection<Uri>,
88                 flags: Int,
89                 userId: Int
90             ) {
91                 val updateDeviceProvisioned = deviceProvisionedUri in uris
92                 val updateUser = if (userSetupUri in uris) userId else NO_USERS
93                 updateValues(updateDeviceProvisioned, updateUser)
94                 if (updateDeviceProvisioned) {
95                     onDeviceProvisionedChanged()
96                 }
97                 if (updateUser != NO_USERS) {
98                     onUserSetupChanged()
99                 }
100             }
101         }
102 
103     private val userChangedCallback =
104         object : UserTracker.Callback {
105             @WorkerThread
onUserChangednull106             override fun onUserChanged(newUser: Int, userContext: Context) {
107                 updateValues(updateDeviceProvisioned = false, updateUser = newUser)
108                 onUserSwitched()
109             }
110 
onProfilesChangednull111             override fun onProfilesChanged(profiles: List<UserInfo>) {}
112         }
113 
114     init {
115         userSetupComplete.put(currentUser, false)
116     }
117 
118     /** Call to initialize values and register observers */
initnull119     open fun init() {
120         if (!initted.compareAndSet(false, true)) {
121             return
122         }
123         dumpManager.registerDumpable(this)
124         updateValues()
125         userTracker.addCallback(userChangedCallback, backgroundExecutor)
126         globalSettings.registerContentObserverSync(deviceProvisionedUri, observer)
127         secureSettings.registerContentObserverForUserSync(
128             userSetupUri,
129             observer,
130             UserHandle.USER_ALL
131         )
132     }
133 
134     @WorkerThread
updateValuesnull135     private fun updateValues(updateDeviceProvisioned: Boolean = true, updateUser: Int = ALL_USERS) {
136         if (updateDeviceProvisioned) {
137             deviceProvisioned.set(globalSettings.getInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0)
138         }
139         synchronized(lock) {
140             if (updateUser == ALL_USERS) {
141                 val n = userSetupComplete.size()
142                 for (i in 0 until n) {
143                     val user = userSetupComplete.keyAt(i)
144                     val value =
145                         secureSettings.getIntForUser(
146                             Settings.Secure.USER_SETUP_COMPLETE,
147                             0,
148                             user
149                         ) != 0
150                     userSetupComplete.put(user, value)
151                 }
152             } else if (updateUser != NO_USERS) {
153                 val value =
154                     secureSettings.getIntForUser(
155                         Settings.Secure.USER_SETUP_COMPLETE,
156                         0,
157                         updateUser
158                     ) != 0
159                 userSetupComplete.put(updateUser, value)
160             }
161         }
162     }
163 
164     /**
165      * Adds a listener.
166      *
167      * The listener will not be called when this happens.
168      */
addCallbacknull169     override fun addCallback(listener: DeviceProvisionedController.DeviceProvisionedListener) {
170         synchronized(lock) { listeners.add(listener) }
171     }
172 
removeCallbacknull173     override fun removeCallback(listener: DeviceProvisionedController.DeviceProvisionedListener) {
174         synchronized(lock) { listeners.remove(listener) }
175     }
176 
isDeviceProvisionednull177     override fun isDeviceProvisioned(): Boolean {
178         return deviceProvisioned.get()
179     }
180 
isUserSetupnull181     override fun isUserSetup(user: Int): Boolean {
182         val index = synchronized(lock) { userSetupComplete.indexOfKey(user) }
183         return if (index < 0) {
184             val value =
185                 secureSettings.getIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, user) != 0
186             synchronized(lock) { userSetupComplete.put(user, value) }
187             value
188         } else {
189             synchronized(lock) { userSetupComplete.get(user, false) }
190         }
191     }
192 
isCurrentUserSetupnull193     override fun isCurrentUserSetup(): Boolean {
194         return isUserSetup(currentUser)
195     }
196 
onDeviceProvisionedChangednull197     override fun onDeviceProvisionedChanged() {
198         dispatchChange(
199             DeviceProvisionedController.DeviceProvisionedListener::onDeviceProvisionedChanged
200         )
201     }
202 
onUserSetupChangednull203     override fun onUserSetupChanged() {
204         dispatchChange(DeviceProvisionedController.DeviceProvisionedListener::onUserSetupChanged)
205     }
206 
onUserSwitchednull207     override fun onUserSwitched() {
208         dispatchChange(DeviceProvisionedController.DeviceProvisionedListener::onUserSwitched)
209     }
210 
dispatchChangenull211     protected fun dispatchChange(
212         callback: DeviceProvisionedController.DeviceProvisionedListener.() -> Unit
213     ) {
214         val listenersCopy = synchronized(lock) { ArrayList(listeners) }
215         mainExecutor.execute { listenersCopy.forEach(callback) }
216     }
217 
dumpnull218     override fun dump(pw: PrintWriter, args: Array<out String>) {
219         pw.println("Device provisioned: ${deviceProvisioned.get()}")
220         synchronized(lock) {
221             pw.println("User setup complete: $userSetupComplete")
222             pw.println("Listeners: $listeners")
223         }
224     }
225 }
226