Fixes multi-user support

The controller is probably not recreated on user changed, so it listens
to intent broadcasts to update its current profiles list.

Test: atest
Fixes: 120028217

Change-Id: I8139827065fc61bc215870631f0215dd1bebe697
This commit is contained in:
Fabian Kozynski
2018-11-21 08:56:55 -05:00
parent 9ebc59e956
commit b5625ac6f6
2 changed files with 98 additions and 10 deletions

View File

@@ -18,10 +18,14 @@ package com.android.systemui.privacy
import android.app.ActivityManager
import android.app.AppOpsManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Handler
import android.os.UserHandle
import android.os.UserManager
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.Dependency
import com.android.systemui.appops.AppOpItem
import com.android.systemui.appops.AppOpsController
@@ -33,25 +37,29 @@ class PrivacyItemController(val context: Context, val callback: Callback) {
AppOpsManager.OP_RECORD_AUDIO,
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION)
val intents = listOf(Intent.ACTION_USER_FOREGROUND,
Intent.ACTION_MANAGED_PROFILE_ADDED,
Intent.ACTION_MANAGED_PROFILE_REMOVED)
const val TAG = "PrivacyItemController"
}
private var privacyList = emptyList<PrivacyItem>()
private val appOpsController = Dependency.get(AppOpsController::class.java)
private val userManager = context.getSystemService(UserManager::class.java)
private val currentUser = ActivityManager.getCurrentUser()
private val currentUserIds = userManager.getProfiles(currentUser).map { it.id }
private var currentUserIds = emptyList<Int>()
private val bgHandler = Handler(Dependency.get(Dependency.BG_LOOPER))
private val uiHandler = Dependency.get(Dependency.MAIN_HANDLER)
private var listening = false
private val notifyChanges = Runnable {
callback.privacyChanged(privacyList)
}
private val updateListAndNotifyChanges = Runnable {
updatePrivacyList()
uiHandler.post(notifyChanges)
}
private var listening = false
private val cb = object : AppOpsController.Callback {
override fun onActiveStateChanged(
code: Int,
@@ -61,12 +69,36 @@ class PrivacyItemController(val context: Context, val callback: Callback) {
) {
val userId = UserHandle.getUserId(uid)
if (userId in currentUserIds) {
update()
update(false)
}
}
}
private fun update() {
@VisibleForTesting
internal var userSwitcherReceiver = Receiver()
set(value) {
context.unregisterReceiver(field)
field = value
registerReceiver()
}
init {
registerReceiver()
}
private fun registerReceiver() {
context.registerReceiverAsUser(userSwitcherReceiver, UserHandle.ALL, IntentFilter().apply {
intents.forEach {
addAction(it)
}
}, null, null)
}
private fun update(updateUsers: Boolean) {
if (updateUsers) {
val currentUser = ActivityManager.getCurrentUser()
currentUserIds = userManager.getProfiles(currentUser).map { it.id }
}
bgHandler.post(updateListAndNotifyChanges)
}
@@ -75,7 +107,7 @@ class PrivacyItemController(val context: Context, val callback: Callback) {
listening = listen
if (listening) {
appOpsController.addCallback(OPS, cb)
update()
update(true)
} else {
appOpsController.removeCallback(OPS, cb)
}
@@ -102,4 +134,12 @@ class PrivacyItemController(val context: Context, val callback: Callback) {
interface Callback {
fun privacyChanged(privacyItems: List<PrivacyItem>)
}
internal inner class Receiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action in intents) {
update(true)
}
}
}
}

View File

@@ -16,8 +16,12 @@
package com.android.systemui.privacy
import android.app.ActivityManager
import android.app.AppOpsManager
import android.content.Intent
import android.os.Handler
import android.os.UserHandle
import android.os.UserManager
import android.support.test.filters.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -34,9 +38,11 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyList
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -44,10 +50,18 @@ import org.mockito.MockitoAnnotations
@RunWithLooper
class PrivacyItemControllerTest : SysuiTestCase() {
companion object {
val CURRENT_USER_ID = ActivityManager.getCurrentUser()
val OTHER_USER = UserHandle(CURRENT_USER_ID + 1)
const val TAG = "PrivacyItemControllerTest"
}
@Mock
private lateinit var appOpsController: AppOpsController
@Mock
private lateinit var callback: PrivacyItemController.Callback
@Mock
private lateinit var userManager: UserManager
private lateinit var testableLooper: TestableLooper
private lateinit var privacyItemController: PrivacyItemController
@@ -57,15 +71,17 @@ class PrivacyItemControllerTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
testableLooper = TestableLooper.get(this)
appOpsController = mDependency.injectMockDependency(AppOpsController:: class.java)
appOpsController = mDependency.injectMockDependency(AppOpsController::class.java)
mDependency.injectTestDependency(Dependency.BG_LOOPER, testableLooper.looper)
mDependency.injectTestDependency(Dependency.MAIN_HANDLER, Handler(testableLooper.looper))
mContext.addMockSystemService(UserManager::class.java, userManager)
doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, 0, "", 0)))
.`when`(appOpsController).getActiveAppOpsForUser(anyInt())
privacyItemController = PrivacyItemController(mContext, callback)
}
@Test
fun testSetListeningTrue() {
privacyItemController.setListening(true)
@@ -80,6 +96,38 @@ class PrivacyItemControllerTest : SysuiTestCase() {
privacyItemController.setListening(true)
privacyItemController.setListening(false)
verify(appOpsController).removeCallback(eq(PrivacyItemController.OPS),
any(AppOpsController.Callback:: class.java))
any(AppOpsController.Callback::class.java))
}
@Test
fun testRegisterReceiver_allUsers() {
val spiedContext = spy(mContext)
val itemController = PrivacyItemController(spiedContext, callback)
verify(spiedContext, atLeastOnce()).registerReceiverAsUser(
eq(itemController.userSwitcherReceiver), eq(UserHandle.ALL), any(), eq(null),
eq(null))
verify(spiedContext, never()).unregisterReceiver(eq(itemController.userSwitcherReceiver))
}
@Test
fun testReceiver_ACTION_USER_FOREGROUND() {
privacyItemController.userSwitcherReceiver.onReceive(context,
Intent(Intent.ACTION_USER_FOREGROUND))
verify(userManager).getProfiles(anyInt())
}
@Test
fun testReceiver_ACTION_MANAGED_PROFILE_ADDED() {
privacyItemController.userSwitcherReceiver.onReceive(context,
Intent(Intent.ACTION_MANAGED_PROFILE_ADDED))
verify(userManager).getProfiles(anyInt())
}
@Test
fun testReceiver_ACTION_MANAGED_PROFILE_REMOVED() {
privacyItemController.userSwitcherReceiver.onReceive(context,
Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED))
verify(userManager).getProfiles(anyInt())
}
}