From 9bad2fd7acac3c8482c5a3b579ca2bc9a6d6cc26 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Wed, 28 Sep 2022 20:28:41 +0800 Subject: [PATCH] Add install & clear app button for instant app These 2 buttons are only for instant apps. Bug: 236346018 Test: App Settings page with Instant App Change-Id: Ibdb27ff78172a59267c16bdfe5a256353fc91b26 --- .../spa/app/appsettings/AppButtons.kt | 5 ++ .../spa/app/appsettings/AppClearButton.kt | 80 +++++++++++++++++++ .../spa/app/appsettings/AppDisableButton.kt | 2 +- .../spa/app/appsettings/AppInstallButton.kt | 46 +++++++++++ .../spa/app/appsettings/AppUninstallButton.kt | 2 +- .../app/appsettings/PackageInfoPresenter.kt | 14 +++- 6 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 src/com/android/settings/spa/app/appsettings/AppClearButton.kt create mode 100644 src/com/android/settings/spa/app/appsettings/AppInstallButton.kt diff --git a/src/com/android/settings/spa/app/appsettings/AppButtons.kt b/src/com/android/settings/spa/app/appsettings/AppButtons.kt index 5082bea22e8..30fcdb77515 100644 --- a/src/com/android/settings/spa/app/appsettings/AppButtons.kt +++ b/src/com/android/settings/spa/app/appsettings/AppButtons.kt @@ -33,8 +33,10 @@ fun AppButtons(packageInfoPresenter: PackageInfoPresenter) { private class AppButtonsHolder(private val packageInfoPresenter: PackageInfoPresenter) { private val appLaunchButton = AppLaunchButton(packageInfoPresenter) + private val appInstallButton = AppInstallButton(packageInfoPresenter) private val appDisableButton = AppDisableButton(packageInfoPresenter) private val appUninstallButton = AppUninstallButton(packageInfoPresenter) + private val appClearButton = AppClearButton(packageInfoPresenter) private val appForceStopButton = AppForceStopButton(packageInfoPresenter) @Composable @@ -46,14 +48,17 @@ private class AppButtonsHolder(private val packageInfoPresenter: PackageInfoPres private fun getActionButtons(packageInfo: PackageInfo): List = listOfNotNull( appLaunchButton.getActionButton(packageInfo), + appInstallButton.getActionButton(packageInfo), appDisableButton.getActionButton(packageInfo), appUninstallButton.getActionButton(packageInfo), + appClearButton.getActionButton(packageInfo), appForceStopButton.getActionButton(packageInfo), ) @Composable fun Dialogs() { appDisableButton.DisableConfirmDialog() + appClearButton.ClearConfirmDialog() appForceStopButton.ForceStopConfirmDialog() } } diff --git a/src/com/android/settings/spa/app/appsettings/AppClearButton.kt b/src/com/android/settings/spa/app/appsettings/AppClearButton.kt new file mode 100644 index 00000000000..e16e09168d3 --- /dev/null +++ b/src/com/android/settings/spa/app/appsettings/AppClearButton.kt @@ -0,0 +1,80 @@ +/* + * 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.appsettings + +import android.content.pm.PackageInfo +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Delete +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.res.stringResource +import com.android.settings.R +import com.android.settingslib.spa.widget.button.ActionButton + +class AppClearButton( + private val packageInfoPresenter: PackageInfoPresenter, +) { + private val context = packageInfoPresenter.context + + private var openConfirmDialog by mutableStateOf(false) + + fun getActionButton(packageInfo: PackageInfo): ActionButton? { + val app = packageInfo.applicationInfo + if (!app.isInstantApp) return null + + return clearButton() + } + + private fun clearButton() = ActionButton( + text = context.getString(R.string.clear_instant_app_data), + imageVector = Icons.Outlined.Delete, + ) { openConfirmDialog = true } + + @Composable + fun ClearConfirmDialog() { + if (!openConfirmDialog) return + AlertDialog( + onDismissRequest = { openConfirmDialog = false }, + confirmButton = { + TextButton( + onClick = { + openConfirmDialog = false + packageInfoPresenter.clearInstantApp() + }, + ) { + Text(stringResource(R.string.clear_instant_app_data)) + } + }, + dismissButton = { + TextButton(onClick = { openConfirmDialog = false }) { + Text(stringResource(R.string.cancel)) + } + }, + title = { + Text(stringResource(R.string.clear_instant_app_data)) + }, + text = { + Text(stringResource(R.string.clear_instant_app_confirmation)) + }, + ) + } +} diff --git a/src/com/android/settings/spa/app/appsettings/AppDisableButton.kt b/src/com/android/settings/spa/app/appsettings/AppDisableButton.kt index ff3fbe3c10e..365da7c0036 100644 --- a/src/com/android/settings/spa/app/appsettings/AppDisableButton.kt +++ b/src/com/android/settings/spa/app/appsettings/AppDisableButton.kt @@ -55,7 +55,7 @@ class AppDisableButton( fun getActionButton(packageInfo: PackageInfo): ActionButton? { val app = packageInfo.applicationInfo - if (!app.hasFlag(ApplicationInfo.FLAG_SYSTEM)) return null + if (!app.isSystemApp) return null return when { app.enabled && !app.isDisabledUntilUsed -> { diff --git a/src/com/android/settings/spa/app/appsettings/AppInstallButton.kt b/src/com/android/settings/spa/app/appsettings/AppInstallButton.kt new file mode 100644 index 00000000000..94290e6a2ad --- /dev/null +++ b/src/com/android/settings/spa/app/appsettings/AppInstallButton.kt @@ -0,0 +1,46 @@ +/* + * 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.appsettings + +import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.FileDownload +import com.android.settings.R +import com.android.settings.applications.AppStoreUtil +import com.android.settingslib.spa.widget.button.ActionButton +import com.android.settingslib.spaprivileged.model.app.userHandle + +class AppInstallButton(private val packageInfoPresenter: PackageInfoPresenter) { + private val context = packageInfoPresenter.context + + fun getActionButton(packageInfo: PackageInfo): ActionButton? { + val app = packageInfo.applicationInfo + if (!app.isInstantApp) return null + + return AppStoreUtil.getAppStoreLink(packageInfoPresenter.contextAsUser, app.packageName) + ?.let { intent -> installButton(intent, app) } + } + + private fun installButton(intent: Intent, app: ApplicationInfo) = ActionButton( + text = context.getString(R.string.install_text), + imageVector = Icons.Outlined.FileDownload, + ) { + context.startActivityAsUser(intent, app.userHandle) + } +} diff --git a/src/com/android/settings/spa/app/appsettings/AppUninstallButton.kt b/src/com/android/settings/spa/app/appsettings/AppUninstallButton.kt index 53b36b99d11..3458f1ddc5e 100644 --- a/src/com/android/settings/spa/app/appsettings/AppUninstallButton.kt +++ b/src/com/android/settings/spa/app/appsettings/AppUninstallButton.kt @@ -46,7 +46,7 @@ class AppUninstallButton(private val packageInfoPresenter: PackageInfoPresenter) fun getActionButton(packageInfo: PackageInfo): ActionButton? { val app = packageInfo.applicationInfo - if (app.hasFlag(ApplicationInfo.FLAG_SYSTEM)) return null + if (app.isSystemApp || app.isInstantApp) return null return uninstallButton(app = app, enabled = isUninstallButtonEnabled(app)) } diff --git a/src/com/android/settings/spa/app/appsettings/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appsettings/PackageInfoPresenter.kt index cd672d3d7d1..b164d7c5064 100644 --- a/src/com/android/settings/spa/app/appsettings/PackageInfoPresenter.kt +++ b/src/com/android/settings/spa/app/appsettings/PackageInfoPresenter.kt @@ -48,9 +48,8 @@ class PackageInfoPresenter( private val coroutineScope: CoroutineScope, ) { private val metricsFeatureProvider = FeatureFactory.getFactory(context).metricsFeatureProvider - val packageManagerAsUser: PackageManager by lazy { - context.createContextAsUser(UserHandle.of(userId), 0).packageManager - } + val contextAsUser by lazy { context.createContextAsUser(UserHandle.of(userId), 0) } + val packageManagerAsUser: PackageManager by lazy { contextAsUser.packageManager } private val _flow: MutableStateFlow = MutableStateFlow(null) val flow: StateFlow = _flow @@ -103,6 +102,15 @@ class PackageInfoPresenter( } } + /** Clears this instant app. */ + fun clearInstantApp() { + logAction(SettingsEnums.ACTION_SETTINGS_CLEAR_INSTANT_APP) + coroutineScope.launch(Dispatchers.IO) { + packageManagerAsUser.deletePackageAsUser(packageName, null, 0, userId) + notifyChange() + } + } + /** Force stops this package. */ fun forceStop() { logAction(SettingsEnums.ACTION_APP_FORCE_STOP)