diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 2a57577bb69..417ac0faeb5 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -107,6 +107,7 @@ import com.android.internal.app.UnlaunchableAppActivity; import com.android.internal.util.ArrayUtils; import com.android.internal.util.UserIcons; import com.android.internal.widget.LockPatternUtils; +import com.android.settings.enterprise.DevicePolicyManagerWrapper; import com.android.settings.password.FingerprintManagerWrapper; import com.android.settings.password.IFingerprintManager; @@ -1279,6 +1280,28 @@ public final class Utils extends com.android.settingslib.Utils { return isVolumeValid(volume) ? volume : null; } + /** + * Return {@code true} if the supplied package is device owner or profile owner of at + * least one user. + * @param userManager used to get profile owner app for each user + * @param devicePolicyManager used to check whether it is device owner app + * @param packageName package to check about + */ + public static boolean isProfileOrDeviceOwner(UserManager userManager, + DevicePolicyManagerWrapper devicePolicyManager, String packageName) { + List userInfos = userManager.getUsers(); + if (devicePolicyManager.isDeviceOwnerAppOnAnyUser(packageName)) { + return true; + } + for (int i = 0, size = userInfos.size(); i < size; i++) { + ComponentName cn = devicePolicyManager.getProfileOwnerAsUser(userInfos.get(i).id); + 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/AppInfoBase.java b/src/com/android/settings/applications/AppInfoBase.java index 4af9bc656ce..a5daee26564 100644 --- a/src/com/android/settings/applications/AppInfoBase.java +++ b/src/com/android/settings/applications/AppInfoBase.java @@ -43,6 +43,8 @@ import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.enterprise.DevicePolicyManagerWrapper; +import com.android.settings.enterprise.DevicePolicyManagerWrapperImpl; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.applications.ApplicationsState; @@ -73,7 +75,7 @@ public abstract class AppInfoBase extends SettingsPreferenceFragment protected String mPackageName; protected IUsbManager mUsbManager; - protected DevicePolicyManager mDpm; + protected DevicePolicyManagerWrapper mDpm; protected UserManager mUserManager; protected PackageManager mPm; @@ -92,7 +94,8 @@ public abstract class AppInfoBase extends SettingsPreferenceFragment .getApplicationFeatureProvider(activity); mState = ApplicationsState.getInstance(activity.getApplication()); mSession = mState.newSession(this); - mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); + mDpm = new DevicePolicyManagerWrapperImpl( + (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE)); mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE); mPm = activity.getPackageManager(); IBinder b = ServiceManager.getService(Context.USB_SERVICE); diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java index e8a4d9d4e09..5421586bfd1 100755 --- a/src/com/android/settings/applications/InstalledAppDetails.java +++ b/src/com/android/settings/applications/InstalledAppDetails.java @@ -274,7 +274,7 @@ public class InstalledAppDetails extends AppInfoBase // We don't allow uninstalling DO/PO on *any* users, because if it's a system app, // "uninstall" is actually "downgrade to the system version + disable", and "downgrade" // will clear data on all users. - if (isProfileOrDeviceOwner(mPackageInfo.packageName)) { + if (Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mPackageInfo.packageName)) { enabled = false; } @@ -349,23 +349,6 @@ public class InstalledAppDetails extends AppInfoBase return enabled; } - /** Returns if the supplied package is device owner or profile owner of at least one user */ - private boolean isProfileOrDeviceOwner(String packageName) { - List userInfos = mUserManager.getUsers(); - DevicePolicyManager dpm = (DevicePolicyManager) - getContext().getSystemService(Context.DEVICE_POLICY_SERVICE); - if (dpm.isDeviceOwnerAppOnAnyUser(packageName)) { - return true; - } - for (UserInfo userInfo : userInfos) { - ComponentName cn = dpm.getProfileOwnerAsUser(userInfo.id); - if (cn != null && cn.getPackageName().equals(packageName)) { - return true; - } - } - return false; - } - /** Called when the activity is first created. */ @Override public void onCreate(Bundle icicle) { diff --git a/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java b/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java index 1647aa58a4f..b889cfdd2e5 100644 --- a/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java +++ b/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java @@ -381,7 +381,7 @@ public class AppButtonsPreferenceController extends AbstractPreferenceController // We don't allow uninstalling DO/PO on *any* users, because if it's a system app, // "uninstall" is actually "downgrade to the system version + disable", and "downgrade" // will clear data on all users. - if (isProfileOrDeviceOwner(mPackageInfo.packageName)) { + if (Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mPackageInfo.packageName)) { enabled = false; } @@ -581,21 +581,6 @@ public class AppButtonsPreferenceController extends AbstractPreferenceController || (mUserManager.isSplitSystemUser() && userCount == 2); } - /** Returns if the supplied package is device owner or profile owner of at least one user */ - private boolean isProfileOrDeviceOwner(String packageName) { - List userInfos = mUserManager.getUsers(); - if (mDpm.isDeviceOwnerAppOnAnyUser(packageName)) { - return true; - } - for (int i = 0, size = userInfos.size(); i < size; i++) { - ComponentName cn = mDpm.getProfileOwnerAsUser(userInfos.get(i).id); - if (cn != null && cn.getPackageName().equals(packageName)) { - return true; - } - } - return false; - } - private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { diff --git a/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java b/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java index 89089e593ce..4d1cf77c2eb 100644 --- a/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java @@ -15,17 +15,22 @@ package com.android.settings.fuelgauge; import android.app.AppOpsManager; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Build; +import android.os.UserManager; import android.support.annotation.VisibleForTesting; import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.Preference; import android.util.Log; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.enterprise.DevicePolicyManagerWrapper; +import com.android.settings.enterprise.DevicePolicyManagerWrapperImpl; import com.android.settingslib.core.AbstractPreferenceController; /** @@ -39,14 +44,20 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo private final PackageManager mPackageManager; private final AppOpsManager mAppOpsManager; + private final UserManager mUserManager; private final String[] mPackages; private final int mUid; + @VisibleForTesting + DevicePolicyManagerWrapper mDpm; private String mTargetPackage; public BackgroundActivityPreferenceController(Context context, int uid) { super(context); mPackageManager = context.getPackageManager(); + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mDpm = new DevicePolicyManagerWrapperImpl( + (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE)); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mUid = uid; mPackages = mPackageManager.getPackagesForUid(mUid); @@ -56,12 +67,15 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo public void updateState(Preference preference) { final int mode = mAppOpsManager .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage); - if (mode == AppOpsManager.MODE_ERRORED) { - preference.setEnabled(false); - } else { + // Set checked or not before we may set it disabled + if (mode != AppOpsManager.MODE_ERRORED) { final boolean checked = mode != AppOpsManager.MODE_IGNORED; ((SwitchPreference) preference).setChecked(checked); } + if (mode == AppOpsManager.MODE_ERRORED + || Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mTargetPackage)) { + preference.setEnabled(false); + } updateSummary(preference); } diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java index d85464d1e08..33ead1fd4d0 100644 --- a/tests/robotests/src/com/android/settings/UtilsTest.java +++ b/tests/robotests/src/com/android/settings/UtilsTest.java @@ -8,14 +8,17 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; +import android.content.pm.UserInfo; import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.wifi.WifiManager; import android.os.Bundle; +import android.os.UserManager; import android.os.storage.DiskInfo; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; @@ -23,6 +26,7 @@ import android.text.SpannableStringBuilder; import android.text.format.DateUtils; import android.text.style.TtsSpan; +import com.android.settings.enterprise.DevicePolicyManagerWrapper; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; @@ -34,12 +38,15 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class UtilsTest { private static final String TIME_DESCRIPTION = "1 day 20 hours 30 minutes"; + private static final String PACKAGE_NAME = "com.android.app"; private Context mContext; @Mock private WifiManager wifiManager; @@ -47,6 +54,10 @@ public class UtilsTest { private Network network; @Mock private ConnectivityManager connectivityManager; + @Mock + private DevicePolicyManagerWrapper mDevicePolicyManager; + @Mock + private UserManager mUserManager; @Before public void setUp() { @@ -194,4 +205,25 @@ public class UtilsTest { assertThat(Utils.getInstallationStatus(info)).isEqualTo(R.string.disabled); } + + @Test + public void testIsProfileOrDeviceOwner_deviceOwnerApp_returnTrue() { + when(mDevicePolicyManager.isDeviceOwnerAppOnAnyUser(PACKAGE_NAME)).thenReturn(true); + + assertThat(Utils.isProfileOrDeviceOwner(mUserManager, mDevicePolicyManager, + PACKAGE_NAME)).isTrue(); + } + + @Test + public void testIsProfileOrDeviceOwner_profileOwnerApp_returnTrue() { + final List userInfos = new ArrayList<>(); + userInfos.add(new UserInfo()); + + when(mUserManager.getUsers()).thenReturn(userInfos); + when(mDevicePolicyManager.getProfileOwnerAsUser(userInfos.get(0).id)).thenReturn( + new ComponentName(PACKAGE_NAME, "")); + + assertThat(Utils.isProfileOrDeviceOwner(mUserManager, mDevicePolicyManager, + PACKAGE_NAME)).isTrue(); + } } diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java index 1de7c9f3a4b..deef5e0dd1f 100644 --- a/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java +++ b/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java @@ -45,6 +45,7 @@ import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.applications.instantapps.InstantAppButtonsController; import com.android.settings.applications.instantapps.InstantAppButtonsController.ShowDialogDelegate; +import com.android.settings.enterprise.DevicePolicyManagerWrapper; import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settingslib.Utils; @@ -103,7 +104,7 @@ public final class InstalledAppDetailsTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private SettingsActivity mActivity; @Mock - private DevicePolicyManager mDevicePolicyManager; + private DevicePolicyManagerWrapper mDevicePolicyManager; @Mock private BatterySipper mBatterySipper; @Mock diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java index 4f489451ac6..91f4a2b606e 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java @@ -17,14 +17,17 @@ package com.android.settings.fuelgauge; import android.app.AppOpsManager; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Build; +import android.os.UserManager; import android.support.v14.preference.SwitchPreference; import com.android.settings.R; import com.android.settings.TestConfig; +import com.android.settings.enterprise.DevicePolicyManagerWrapper; import org.junit.Before; import org.junit.Test; @@ -62,6 +65,12 @@ public class BackgroundActivityPreferenceControllerTest { private ApplicationInfo mHighApplicationInfo; @Mock private ApplicationInfo mLowApplicationInfo; + @Mock + private UserManager mUserManager; + @Mock + private DevicePolicyManager mDevicePolicyManager; + @Mock + private DevicePolicyManagerWrapper mDevicePolicyManagerWrapper; private BackgroundActivityPreferenceController mController; private SwitchPreference mPreference; private Context mShadowContext; @@ -73,6 +82,9 @@ public class BackgroundActivityPreferenceControllerTest { mShadowContext = RuntimeEnvironment.application; when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager); + when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn( + mDevicePolicyManager); when(mPackageManager.getPackagesForUid(UID_NORMAL)).thenReturn(PACKAGES_NORMAL); when(mPackageManager.getPackagesForUid(UID_SPECIAL)).thenReturn(PACKAGES_SPECIAL); @@ -86,6 +98,7 @@ public class BackgroundActivityPreferenceControllerTest { mPreference = new SwitchPreference(mShadowContext); mController = spy(new BackgroundActivityPreferenceController(mContext, UID_NORMAL)); mController.isAvailable(); + mController.mDpm = mDevicePolicyManagerWrapper; } @Test @@ -181,6 +194,7 @@ public class BackgroundActivityPreferenceControllerTest { @Test public void testMultiplePackages_ReturnStatusForTargetPackage() { mController = new BackgroundActivityPreferenceController(mContext, UID_SPECIAL); + mController.mDpm = mDevicePolicyManagerWrapper; when(mAppOpsManager .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_SPECIAL, LOW_SDK_PACKAGE)) .thenReturn(AppOpsManager.MODE_ALLOWED);