Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3bda562 authored by Chaohui Wang's avatar Chaohui Wang
Browse files

Hide not changeable app from AppOpPermissionAppList

Also add unit tests for AppOpPermissionAppList.

Also correct the test only resources R to
com.android.settingslib.spaprivileged.test.R

Bug: 260660819
Test: Unit test
Test: Manually with Settings
Change-Id: I732f777906c5ea4a79e876b982ba0ca28b39a0ee
parent f9078e0e
Loading
Loading
Loading
Loading
+17 −11
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.settingslib.spaprivileged.model.app

import android.app.AppOpsManager
import android.app.AppOpsManager.MODE_ALLOWED
import android.app.AppOpsManager.MODE_ERRORED
import android.app.AppOpsManager.Mode
@@ -25,34 +24,41 @@ import android.content.pm.ApplicationInfo
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
import com.android.settingslib.spaprivileged.framework.common.appOpsManager

interface IAppOpsController {
    val mode: LiveData<Int>
    val isAllowed: LiveData<Boolean>
        get() = mode.map { it == MODE_ALLOWED }

    fun setAllowed(allowed: Boolean)

    @Mode
    fun getMode(): Int
}

class AppOpsController(
    context: Context,
    private val app: ApplicationInfo,
    private val op: Int,
) {
    private val appOpsManager = checkNotNull(context.getSystemService(AppOpsManager::class.java))
) : IAppOpsController {
    private val appOpsManager = context.appOpsManager

    val mode: LiveData<Int>
    override val mode: LiveData<Int>
        get() = _mode
    val isAllowed: LiveData<Boolean>
        get() = _mode.map { it == MODE_ALLOWED }

    fun setAllowed(allowed: Boolean) {
    override fun setAllowed(allowed: Boolean) {
        val mode = if (allowed) MODE_ALLOWED else MODE_ERRORED
        appOpsManager.setMode(op, app.uid, app.packageName, mode)
        _mode.postValue(mode)
    }

    @Mode
    fun getMode(): Int = appOpsManager.checkOpNoThrow(op, app.uid, app.packageName)
    override fun getMode(): Int = appOpsManager.checkOpNoThrow(op, app.uid, app.packageName)

    private val _mode = object : MutableLiveData<Int>() {
        override fun onActive() {
            postValue(getMode())
        }

        override fun onInactive() {
        }
    }
}
+15 −11
Original line number Diff line number Diff line
@@ -25,11 +25,12 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import com.android.settingslib.spa.framework.util.filterItem
import com.android.settingslib.spaprivileged.model.app.AppOpsController
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.IAppOpsController
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
import com.android.settingslib.spaprivileged.model.app.PackageManagers
import com.android.settingslib.spaprivileged.model.app.PackageManagers.hasGrantPermission
import com.android.settingslib.spaprivileged.model.app.PackageManagers.hasRequestPermission
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
@@ -37,21 +38,24 @@ import kotlinx.coroutines.flow.map
data class AppOpPermissionRecord(
    override val app: ApplicationInfo,
    val hasRequestPermission: Boolean,
    var appOpsController: AppOpsController,
    var appOpsController: IAppOpsController,
) : AppRecord

abstract class AppOpPermissionListModel(private val context: Context) :
    TogglePermissionAppListModel<AppOpPermissionRecord> {
abstract class AppOpPermissionListModel(
    private val context: Context,
    private val packageManagers: IPackageManagers = PackageManagers,
) : TogglePermissionAppListModel<AppOpPermissionRecord> {

    abstract val appOp: Int
    abstract val permission: String

    /** These not changeable packages will also be hidden from app list. */
    private val notChangeablePackages =
        setOf("android", "com.android.systemui", context.packageName)

    override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
        userIdFlow.map { userId ->
            PackageManagers.getAppOpPermissionPackages(userId, permission)
            packageManagers.getAppOpPermissionPackages(userId, permission)
        }.combine(appListFlow) { packageNames, appList ->
            appList.map { app ->
                AppOpPermissionRecord(
@@ -64,14 +68,12 @@ abstract class AppOpPermissionListModel(private val context: Context) :

    override fun transformItem(app: ApplicationInfo) = AppOpPermissionRecord(
        app = app,
        hasRequestPermission = app.hasRequestPermission(permission),
        hasRequestPermission = with(packageManagers) { app.hasRequestPermission(permission) },
        appOpsController = AppOpsController(context = context, app = app, op = appOp),
    )

    override fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<AppOpPermissionRecord>>) =
        recordListFlow.map { recordList ->
            recordList.filter { it.hasRequestPermission }
        }
        recordListFlow.filterItem(::isChangeable)

    /**
     * Defining the default behavior as permissible as long as the package requested this permission
@@ -85,7 +87,9 @@ abstract class AppOpPermissionListModel(private val context: Context) :
                when (mode.value) {
                    null -> null
                    MODE_ALLOWED -> true
                    MODE_DEFAULT -> record.app.hasGrantPermission(permission)
                    MODE_DEFAULT -> with(packageManagers) {
                        record.app.hasGrantPermission(permission)
                    }
                    else -> false
                }
            }
+2 −2
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.settingslib.spaprivileged.tests">
    package="com.android.settingslib.spaprivileged.test">

    <application>
        <uses-library android:name="android.test.runner" />
@@ -24,5 +24,5 @@
    <instrumentation
        android:name="androidx.test.runner.AndroidJUnitRunner"
        android:label="Tests for SpaPrivilegedLib"
        android:targetPackage="com.android.settingslib.spaprivileged.tests" />
        android:targetPackage="com.android.settingslib.spaprivileged.test" />
</manifest>
+10 −1
Original line number Diff line number Diff line
@@ -22,5 +22,14 @@
    <string name="test_permission_switch_title" translatable="false">Allow Test Permission</string>

    <!-- Test Permission footer. [DO NOT TRANSLATE] -->
    <string name="test_permission_footer" translatable="false">Test Permission is for demo.</string>
    <string name="test_permission_footer" translatable="false">Test Permission is for testing.</string>

    <!-- Test App Op Permission title. [DO NOT TRANSLATE] -->
    <string name="test_app_op_permission_title" translatable="false">Test App Op Permission</string>

    <!-- Test App Op Permission switch title. [DO NOT TRANSLATE] -->
    <string name="test_app_op_permission_switch_title" translatable="false">Allow Test App Op Permission</string>

    <!-- Test App Op Permission footer. [DO NOT TRANSLATE] -->
    <string name="test_app_op_permission_footer" translatable="false">Test App Op Permission is for testing.</string>
</resources>
+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ class AppInfoTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    private var context: Context = ApplicationProvider.getApplicationContext()
    private val context: Context = ApplicationProvider.getApplicationContext()

    @Test
    fun appInfoLabel_isDisplayed() {
Loading