Merge "Create TogglePermissionAppInfoPage"
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spaprivileged.framework.app
|
||||
|
||||
import android.app.AppOpsManager
|
||||
import android.app.AppOpsManager.MODE_ALLOWED
|
||||
import android.app.AppOpsManager.MODE_ERRORED
|
||||
import android.app.AppOpsManager.Mode
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
||||
class AppOpsController(
|
||||
context: Context,
|
||||
private val app: ApplicationInfo,
|
||||
private val op: Int,
|
||||
) {
|
||||
private val appOpsManager = checkNotNull(context.getSystemService(AppOpsManager::class.java))
|
||||
|
||||
val isAllowed: LiveData<Boolean>
|
||||
get() = _isAllowed
|
||||
|
||||
fun setAllowed(allowed: Boolean) {
|
||||
val mode = if (allowed) MODE_ALLOWED else MODE_ERRORED
|
||||
appOpsManager.setMode(op, app.uid, app.packageName, mode)
|
||||
_isAllowed.postValue(allowed)
|
||||
}
|
||||
|
||||
@Mode
|
||||
private fun getMode(): Int = appOpsManager.checkOpNoThrow(op, app.uid, app.packageName)
|
||||
|
||||
private val _isAllowed = object : MutableLiveData<Boolean>() {
|
||||
override fun onActive() {
|
||||
postValue(getMode() == MODE_ALLOWED)
|
||||
}
|
||||
|
||||
override fun onInactive() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spaprivileged.framework.app
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
|
||||
interface AppRecord {
|
||||
val app: ApplicationInfo
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spaprivileged.framework.app
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.os.UserHandle
|
||||
|
||||
val ApplicationInfo.userId: Int
|
||||
get() = UserHandle.getUserId(uid)
|
||||
|
||||
fun ApplicationInfo.toRoute() = "$packageName/$userId"
|
||||
@@ -16,10 +16,14 @@
|
||||
|
||||
package com.android.settingslib.spaprivileged.framework.app
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
|
||||
object PackageManagers {
|
||||
fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo =
|
||||
PackageManager.getPackageInfoAsUserCached(packageName, 0, userId)
|
||||
|
||||
fun getApplicationInfoAsUser(packageName: String, userId: Int): ApplicationInfo =
|
||||
PackageManager.getApplicationInfoAsUserCached(packageName, 0, userId)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spaprivileged.template.app
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
||||
import com.android.settingslib.spa.widget.ui.Footer
|
||||
|
||||
@Composable
|
||||
fun AppInfoPage(
|
||||
title: String,
|
||||
packageName: String,
|
||||
userId: Int,
|
||||
footerText: String,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
// TODO: Replace with SettingsScaffold
|
||||
Column(Modifier.verticalScroll(rememberScrollState())) {
|
||||
Text(
|
||||
text = title,
|
||||
modifier = Modifier.padding(SettingsDimension.itemPadding),
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
)
|
||||
|
||||
AppInfo(packageName, userId)
|
||||
|
||||
content()
|
||||
|
||||
Footer(footerText)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spaprivileged.template.app
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.navArgument
|
||||
import com.android.settingslib.spa.framework.api.SettingsPageProvider
|
||||
import com.android.settingslib.spa.framework.compose.rememberContext
|
||||
import com.android.settingslib.spa.widget.preference.SwitchPreference
|
||||
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
||||
import com.android.settingslib.spaprivileged.framework.app.AppRecord
|
||||
import com.android.settingslib.spaprivileged.framework.app.PackageManagers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
private const val PERMISSION = "permission"
|
||||
private const val PACKAGE_NAME = "packageName"
|
||||
private const val USER_ID = "userId"
|
||||
|
||||
open class TogglePermissionAppInfoPageProvider(
|
||||
private val factory: TogglePermissionAppListModelFactory,
|
||||
) : SettingsPageProvider {
|
||||
override val name = "TogglePermissionAppInfoPage"
|
||||
|
||||
override val arguments = listOf(
|
||||
navArgument(PERMISSION) { type = NavType.StringType },
|
||||
navArgument(PACKAGE_NAME) { type = NavType.StringType },
|
||||
navArgument(USER_ID) { type = NavType.IntType },
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Page(arguments: Bundle?) {
|
||||
checkNotNull(arguments)
|
||||
val permission = checkNotNull(arguments.getString(PERMISSION))
|
||||
val packageName = checkNotNull(arguments.getString(PACKAGE_NAME))
|
||||
val userId = arguments.getInt(USER_ID)
|
||||
val listModel = rememberContext { context -> factory.createModel(permission, context) }
|
||||
TogglePermissionAppInfoPage(listModel, packageName, userId)
|
||||
}
|
||||
|
||||
fun getRoute(permissionType: String, packageName: String, userId: Int): String =
|
||||
"$name/$permissionType/$packageName/$userId"
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TogglePermissionAppInfoPage(
|
||||
listModel: TogglePermissionAppListModel<out AppRecord>,
|
||||
packageName: String,
|
||||
userId: Int,
|
||||
) {
|
||||
AppInfoPage(
|
||||
title = stringResource(listModel.pageTitleResId),
|
||||
packageName = packageName,
|
||||
userId = userId,
|
||||
footerText = stringResource(listModel.footerResId),
|
||||
) {
|
||||
val model = createSwitchModel(listModel, packageName, userId)
|
||||
LaunchedEffect(model, Dispatchers.Default) {
|
||||
model.initState()
|
||||
}
|
||||
SwitchPreference(model)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun <T : AppRecord> createSwitchModel(
|
||||
listModel: TogglePermissionAppListModel<T>,
|
||||
packageName: String,
|
||||
userId: Int,
|
||||
): TogglePermissionSwitchModel<T> {
|
||||
val record = remember {
|
||||
val app = PackageManagers.getApplicationInfoAsUser(packageName, userId)
|
||||
listModel.transformItem(app)
|
||||
}
|
||||
val context = LocalContext.current
|
||||
val isAllowed = listModel.isAllowed(record)
|
||||
return remember {
|
||||
TogglePermissionSwitchModel(context, listModel, record, isAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
private class TogglePermissionSwitchModel<T : AppRecord>(
|
||||
context: Context,
|
||||
private val listModel: TogglePermissionAppListModel<T>,
|
||||
private val record: T,
|
||||
isAllowed: State<Boolean?>,
|
||||
) : SwitchPreferenceModel {
|
||||
override val title: String = context.getString(listModel.switchTitleResId)
|
||||
override val checked = isAllowed
|
||||
override val changeable = mutableStateOf(true)
|
||||
|
||||
fun initState() {
|
||||
changeable.value = listModel.isChangeable(record)
|
||||
}
|
||||
|
||||
override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
|
||||
listModel.setAllowed(record, newChecked)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spaprivileged.template.app
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import com.android.settingslib.spaprivileged.framework.app.AppRecord
|
||||
|
||||
interface TogglePermissionAppListModel<T : AppRecord> {
|
||||
val pageTitleResId: Int
|
||||
val switchTitleResId: Int
|
||||
val footerResId: Int
|
||||
|
||||
fun transformItem(app: ApplicationInfo): T
|
||||
|
||||
@Composable
|
||||
fun isAllowed(record: T): State<Boolean?>
|
||||
|
||||
fun isChangeable(record: T): Boolean
|
||||
fun setAllowed(record: T, newAllowed: Boolean)
|
||||
}
|
||||
|
||||
interface TogglePermissionAppListModelFactory {
|
||||
fun createModel(
|
||||
permission: String,
|
||||
context: Context,
|
||||
): TogglePermissionAppListModel<out AppRecord>
|
||||
}
|
||||
Reference in New Issue
Block a user