Loading packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt +12 −23 Original line number Diff line number Diff line Loading @@ -29,46 +29,36 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map interface IAppOpsController { val modeFlow: Flow<Int> val mode: Flow<Int> val isAllowed: Flow<Boolean> get() = modeFlow.map { it == MODE_ALLOWED } get() = mode.map { it == MODE_ALLOWED } fun setAllowed(allowed: Boolean) @Mode fun getMode(): Int } data class AppOps( val op: Int, val modeForNotAllowed: Int = MODE_ERRORED, /** * Use AppOpsManager#setUidMode() instead of AppOpsManager#setMode() when set allowed. * * Security or privacy related app-ops should be set with setUidMode() instead of setMode(). */ val setModeByUid: Boolean = false, ) class AppOpsController( context: Context, private val app: ApplicationInfo, private val appOps: AppOps, private val op: Int, private val modeForNotAllowed: Int = MODE_ERRORED, private val setModeByUid: Boolean = false, ) : IAppOpsController { private val appOpsManager = context.appOpsManager private val packageManager = context.packageManager override val modeFlow = appOpsManager.opModeFlow(appOps.op, app) override val mode = appOpsManager.opModeFlow(op, app) override fun setAllowed(allowed: Boolean) { val mode = if (allowed) MODE_ALLOWED else appOps.modeForNotAllowed val mode = if (allowed) MODE_ALLOWED else modeForNotAllowed if (appOps.setModeByUid) { appOpsManager.setUidMode(appOps.op, app.uid, mode) if (setModeByUid) { appOpsManager.setUidMode(op, app.uid, mode) } else { appOpsManager.setMode(appOps.op, app.uid, app.packageName, mode) appOpsManager.setMode(op, app.uid, app.packageName, mode) } val permission = AppOpsManager.opToPermission(appOps.op) val permission = AppOpsManager.opToPermission(op) if (permission != null) { packageManager.updatePermissionFlags(permission, app.packageName, PackageManager.FLAG_PERMISSION_USER_SET, Loading @@ -77,6 +67,5 @@ class AppOpsController( } } @Mode override fun getMode(): Int = appOpsManager.getOpMode(appOps.op, app) @Mode override fun getMode(): Int = appOpsManager.getOpMode(op, app) } packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt +19 −5 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import androidx.compose.runtime.Composable import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.settingslib.spa.framework.util.asyncMapItem import com.android.settingslib.spa.framework.util.filterItem import com.android.settingslib.spaprivileged.model.app.AppOps import com.android.settingslib.spaprivileged.model.app.AppOpsController import com.android.settingslib.spaprivileged.model.app.AppRecord import com.android.settingslib.spaprivileged.model.app.IAppOpsController Loading @@ -45,11 +44,11 @@ abstract class AppOpPermissionListModel( private val packageManagers: IPackageManagers = PackageManagers, ) : TogglePermissionAppListModel<AppOpPermissionRecord> { abstract val appOps: AppOps abstract val appOp: Int abstract val permission: String override val enhancedConfirmationKey: String? get() = AppOpsManager.opToPublicName(appOps.op) get() = AppOpsManager.opToPublicName(appOp) /** * When set, specifies the broader permission who trumps the [permission]. Loading @@ -66,12 +65,27 @@ abstract class AppOpPermissionListModel( */ open val permissionHasAppOpFlag: Boolean = true open val modeForNotAllowed: Int = AppOpsManager.MODE_ERRORED /** * Use AppOpsManager#setUidMode() instead of AppOpsManager#setMode() when set allowed. * * Security or privacy related app-ops should be set with setUidMode() instead of setMode(). */ open val setModeByUid = false /** These not changeable packages will also be hidden from app list. */ private val notChangeablePackages = setOf("android", "com.android.systemui", context.packageName) private fun createAppOpsController(app: ApplicationInfo) = AppOpsController(context, app, appOps) AppOpsController( context = context, app = app, op = appOp, setModeByUid = setModeByUid, modeForNotAllowed = modeForNotAllowed, ) private fun createRecord( app: ApplicationInfo, Loading Loading @@ -152,7 +166,7 @@ internal fun isAllowed( return { true } } val mode = appOpsController.modeFlow.collectAsStateWithLifecycle(initialValue = null) val mode = appOpsController.mode.collectAsStateWithLifecycle(initialValue = null) return { when (mode.value) { null -> null Loading packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt +54 −26 Original line number Diff line number Diff line Loading @@ -27,14 +27,16 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settingslib.spaprivileged.framework.common.appOpsManager import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Spy import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.spy import org.mockito.kotlin.any import org.mockito.kotlin.doNothing import org.mockito.kotlin.verify import org.mockito.kotlin.whenever Loading @@ -42,18 +44,28 @@ import org.mockito.kotlin.whenever class AppOpsControllerTest { @get:Rule val mockito: MockitoRule = MockitoJUnit.rule() private val appOpsManager = mock<AppOpsManager>() @Spy private val context: Context = ApplicationProvider.getApplicationContext() private val packageManager = mock<PackageManager>() @Mock private lateinit var appOpsManager: AppOpsManager private val context: Context = spy(ApplicationProvider.getApplicationContext()) { on { appOpsManager } doReturn appOpsManager on { packageManager } doReturn packageManager @Mock private lateinit var packageManager: PackageManager @Before fun setUp() { whenever(context.appOpsManager).thenReturn(appOpsManager) whenever(context.packageManager).thenReturn(packageManager) doNothing().whenever(packageManager) .updatePermissionFlags(any(), any(), any(), any(), any()) } @Test fun setAllowed_setToTrue() { val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP)) val controller = AppOpsController( context = context, app = APP, op = OP, ) controller.setAllowed(true) Loading @@ -62,7 +74,12 @@ class AppOpsControllerTest { @Test fun setAllowed_setToFalse() { val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP)) val controller = AppOpsController( context = context, app = APP, op = OP, ) controller.setAllowed(false) Loading @@ -71,10 +88,12 @@ class AppOpsControllerTest { @Test fun setAllowed_setToFalseWithModeForNotAllowed() { val controller = AppOpsController( val controller = AppOpsController( context = context, app = APP, appOps = AppOps(op = OP, modeForNotAllowed = MODE_IGNORED), op = OP, modeForNotAllowed = MODE_IGNORED, ) controller.setAllowed(false) Loading @@ -84,10 +103,12 @@ class AppOpsControllerTest { @Test fun setAllowed_setToTrueByUid() { val controller = AppOpsController( val controller = AppOpsController( context = context, app = APP, appOps = AppOps(op = OP, setModeByUid = true), op = OP, setModeByUid = true, ) controller.setAllowed(true) Loading @@ -97,10 +118,12 @@ class AppOpsControllerTest { @Test fun setAllowed_setToFalseByUid() { val controller = AppOpsController( val controller = AppOpsController( context = context, app = APP, appOps = AppOps(op = OP, setModeByUid = true), op = OP, setModeByUid = true, ) controller.setAllowed(false) Loading @@ -112,7 +135,12 @@ class AppOpsControllerTest { fun getMode() { whenever(appOpsManager.checkOpNoThrow(OP, APP.uid, APP.packageName)) .thenReturn(MODE_ALLOWED) val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP)) val controller = AppOpsController( context = context, app = APP, op = OP, ) val mode = controller.getMode() Loading packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt +15 −3 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull import com.android.settingslib.spaprivileged.framework.common.appOpsManager import com.android.settingslib.spaprivileged.model.app.AppOps import com.android.settingslib.spaprivileged.model.app.IAppOpsController import com.android.settingslib.spaprivileged.model.app.IPackageManagers import com.android.settingslib.spaprivileged.test.R Loading @@ -40,6 +39,7 @@ import org.mockito.kotlin.doNothing import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.spy import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) Loading Loading @@ -287,6 +287,16 @@ class AppOpPermissionAppListTest { assertThat(appOpsController.setAllowedCalledWith).isTrue() } @Test fun setAllowed_setModeByUid() { listModel.setModeByUid = true val record = listModel.transformItem(APP) listModel.setAllowed(record = record, newAllowed = true) verify(appOpsManager).setUidMode(listModel.appOp, APP.uid, AppOpsManager.MODE_ALLOWED) } private fun getIsAllowed(record: AppOpPermissionRecord): Boolean? { lateinit var isAllowedState: () -> Boolean? composeTestRule.setContent { isAllowedState = listModel.isAllowed(record) } Loading @@ -299,9 +309,11 @@ class AppOpPermissionAppListTest { override val switchTitleResId = R.string.test_app_op_permission_switch_title override val footerResId = R.string.test_app_op_permission_footer override val appOps = AppOps(AppOpsManager.OP_MANAGE_MEDIA) override val appOp = AppOpsManager.OP_MANAGE_MEDIA override val permission = PERMISSION override var broaderPermission: String? = null override var setModeByUid = false } private companion object { Loading @@ -317,7 +329,7 @@ class AppOpPermissionAppListTest { private class FakeAppOpsController(private val fakeMode: Int) : IAppOpsController { var setAllowedCalledWith: Boolean? = null override val modeFlow = flowOf(fakeMode) override val mode = flowOf(fakeMode) override fun setAllowed(allowed: Boolean) { setAllowedCalledWith = allowed Loading Loading
packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt +12 −23 Original line number Diff line number Diff line Loading @@ -29,46 +29,36 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map interface IAppOpsController { val modeFlow: Flow<Int> val mode: Flow<Int> val isAllowed: Flow<Boolean> get() = modeFlow.map { it == MODE_ALLOWED } get() = mode.map { it == MODE_ALLOWED } fun setAllowed(allowed: Boolean) @Mode fun getMode(): Int } data class AppOps( val op: Int, val modeForNotAllowed: Int = MODE_ERRORED, /** * Use AppOpsManager#setUidMode() instead of AppOpsManager#setMode() when set allowed. * * Security or privacy related app-ops should be set with setUidMode() instead of setMode(). */ val setModeByUid: Boolean = false, ) class AppOpsController( context: Context, private val app: ApplicationInfo, private val appOps: AppOps, private val op: Int, private val modeForNotAllowed: Int = MODE_ERRORED, private val setModeByUid: Boolean = false, ) : IAppOpsController { private val appOpsManager = context.appOpsManager private val packageManager = context.packageManager override val modeFlow = appOpsManager.opModeFlow(appOps.op, app) override val mode = appOpsManager.opModeFlow(op, app) override fun setAllowed(allowed: Boolean) { val mode = if (allowed) MODE_ALLOWED else appOps.modeForNotAllowed val mode = if (allowed) MODE_ALLOWED else modeForNotAllowed if (appOps.setModeByUid) { appOpsManager.setUidMode(appOps.op, app.uid, mode) if (setModeByUid) { appOpsManager.setUidMode(op, app.uid, mode) } else { appOpsManager.setMode(appOps.op, app.uid, app.packageName, mode) appOpsManager.setMode(op, app.uid, app.packageName, mode) } val permission = AppOpsManager.opToPermission(appOps.op) val permission = AppOpsManager.opToPermission(op) if (permission != null) { packageManager.updatePermissionFlags(permission, app.packageName, PackageManager.FLAG_PERMISSION_USER_SET, Loading @@ -77,6 +67,5 @@ class AppOpsController( } } @Mode override fun getMode(): Int = appOpsManager.getOpMode(appOps.op, app) @Mode override fun getMode(): Int = appOpsManager.getOpMode(op, app) }
packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt +19 −5 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import androidx.compose.runtime.Composable import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.settingslib.spa.framework.util.asyncMapItem import com.android.settingslib.spa.framework.util.filterItem import com.android.settingslib.spaprivileged.model.app.AppOps import com.android.settingslib.spaprivileged.model.app.AppOpsController import com.android.settingslib.spaprivileged.model.app.AppRecord import com.android.settingslib.spaprivileged.model.app.IAppOpsController Loading @@ -45,11 +44,11 @@ abstract class AppOpPermissionListModel( private val packageManagers: IPackageManagers = PackageManagers, ) : TogglePermissionAppListModel<AppOpPermissionRecord> { abstract val appOps: AppOps abstract val appOp: Int abstract val permission: String override val enhancedConfirmationKey: String? get() = AppOpsManager.opToPublicName(appOps.op) get() = AppOpsManager.opToPublicName(appOp) /** * When set, specifies the broader permission who trumps the [permission]. Loading @@ -66,12 +65,27 @@ abstract class AppOpPermissionListModel( */ open val permissionHasAppOpFlag: Boolean = true open val modeForNotAllowed: Int = AppOpsManager.MODE_ERRORED /** * Use AppOpsManager#setUidMode() instead of AppOpsManager#setMode() when set allowed. * * Security or privacy related app-ops should be set with setUidMode() instead of setMode(). */ open val setModeByUid = false /** These not changeable packages will also be hidden from app list. */ private val notChangeablePackages = setOf("android", "com.android.systemui", context.packageName) private fun createAppOpsController(app: ApplicationInfo) = AppOpsController(context, app, appOps) AppOpsController( context = context, app = app, op = appOp, setModeByUid = setModeByUid, modeForNotAllowed = modeForNotAllowed, ) private fun createRecord( app: ApplicationInfo, Loading Loading @@ -152,7 +166,7 @@ internal fun isAllowed( return { true } } val mode = appOpsController.modeFlow.collectAsStateWithLifecycle(initialValue = null) val mode = appOpsController.mode.collectAsStateWithLifecycle(initialValue = null) return { when (mode.value) { null -> null Loading
packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt +54 −26 Original line number Diff line number Diff line Loading @@ -27,14 +27,16 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settingslib.spaprivileged.framework.common.appOpsManager import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Spy import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.spy import org.mockito.kotlin.any import org.mockito.kotlin.doNothing import org.mockito.kotlin.verify import org.mockito.kotlin.whenever Loading @@ -42,18 +44,28 @@ import org.mockito.kotlin.whenever class AppOpsControllerTest { @get:Rule val mockito: MockitoRule = MockitoJUnit.rule() private val appOpsManager = mock<AppOpsManager>() @Spy private val context: Context = ApplicationProvider.getApplicationContext() private val packageManager = mock<PackageManager>() @Mock private lateinit var appOpsManager: AppOpsManager private val context: Context = spy(ApplicationProvider.getApplicationContext()) { on { appOpsManager } doReturn appOpsManager on { packageManager } doReturn packageManager @Mock private lateinit var packageManager: PackageManager @Before fun setUp() { whenever(context.appOpsManager).thenReturn(appOpsManager) whenever(context.packageManager).thenReturn(packageManager) doNothing().whenever(packageManager) .updatePermissionFlags(any(), any(), any(), any(), any()) } @Test fun setAllowed_setToTrue() { val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP)) val controller = AppOpsController( context = context, app = APP, op = OP, ) controller.setAllowed(true) Loading @@ -62,7 +74,12 @@ class AppOpsControllerTest { @Test fun setAllowed_setToFalse() { val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP)) val controller = AppOpsController( context = context, app = APP, op = OP, ) controller.setAllowed(false) Loading @@ -71,10 +88,12 @@ class AppOpsControllerTest { @Test fun setAllowed_setToFalseWithModeForNotAllowed() { val controller = AppOpsController( val controller = AppOpsController( context = context, app = APP, appOps = AppOps(op = OP, modeForNotAllowed = MODE_IGNORED), op = OP, modeForNotAllowed = MODE_IGNORED, ) controller.setAllowed(false) Loading @@ -84,10 +103,12 @@ class AppOpsControllerTest { @Test fun setAllowed_setToTrueByUid() { val controller = AppOpsController( val controller = AppOpsController( context = context, app = APP, appOps = AppOps(op = OP, setModeByUid = true), op = OP, setModeByUid = true, ) controller.setAllowed(true) Loading @@ -97,10 +118,12 @@ class AppOpsControllerTest { @Test fun setAllowed_setToFalseByUid() { val controller = AppOpsController( val controller = AppOpsController( context = context, app = APP, appOps = AppOps(op = OP, setModeByUid = true), op = OP, setModeByUid = true, ) controller.setAllowed(false) Loading @@ -112,7 +135,12 @@ class AppOpsControllerTest { fun getMode() { whenever(appOpsManager.checkOpNoThrow(OP, APP.uid, APP.packageName)) .thenReturn(MODE_ALLOWED) val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP)) val controller = AppOpsController( context = context, app = APP, op = OP, ) val mode = controller.getMode() Loading
packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt +15 −3 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull import com.android.settingslib.spaprivileged.framework.common.appOpsManager import com.android.settingslib.spaprivileged.model.app.AppOps import com.android.settingslib.spaprivileged.model.app.IAppOpsController import com.android.settingslib.spaprivileged.model.app.IPackageManagers import com.android.settingslib.spaprivileged.test.R Loading @@ -40,6 +39,7 @@ import org.mockito.kotlin.doNothing import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.spy import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) Loading Loading @@ -287,6 +287,16 @@ class AppOpPermissionAppListTest { assertThat(appOpsController.setAllowedCalledWith).isTrue() } @Test fun setAllowed_setModeByUid() { listModel.setModeByUid = true val record = listModel.transformItem(APP) listModel.setAllowed(record = record, newAllowed = true) verify(appOpsManager).setUidMode(listModel.appOp, APP.uid, AppOpsManager.MODE_ALLOWED) } private fun getIsAllowed(record: AppOpPermissionRecord): Boolean? { lateinit var isAllowedState: () -> Boolean? composeTestRule.setContent { isAllowedState = listModel.isAllowed(record) } Loading @@ -299,9 +309,11 @@ class AppOpPermissionAppListTest { override val switchTitleResId = R.string.test_app_op_permission_switch_title override val footerResId = R.string.test_app_op_permission_footer override val appOps = AppOps(AppOpsManager.OP_MANAGE_MEDIA) override val appOp = AppOpsManager.OP_MANAGE_MEDIA override val permission = PERMISSION override var broaderPermission: String? = null override var setModeByUid = false } private companion object { Loading @@ -317,7 +329,7 @@ class AppOpPermissionAppListTest { private class FakeAppOpsController(private val fakeMode: Int) : IAppOpsController { var setAllowedCalledWith: Boolean? = null override val modeFlow = flowOf(fakeMode) override val mode = flowOf(fakeMode) override fun setAllowed(allowed: Boolean) { setAllowedCalledWith = allowed Loading