diff --git a/Android.bp b/Android.bp index 5bf5514cbc4..4af8d099d58 100644 --- a/Android.bp +++ b/Android.bp @@ -51,6 +51,7 @@ android_library { defaults: [ "SettingsLibDefaults", "SettingsLib-search-defaults", + "SpaPrivilegedLib-defaults", ], srcs: ["src/**/*.java", "src/**/*.kt"], @@ -63,6 +64,7 @@ android_library { "androidx.core_core", "androidx.appcompat_appcompat", "androidx.cardview_cardview", + "androidx.compose.runtime_runtime-livedata", "androidx.preference_preference", "androidx.recyclerview_recyclerview", "androidx.window_window", @@ -103,7 +105,10 @@ platform_compat_config { android_app { name: "Settings", - defaults: ["platform_app_defaults"], + defaults: [ + "platform_app_defaults", + "SpaPrivilegedLib-defaults", + ], platform_apis: true, certificate: "platform", system_ext_specific: true, diff --git a/AndroidManifest.xml b/AndroidManifest.xml index cf93f9b12e0..c05d310719b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -4544,6 +4544,11 @@ + + + diff --git a/src/com/android/settings/spa/SpaActivity.kt b/src/com/android/settings/spa/SpaActivity.kt new file mode 100644 index 00000000000..7e79350c8b4 --- /dev/null +++ b/src/com/android/settings/spa/SpaActivity.kt @@ -0,0 +1,21 @@ +/* + * 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.settings.spa + +import com.android.settingslib.spa.framework.BrowseActivity + +class SpaActivity : BrowseActivity(settingsPageProviders) diff --git a/src/com/android/settings/spa/SpaEnvironment.kt b/src/com/android/settings/spa/SpaEnvironment.kt new file mode 100644 index 00000000000..fad7ef23ea8 --- /dev/null +++ b/src/com/android/settings/spa/SpaEnvironment.kt @@ -0,0 +1,33 @@ +/* + * 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.settings.spa + +import com.android.settings.spa.app.InstallUnknownAppsListProvider +import com.android.settings.spa.home.HomePageProvider +import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository +import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListTemplate + +private val togglePermissionAppListTemplate = TogglePermissionAppListTemplate( + allProviders = listOf(InstallUnknownAppsListProvider), +) + +val settingsPageProviders = SettingsPageProviderRepository( + allPagesList = listOf( + HomePageProvider, + ) + togglePermissionAppListTemplate.createPageProviders(), + rootPages = listOf(HomePageProvider.name), +) diff --git a/src/com/android/settings/spa/app/InstallUnknownApps.kt b/src/com/android/settings/spa/app/InstallUnknownApps.kt new file mode 100644 index 00000000000..a09fda2b098 --- /dev/null +++ b/src/com/android/settings/spa/app/InstallUnknownApps.kt @@ -0,0 +1,94 @@ +/* + * 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.settings.spa.app + +import android.Manifest +import android.app.AppGlobals +import android.app.AppOpsManager.MODE_DEFAULT +import android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES +import android.content.Context +import android.content.pm.ApplicationInfo +import androidx.compose.runtime.Composable +import androidx.compose.runtime.livedata.observeAsState +import com.android.settings.R +import com.android.settingslib.spaprivileged.model.app.AppOpsController +import com.android.settingslib.spaprivileged.model.app.AppRecord +import com.android.settingslib.spaprivileged.model.app.userId +import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListModel +import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map + +object InstallUnknownAppsListProvider : TogglePermissionAppListProvider { + override val permissionType = "InstallUnknownApps" + override fun createModel(context: Context) = InstallUnknownAppsListModel(context) +} + +data class InstallUnknownAppsRecord( + override val app: ApplicationInfo, + val appOpsController: AppOpsController, +) : AppRecord + +class InstallUnknownAppsListModel(private val context: Context) : + TogglePermissionAppListModel { + override val pageTitleResId = R.string.install_other_apps + override val switchTitleResId = R.string.external_source_switch_title + override val footerResId = R.string.install_all_warning + + override fun transformItem(app: ApplicationInfo) = InstallUnknownAppsRecord( + app = app, + appOpsController = AppOpsController( + context = context, + app = app, + op = OP_REQUEST_INSTALL_PACKAGES, + ), + ) + + override fun filter( + userIdFlow: Flow, recordListFlow: Flow>, + ) = userIdFlow.map(::getPotentialPackageNames) + .combine(recordListFlow) { potentialPackageNames, recordList -> + recordList.filter { record -> + isChangeable(record, potentialPackageNames) + } + } + + @Composable + override fun isAllowed(record: InstallUnknownAppsRecord) = + record.appOpsController.isAllowed.observeAsState() + + override fun isChangeable(record: InstallUnknownAppsRecord) = + isChangeable(record, getPotentialPackageNames(record.app.userId)) + + override fun setAllowed(record: InstallUnknownAppsRecord, newAllowed: Boolean) { + record.appOpsController.setAllowed(newAllowed) + } + + companion object { + private fun isChangeable( + record: InstallUnknownAppsRecord, + potentialPackageNames: Set, + ) = record.appOpsController.getMode() != MODE_DEFAULT || + record.app.packageName in potentialPackageNames + + private fun getPotentialPackageNames(userId: Int): Set = + AppGlobals.getPackageManager().getAppOpPermissionPackages( + Manifest.permission.REQUEST_INSTALL_PACKAGES, userId + ).toSet() + } +} diff --git a/src/com/android/settings/spa/home/HomePage.kt b/src/com/android/settings/spa/home/HomePage.kt new file mode 100644 index 00000000000..6cd6fe67086 --- /dev/null +++ b/src/com/android/settings/spa/home/HomePage.kt @@ -0,0 +1,41 @@ +/* + * 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.settings.spa.home + +import android.os.Bundle +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import com.android.settings.R +import com.android.settings.spa.app.InstallUnknownAppsListProvider +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.widget.scaffold.HomeScaffold + +object HomePageProvider : SettingsPageProvider { + override val name = "Home" + + @Composable + override fun Page(arguments: Bundle?) { + HomePage() + } +} + +@Composable +private fun HomePage() { + HomeScaffold(title = stringResource(R.string.settings_label)) { + InstallUnknownAppsListProvider.EntryItem() + } +}