diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 07d2549a614e006e9ef8667dbda71e28d08f8186..1ae05312f0f19181f26102f0fb6eb61345cd3b68 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -114,6 +114,7 @@ import com.android.settings.password.ChooseLockSettingsHelper; 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; @@ -1254,4 +1255,19 @@ public final class Utils extends com.android.settingslib.Utils { } return input; } + + /** + * 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 protectedPackageNames = Arrays.asList(context.getResources() + .getStringArray(com.android.internal.R.array + .config_biometric_protected_package_names)); + return protectedPackageNames != null && protectedPackageNames.contains(packageName); + } } diff --git a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java index 1b270d63b4dd3e30a7935dc1f142cea5d4cdd81a..69f23fe5648c063b020580fa9c81c5cae9843e3b 100644 --- a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java @@ -52,6 +52,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; @@ -249,13 +250,21 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp } else { 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)); } @@ -303,13 +312,28 @@ 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); - AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)); + requireAuthAndExecute(() -> { + mMetricsFeatureProvider.action(mActivity, + SettingsEnums.ACTION_SETTINGS_DISABLE_APP); + AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)); + }); break; case ButtonActionDialogFragment.DialogType.SPECIAL_DISABLE: mMetricsFeatureProvider.action(mActivity, @@ -317,7 +341,9 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp uninstallPkg(mAppEntry.info.packageName, false, true); break; case ButtonActionDialogFragment.DialogType.FORCE_STOP: - forceStopPackage(mAppEntry.info.packageName); + requireAuthAndExecute(() -> { + forceStopPackage(mAppEntry.info.packageName); + }); break; } } @@ -547,16 +573,18 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp @VisibleForTesting void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) { - 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); - mDisableAfterUninstall = andDisable; + 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); + mDisableAfterUninstall = andDisable; + }); } @VisibleForTesting diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index e1e58513a7694b7b3ffb5046da1ec8fc539d977e..ed603ed741f847f24bbb23091928f420acb75b7b 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -431,7 +431,8 @@ public class AppInfoDashboardFragment extends DashboardFragment } } - private static void showLockScreen(Context context, Runnable successRunnable) { + /** Shows the lock screen if the keyguard is secured. */ + public static void showLockScreen(Context context, Runnable successRunnable) { final KeyguardManager keyguardManager = context.getSystemService( KeyguardManager.class); diff --git a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java index 253ae88e4b3d44109b490a6d743068dff964d229..79e99fed4e5f348c1d6b137867f34509b6aedb4a 100644 --- a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java +++ b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java @@ -122,7 +122,7 @@ public class NotificationAccessConfirmationActivity extends Activity NLSIntent, /* flags */ 0, mUserId); boolean hasNLSIntentFilter = false; for (ResolveInfo service : matchedServiceList) { - if (service.serviceInfo.packageName.equals(mComponentName.getPackageName())) { + if (service.serviceInfo.getComponentName().equals(mComponentName)) { if (!requiredPermission.equals(service.serviceInfo.permission)) { Slog.e(LOG_TAG, "Service " + mComponentName + " lacks permission " + requiredPermission); @@ -156,7 +156,7 @@ public class NotificationAccessConfirmationActivity extends Activity .installContent(p); // Consistent with the permission dialog // Used instead of p.mCancelable as that is only honored for AlertDialog - getWindow().setCloseOnTouchOutside(false); + getWindow().setCloseOnTouchOutside(false); } private void onAllow() { diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java index 9a65dc8829c4f9ec58ffddb6650dfe66b24e9396..91c5e7bf0fd577018f22404fd96abcff63fad3bf 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java @@ -81,6 +81,7 @@ import org.robolectric.util.ReflectionHelpers; import java.util.Set; +@Config(shadows = {ShadowUtils.class}) @RunWith(RobolectricTestRunner.class) public class AppButtonsPreferenceControllerTest { @@ -166,6 +167,7 @@ public class AppButtonsPreferenceControllerTest { @After public void tearDown() { ShadowAppUtils.reset(); + ShadowUtils.reset(); } @Test diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java index 5f8c434fc9fdb5d216b770343013d6d098dfdfd5..1dd381f35707720c51927b2189ad532ae62b7fc0 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java @@ -50,6 +50,7 @@ public class ShadowUtils { private static ArraySet sResultLinks = new ArraySet<>(); private static boolean sIsBatteryPresent; private static boolean sIsMultipleBiometricsSupported; + private static boolean sIsProtectedPackage; @Implementation protected static int enforceSameOwner(Context context, int userId) { @@ -82,6 +83,7 @@ public class ShadowUtils { sResultLinks = new ArraySet<>(); sIsBatteryPresent = true; sIsMultipleBiometricsSupported = false; + sIsProtectedPackage = false; } public static void setIsDemoUser(boolean isDemoUser) { @@ -188,4 +190,13 @@ public class ShadowUtils { public static void setIsMultipleBiometricsSupported(boolean isMultipleBiometricsSupported) { sIsMultipleBiometricsSupported = isMultipleBiometricsSupported; } + + @Implementation + protected static boolean isProtectedPackage(Context context, String packageName) { + return sIsProtectedPackage; + } + + public static void setIsProtectedPackage(boolean isProtectedPackage) { + sIsProtectedPackage = isProtectedPackage; + } }