From 341f99597159a4ab6ff2cbb94accbc7697889802 Mon Sep 17 00:00:00 2001 From: Alex Johnston Date: Wed, 26 Feb 2020 15:54:11 +0000 Subject: [PATCH] DPC can be uninstalled in personal profile in New COPE * For an organization-owned device, the DPC should be able to be uninstalled in the personal profile. Previously, the observed behaviour was that the uninstall button in the App Info Screen was being greyed out. * This was because the previous logic did not allow for uninstalling any app which has a profile owner or device owner on *any* user. * This CL updates this logic, such that, for non-system apps uninstalling is blocked only if the app has a profile owner or device owner for the current calling user. Bug: 149381804 Test: Manual testing atest com.android.settings.applications.appinfo.AppButtonsPreferenceControllerTest Change-Id: Ifaf03daa41724dbbd869c7e1371a77cc39d15ac7 --- src/com/android/settings/Utils.java | 21 +++++++++++ .../AppButtonsPreferenceController.java | 16 ++++++--- .../AppButtonsPreferenceControllerTest.java | 36 ++++++++++++++++--- 3 files changed, 65 insertions(+), 8 deletions(-) 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());