diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 315cba12b2c..e8eb8baadb0 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -887,6 +887,27 @@ public final class Utils extends com.android.settingslib.Utils { return false; } + /** + * Return {@code true} if the supplied package is the device owner or profile owner of a + * given user. + * + * @param devicePolicyManager used to check whether it is device owner and profile owner app + * @param packageName package to check about + * @param userId the if of the relevant user + */ + public static boolean isProfileOrDeviceOwner(DevicePolicyManager devicePolicyManager, + String packageName, int userId) { + if ((devicePolicyManager.getDeviceOwnerUserId() == userId) + && devicePolicyManager.isDeviceOwnerApp(packageName)) { + return true; + } + final ComponentName cn = devicePolicyManager.getProfileOwnerAsUser(userId); + if (cn != null && cn.getPackageName().equals(packageName)) { + return true; + } + return false; + } + /** * Return the resource id to represent the install status for an app */ diff --git a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java index 1b14402c365..19627ffcb43 100644 --- a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java @@ -25,8 +25,8 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.om.OverlayManager; import android.content.om.OverlayInfo; +import android.content.om.OverlayManager; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -393,11 +393,19 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp enabled = false; } - // We don't allow uninstalling DO/PO on *any* users, because if it's a system app, + // We don't allow uninstalling DO/PO on *any* users if it's a system app, because // "uninstall" is actually "downgrade to the system version + disable", and "downgrade" // will clear data on all users. - if (Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mPackageInfo.packageName)) { - enabled = false; + if (Utils.isSystemPackage(mActivity.getResources(), mPm, mPackageInfo)) { + if (Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mPackageInfo.packageName)) { + enabled = false; + } + // We allow uninstalling if the calling user is not a DO/PO and if it's not a system app, + // because this will not have device-wide consequences. + } else { + if (Utils.isProfileOrDeviceOwner(mDpm, mPackageInfo.packageName, mUserId)) { + enabled = false; + } } // Don't allow uninstalling the device provisioning package. 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 ca2a8002ada..044b6982424 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java @@ -36,7 +36,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; -import android.app.Application; import android.app.admin.DevicePolicyManager; import android.app.settings.SettingsEnums; import android.content.Context; @@ -51,8 +50,6 @@ import android.os.UserManager; import android.util.ArraySet; import android.view.View; -import androidx.preference.PreferenceScreen; - import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.core.InstrumentedPreferenceFragment; @@ -277,7 +274,8 @@ public class AppButtonsPreferenceControllerTest { } @Test - public void updateUninstallButton_isProfileOrDeviceOwner_setButtonDisable() { + public void updateUninstallButton_isSystemAndIsProfileOrDeviceOwner_setButtonDisable() { + mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM; doReturn(true).when(mDpm).isDeviceOwnerAppOnAnyUser(anyString()); mController.updateUninstallButton(); @@ -285,6 +283,36 @@ public class AppButtonsPreferenceControllerTest { verify(mButtonPrefs).setButton2Enabled(false); } + @Test + public void updateUninstallButton_isSystemAndIsNotProfileOrDeviceOwner_setButtonEnabled() { + mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM; + doReturn(false).when(mDpm).isDeviceOwnerAppOnAnyUser(anyString()); + + mController.updateUninstallButton(); + + verify(mButtonPrefs).setButton2Enabled(true); + } + + @Test + public void updateUninstallButton_isNotSystemAndIsProfileOrDeviceOwner_setButtonDisable() { + doReturn(0).when(mDpm).getDeviceOwnerUserId(); + doReturn(true).when(mDpm).isDeviceOwnerApp(anyString()); + + mController.updateUninstallButton(); + + verify(mButtonPrefs).setButton2Enabled(false); + } + + @Test + public void updateUninstallButton_isNotSystemAndIsNotProfileOrDeviceOwner_setButtonEnabled() { + doReturn(10).when(mDpm).getDeviceOwnerUserId(); + doReturn(false).when(mDpm).isDeviceOwnerApp(anyString()); + + mController.updateUninstallButton(); + + verify(mButtonPrefs).setButton2Enabled(true); + } + @Test public void updateUninstallButton_isDeviceProvisioningApp_setButtonDisable() { doReturn(true).when(mDpm).isDeviceOwnerAppOnAnyUser(anyString());