Merge "Add install & clear app button for instant app"

This commit is contained in:
Chaohui Wang
2022-09-29 03:10:43 +00:00
committed by Android (Google) Code Review
6 changed files with 144 additions and 5 deletions

View File

@@ -33,8 +33,10 @@ fun AppButtons(packageInfoPresenter: PackageInfoPresenter) {
private class AppButtonsHolder(private val packageInfoPresenter: PackageInfoPresenter) { private class AppButtonsHolder(private val packageInfoPresenter: PackageInfoPresenter) {
private val appLaunchButton = AppLaunchButton(packageInfoPresenter) private val appLaunchButton = AppLaunchButton(packageInfoPresenter)
private val appInstallButton = AppInstallButton(packageInfoPresenter)
private val appDisableButton = AppDisableButton(packageInfoPresenter) private val appDisableButton = AppDisableButton(packageInfoPresenter)
private val appUninstallButton = AppUninstallButton(packageInfoPresenter) private val appUninstallButton = AppUninstallButton(packageInfoPresenter)
private val appClearButton = AppClearButton(packageInfoPresenter)
private val appForceStopButton = AppForceStopButton(packageInfoPresenter) private val appForceStopButton = AppForceStopButton(packageInfoPresenter)
@Composable @Composable
@@ -46,14 +48,17 @@ private class AppButtonsHolder(private val packageInfoPresenter: PackageInfoPres
private fun getActionButtons(packageInfo: PackageInfo): List<ActionButton> = listOfNotNull( private fun getActionButtons(packageInfo: PackageInfo): List<ActionButton> = listOfNotNull(
appLaunchButton.getActionButton(packageInfo), appLaunchButton.getActionButton(packageInfo),
appInstallButton.getActionButton(packageInfo),
appDisableButton.getActionButton(packageInfo), appDisableButton.getActionButton(packageInfo),
appUninstallButton.getActionButton(packageInfo), appUninstallButton.getActionButton(packageInfo),
appClearButton.getActionButton(packageInfo),
appForceStopButton.getActionButton(packageInfo), appForceStopButton.getActionButton(packageInfo),
) )
@Composable @Composable
fun Dialogs() { fun Dialogs() {
appDisableButton.DisableConfirmDialog() appDisableButton.DisableConfirmDialog()
appClearButton.ClearConfirmDialog()
appForceStopButton.ForceStopConfirmDialog() appForceStopButton.ForceStopConfirmDialog()
} }
} }

View File

@@ -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))
},
)
}
}

View File

@@ -55,7 +55,7 @@ class AppDisableButton(
fun getActionButton(packageInfo: PackageInfo): ActionButton? { fun getActionButton(packageInfo: PackageInfo): ActionButton? {
val app = packageInfo.applicationInfo val app = packageInfo.applicationInfo
if (!app.hasFlag(ApplicationInfo.FLAG_SYSTEM)) return null if (!app.isSystemApp) return null
return when { return when {
app.enabled && !app.isDisabledUntilUsed -> { app.enabled && !app.isDisabledUntilUsed -> {

View File

@@ -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)
}
}

View File

@@ -46,7 +46,7 @@ class AppUninstallButton(private val packageInfoPresenter: PackageInfoPresenter)
fun getActionButton(packageInfo: PackageInfo): ActionButton? { fun getActionButton(packageInfo: PackageInfo): ActionButton? {
val app = packageInfo.applicationInfo 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)) return uninstallButton(app = app, enabled = isUninstallButtonEnabled(app))
} }

View File

@@ -48,9 +48,8 @@ class PackageInfoPresenter(
private val coroutineScope: CoroutineScope, private val coroutineScope: CoroutineScope,
) { ) {
private val metricsFeatureProvider = FeatureFactory.getFactory(context).metricsFeatureProvider private val metricsFeatureProvider = FeatureFactory.getFactory(context).metricsFeatureProvider
val packageManagerAsUser: PackageManager by lazy { val contextAsUser by lazy { context.createContextAsUser(UserHandle.of(userId), 0) }
context.createContextAsUser(UserHandle.of(userId), 0).packageManager val packageManagerAsUser: PackageManager by lazy { contextAsUser.packageManager }
}
private val _flow: MutableStateFlow<PackageInfo?> = MutableStateFlow(null) private val _flow: MutableStateFlow<PackageInfo?> = MutableStateFlow(null)
val flow: StateFlow<PackageInfo?> = _flow val flow: StateFlow<PackageInfo?> = _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. */ /** Force stops this package. */
fun forceStop() { fun forceStop() {
logAction(SettingsEnums.ACTION_APP_FORCE_STOP) logAction(SettingsEnums.ACTION_APP_FORCE_STOP)