Loading packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt +47 −7 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, Loading @@ -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) } Loading @@ -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) } Loading @@ -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) } } } } No newline at end of file packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt +51 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading @@ -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 Loading @@ -60,12 +74,14 @@ class PrivacyItemControllerTest : SysuiTestCase() { 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) Loading @@ -82,4 +98,36 @@ class PrivacyItemControllerTest : SysuiTestCase() { verify(appOpsController).removeCallback(eq(PrivacyItemController.OPS), 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()) } } No newline at end of file Loading
packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt +47 −7 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, Loading @@ -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) } Loading @@ -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) } Loading @@ -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) } } } } No newline at end of file
packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt +51 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading @@ -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 Loading @@ -60,12 +74,14 @@ class PrivacyItemControllerTest : SysuiTestCase() { 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) Loading @@ -82,4 +98,36 @@ class PrivacyItemControllerTest : SysuiTestCase() { verify(appOpsController).removeCallback(eq(PrivacyItemController.OPS), 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()) } } No newline at end of file