Merge "[SPA] Add biometric authentication for package modification" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
6b98c4e74b
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user