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