1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.spa.app.appinfo 18 19 import android.app.settings.SettingsEnums 20 import android.content.Intent 21 import android.content.pm.ApplicationInfo 22 import android.os.UserHandle 23 import android.os.UserManager 24 import androidx.compose.runtime.Composable 25 import androidx.compose.runtime.remember 26 import androidx.compose.ui.graphics.vector.ImageVector 27 import androidx.compose.ui.res.vectorResource 28 import androidx.lifecycle.compose.collectAsStateWithLifecycle 29 import com.android.settings.R 30 import com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminAdd 31 import com.android.settingslib.spa.widget.button.ActionButton 32 import com.android.settingslib.spaprivileged.model.app.isActiveAdmin 33 import com.android.settingslib.spaprivileged.model.app.userHandle 34 import kotlinx.coroutines.Dispatchers 35 import kotlinx.coroutines.flow.flow 36 import kotlinx.coroutines.flow.flowOn 37 38 class AppUninstallButton(private val packageInfoPresenter: PackageInfoPresenter) { 39 private val context = packageInfoPresenter.context 40 private val appButtonRepository = AppButtonRepository(context) 41 private val userManager = context.getSystemService(UserManager::class.java)!! 42 43 @Composable getActionButtonnull44 fun getActionButton(app: ApplicationInfo): ActionButton? { 45 if (app.isSystemApp || app.isInstantApp) return null 46 return uninstallButton(app) 47 } 48 49 @Composable uninstallButtonnull50 private fun uninstallButton(app: ApplicationInfo) = ActionButton( 51 text = if (isCloneApp(app)) context.getString(R.string.delete) else 52 context.getString(R.string.uninstall_text), 53 imageVector = ImageVector.vectorResource(R.drawable.ic_settings_delete), 54 enabled = remember(app) { 55 flow { 56 emit(appButtonRepository.isAllowUninstallOrArchive(context, app)) 57 }.flowOn(Dispatchers.Default) 58 }.collectAsStateWithLifecycle(false).value, <lambda>null59 ) { onUninstallClicked(app) } 60 onUninstallClickednull61 private fun onUninstallClicked(app: ApplicationInfo) { 62 if (appButtonRepository.isUninstallBlockedByAdmin(app)) { 63 return 64 } else if (app.isActiveAdmin(context)) { 65 val uninstallDaIntent = Intent(context, DeviceAdminAdd::class.java) 66 uninstallDaIntent.putExtra(DeviceAdminAdd.EXTRA_DEVICE_ADMIN_PACKAGE_NAME, 67 app.packageName) 68 packageInfoPresenter.logAction( 69 SettingsEnums.ACTION_SETTINGS_UNINSTALL_DEVICE_ADMIN) 70 context.startActivityAsUser(uninstallDaIntent, app.userHandle) 71 return 72 } 73 packageInfoPresenter.startUninstallActivity() 74 } 75 isCloneAppnull76 private fun isCloneApp(app: ApplicationInfo): Boolean { 77 val userInfo = userManager.getUserInfo(UserHandle.getUserId(app.uid)) 78 return userInfo != null && userInfo.isCloneProfile 79 } 80 } 81