[SPA] Add biometric authentication for package modification

Add an extra step of Lock Screen for disabling, force-stopping or
uninstalling updates for protected packages

UI Change Details : https://drive.google.com/drive/folders/1w7gKTmCxQ_j-9GQnIpEfF5_gmQ27b8l_?resourcekey=0-brLdN8VfqVPGm2FMwfrmkQ&usp=drive_link
Bug: 352504490, 344865740
Test: atest AppButtonsPreferenceControllerTest PackageInfoPresenterTest
Flag: EXEMPT High Security Bug
Change-Id: I0c494e307b02229d751de118abcc89e4e61a6861
This commit is contained in:
Shraddha Basantwani
2024-12-02 09:36:05 +00:00
parent 4084b5603e
commit 32e388ad31
6 changed files with 218 additions and 47 deletions

View File

@@ -131,6 +131,7 @@ import com.android.settings.password.ConfirmDeviceCredentialActivity;
import com.android.settingslib.widget.ActionBarShadowController;
import com.android.settingslib.widget.AdaptiveIcon;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
@@ -1600,4 +1601,19 @@ public final class Utils extends com.android.settingslib.Utils {
pm.setComponentEnabledSetting(componentName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
/**
* Returns {@code true} if the supplied package is a protected package. Otherwise, returns
* {@code false}.
*
* @param context the context
* @param packageName the package name
*/
public static boolean isProtectedPackage(
@NonNull Context context, @NonNull String packageName) {
final List<String> protectedPackageNames = Arrays.asList(context.getResources()
.getStringArray(com.android.internal.R.array
.config_biometric_protected_package_names));
return protectedPackageNames != null && protectedPackageNames.contains(packageName);
}
}

View File

@@ -53,6 +53,7 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminAdd;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.InstrumentedPreferenceFragment;
@@ -240,13 +241,21 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
} else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
showDialogInner(ButtonActionDialogFragment.DialogType.DISABLE);
} else if (mAppEntry.info.enabled) {
requireAuthAndExecute(() -> {
mMetricsFeatureProvider.action(
mActivity,
SettingsEnums.ACTION_SETTINGS_DISABLE_APP,
getPackageNameForMetric());
AsyncTask.execute(new DisableChangerRunnable(mPm,
mAppEntry.info.packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT));
});
} else {
mMetricsFeatureProvider.action(
mActivity,
mAppEntry.info.enabled
? SettingsEnums.ACTION_SETTINGS_DISABLE_APP
: SettingsEnums.ACTION_SETTINGS_ENABLE_APP,
getPackageNameForMetric());
SettingsEnums.ACTION_SETTINGS_ENABLE_APP,
getPackageNameForMetric());
AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT));
}
@@ -289,17 +298,34 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
}
}
/**
* Runs the given action with restricted lock authentication if it is a protected package.
*
* @param action The action to run.
*/
private void requireAuthAndExecute(Runnable action) {
if (Utils.isProtectedPackage(mContext, mAppEntry.info.packageName)) {
AppInfoDashboardFragment.showLockScreen(mContext, () -> action.run());
} else {
action.run();
}
}
public void handleDialogClick(int id) {
switch (id) {
case ButtonActionDialogFragment.DialogType.DISABLE:
mMetricsFeatureProvider.action(mActivity,
SettingsEnums.ACTION_SETTINGS_DISABLE_APP,
getPackageNameForMetric());
AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER));
requireAuthAndExecute(() -> {
mMetricsFeatureProvider.action(mActivity,
SettingsEnums.ACTION_SETTINGS_DISABLE_APP,
getPackageNameForMetric());
AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER));
});
break;
case ButtonActionDialogFragment.DialogType.FORCE_STOP:
forceStopPackage(mAppEntry.info.packageName);
requireAuthAndExecute(() -> {
forceStopPackage(mAppEntry.info.packageName);
});
break;
}
}
@@ -535,14 +561,16 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
@VisibleForTesting
void uninstallPkg(String packageName, boolean allUsers) {
stopListeningToPackageRemove();
// Create new intent to launch Uninstaller activity
Uri packageUri = Uri.parse("package:" + packageName);
Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
requireAuthAndExecute(() -> {
stopListeningToPackageRemove();
// Create new intent to launch Uninstaller activity
Uri packageUri = Uri.parse("package:" + packageName);
Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
mMetricsFeatureProvider.action(mActivity, SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP);
mFragment.startActivityForResult(uninstallIntent, mRequestUninstall);
mMetricsFeatureProvider.action(mActivity, SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP);
mFragment.startActivityForResult(uninstallIntent, mRequestUninstall);
});
}
@VisibleForTesting

View File

@@ -29,6 +29,8 @@ import android.os.UserHandle
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
import com.android.settings.Utils
import com.android.settings.applications.appinfo.AppInfoDashboardFragment
import com.android.settings.flags.FeatureFlags
import com.android.settings.flags.FeatureFlagsImpl
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
@@ -116,6 +118,16 @@ class PackageInfoPresenter(
private fun isForThisApp(intent: Intent) = packageName == intent.data?.schemeSpecificPart
private fun requireAuthAndExecute(action: () -> Unit) {
if (Utils.isProtectedPackage(context, packageName)) {
AppInfoDashboardFragment.showLockScreen(context) {
action()
}
} else {
action()
}
}
/** Enables this package. */
fun enable() {
logAction(SettingsEnums.ACTION_SETTINGS_ENABLE_APP)
@@ -129,17 +141,21 @@ class PackageInfoPresenter(
/** Disables this package. */
fun disable() {
logAction(SettingsEnums.ACTION_SETTINGS_DISABLE_APP)
coroutineScope.launch(Dispatchers.IO) {
userPackageManager.setApplicationEnabledSetting(
packageName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0
)
requireAuthAndExecute {
coroutineScope.launch(Dispatchers.IO) {
userPackageManager.setApplicationEnabledSetting(
packageName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0
)
}
}
}
/** Starts the uninstallation activity. */
fun startUninstallActivity(forAllUsers: Boolean = false) {
logAction(SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP)
context.startUninstallActivity(packageName, userHandle, forAllUsers)
requireAuthAndExecute {
context.startUninstallActivity(packageName, userHandle, forAllUsers)
}
}
/** Clears this instant app. */
@@ -153,17 +169,19 @@ class PackageInfoPresenter(
/** Force stops this package. */
fun forceStop() {
logAction(SettingsEnums.ACTION_APP_FORCE_STOP)
coroutineScope.launch(Dispatchers.Default) {
Log.d(TAG, "Stopping package $packageName")
if (android.app.Flags.appRestrictionsApi()) {
val uid = userPackageManager.getPackageUid(packageName, 0)
context.activityManager.noteAppRestrictionEnabled(
packageName, uid,
ActivityManager.RESTRICTION_LEVEL_FORCE_STOPPED, true,
ActivityManager.RESTRICTION_REASON_USER, "settings",
ActivityManager.RESTRICTION_SOURCE_USER, 0)
requireAuthAndExecute {
coroutineScope.launch(Dispatchers.Default) {
Log.d(TAG, "Stopping package $packageName")
if (android.app.Flags.appRestrictionsApi()) {
val uid = userPackageManager.getPackageUid(packageName, 0)
context.activityManager.noteAppRestrictionEnabled(
packageName, uid,
ActivityManager.RESTRICTION_LEVEL_FORCE_STOPPED, true,
ActivityManager.RESTRICTION_REASON_USER, "settings",
ActivityManager.RESTRICTION_SOURCE_USER, 0)
}
context.activityManager.forceStopPackageAsUser(packageName, userId)
}
context.activityManager.forceStopPackageAsUser(packageName, userId)
}
}