Send EXTRA_USER with DevicePolicy lock broadcasts
DeviceAdmins inside profiles may receive broadcasts referring either
to the parent profile or to themselves.
We need a way to differentiate that.
Same commit fixes a bug in DevicePolicyManagerTest where USER_SYSTEM
is returned twice in getProfiles() when called for a managed profile of
USER_SYSTEM. This does not happen in the real API.
Bug: 30185351
Bug: 31001762
Test: runtest -x services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
Change-Id: Iea2735357f4019b2b81b6784e7ea6aead63f2636
diff --git a/api/current.txt b/api/current.txt
index b1ba9c8..83b71f5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6024,10 +6024,14 @@
method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, java.lang.String);
method public void onLockTaskModeExiting(android.content.Context, android.content.Intent);
method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int);
- method public void onPasswordChanged(android.content.Context, android.content.Intent);
- method public void onPasswordExpiring(android.content.Context, android.content.Intent);
- method public void onPasswordFailed(android.content.Context, android.content.Intent);
- method public void onPasswordSucceeded(android.content.Context, android.content.Intent);
+ method public deprecated void onPasswordChanged(android.content.Context, android.content.Intent);
+ method public void onPasswordChanged(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public deprecated void onPasswordExpiring(android.content.Context, android.content.Intent);
+ method public void onPasswordExpiring(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public deprecated void onPasswordFailed(android.content.Context, android.content.Intent);
+ method public void onPasswordFailed(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public deprecated void onPasswordSucceeded(android.content.Context, android.content.Intent);
+ method public void onPasswordSucceeded(android.content.Context, android.content.Intent, android.os.UserHandle);
method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
method public deprecated void onReadyForUserInitialization(android.content.Context, android.content.Intent);
method public void onReceive(android.content.Context, android.content.Intent);
diff --git a/api/system-current.txt b/api/system-current.txt
index 92b437d..4538241 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6202,10 +6202,14 @@
method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, java.lang.String);
method public void onLockTaskModeExiting(android.content.Context, android.content.Intent);
method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int);
- method public void onPasswordChanged(android.content.Context, android.content.Intent);
- method public void onPasswordExpiring(android.content.Context, android.content.Intent);
- method public void onPasswordFailed(android.content.Context, android.content.Intent);
- method public void onPasswordSucceeded(android.content.Context, android.content.Intent);
+ method public deprecated void onPasswordChanged(android.content.Context, android.content.Intent);
+ method public void onPasswordChanged(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public deprecated void onPasswordExpiring(android.content.Context, android.content.Intent);
+ method public void onPasswordExpiring(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public deprecated void onPasswordFailed(android.content.Context, android.content.Intent);
+ method public void onPasswordFailed(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public deprecated void onPasswordSucceeded(android.content.Context, android.content.Intent);
+ method public void onPasswordSucceeded(android.content.Context, android.content.Intent, android.os.UserHandle);
method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
method public deprecated void onReadyForUserInitialization(android.content.Context, android.content.Intent);
method public void onReceive(android.content.Context, android.content.Intent);
diff --git a/api/test-current.txt b/api/test-current.txt
index 9b8e87c..54b2830 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6041,10 +6041,14 @@
method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, java.lang.String);
method public void onLockTaskModeExiting(android.content.Context, android.content.Intent);
method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int);
- method public void onPasswordChanged(android.content.Context, android.content.Intent);
- method public void onPasswordExpiring(android.content.Context, android.content.Intent);
- method public void onPasswordFailed(android.content.Context, android.content.Intent);
- method public void onPasswordSucceeded(android.content.Context, android.content.Intent);
+ method public deprecated void onPasswordChanged(android.content.Context, android.content.Intent);
+ method public void onPasswordChanged(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public deprecated void onPasswordExpiring(android.content.Context, android.content.Intent);
+ method public void onPasswordExpiring(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public deprecated void onPasswordFailed(android.content.Context, android.content.Intent);
+ method public void onPasswordFailed(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public deprecated void onPasswordSucceeded(android.content.Context, android.content.Intent);
+ method public void onPasswordSucceeded(android.content.Context, android.content.Intent, android.os.UserHandle);
method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
method public deprecated void onReadyForUserInitialization(android.content.Context, android.content.Intent);
method public void onReceive(android.content.Context, android.content.Intent);
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index aae80ed..f2a8777 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -28,6 +28,7 @@
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Process;
import android.os.UserHandle;
import android.security.KeyChain;
@@ -123,7 +124,7 @@
* of the new password with {@link DevicePolicyManager#isActivePasswordSufficient()
* DevicePolicyManager.isActivePasswordSufficient()}.
* You will generally
- * handle this in {@link DeviceAdminReceiver#onPasswordChanged}.
+ * handle this in {@link DeviceAdminReceiver#onPasswordChanged(Context, Intent, UserHandle)}.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to receive
@@ -139,7 +140,7 @@
* number of failed password attempts there have been with
* {@link DevicePolicyManager#getCurrentFailedPasswordAttempts
* DevicePolicyManager.getCurrentFailedPasswordAttempts()}. You will generally
- * handle this in {@link DeviceAdminReceiver#onPasswordFailed}.
+ * handle this in {@link DeviceAdminReceiver#onPasswordFailed(Context, Intent, UserHandle)}.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
@@ -152,7 +153,7 @@
/**
* Action sent to a device administrator when the user has successfully entered their device
* or profile challenge password, after failing one or more times. You will generally
- * handle this in {@link DeviceAdminReceiver#onPasswordSucceeded}.
+ * handle this in {@link DeviceAdminReceiver#onPasswordSucceeded(Context, Intent, UserHandle)}.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
@@ -165,7 +166,7 @@
/**
* Action periodically sent to a device administrator when the device or profile challenge
* password is expiring. You will generally
- * handle this in {@link DeviceAdminReceiver#onPasswordExpiring}.
+ * handle this in {@link DeviceAdminReceiver#onPasswordExpiring(Context, Intent, UserHandle)}.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD} to receive
@@ -497,33 +498,90 @@
* to retrieve the active password characteristics.
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
+ *
+ * @deprecated From {@link android.os.Build.VERSION_CODES#O}, use
+ * {@link #onPasswordChanged(Context, Intent, UserHandle)} instead.
*/
+ @Deprecated
public void onPasswordChanged(Context context, Intent intent) {
}
/**
+ * Called after the user has changed their device or profile challenge password, as a result of
+ * receiving {@link #ACTION_PASSWORD_CHANGED}. At this point you
+ * can use {@link DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
+ * to retrieve the active password characteristics.
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ * @param user The user or profile for whom the password changed. To see whether this
+ * user is the current profile or a parent user, check for equality with
+ * {@link Process#myUserHandle}.
+ */
+ public void onPasswordChanged(Context context, Intent intent, UserHandle user) {
+ onPasswordChanged(context, intent);
+ }
+
+ /**
* Called after the user has failed at entering their device or profile challenge password,
* as a result of receiving {@link #ACTION_PASSWORD_FAILED}. At this point you can use
* {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()} to retrieve the number of
* failed password attempts.
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
+ *
+ * @deprecated From {@link android.os.Build.VERSION_CODES#O}, use
+ * {@link #onPasswordFailed(Context, Intent, UserHandle)} instead.
*/
+ @Deprecated
public void onPasswordFailed(Context context, Intent intent) {
}
/**
+ * Called after the user has failed at entering their device or profile challenge password,
+ * as a result of receiving {@link #ACTION_PASSWORD_FAILED}. At this point you can use
+ * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()} to retrieve the number of
+ * failed password attempts.
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ * @param user The user or profile for whom the password check failed. To see whether this
+ * user is the current profile or a parent user, check for equality with
+ * {@link Process#myUserHandle}.
+ */
+ public void onPasswordFailed(Context context, Intent intent, UserHandle user) {
+ onPasswordFailed(context, intent);
+ }
+
+ /**
* Called after the user has succeeded at entering their device or profile challenge password,
* as a result of receiving {@link #ACTION_PASSWORD_SUCCEEDED}. This will
* only be received the first time they succeed after having previously
* failed.
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
+ *
+ * @deprecated From {@link android.os.Build.VERSION_CODES#O}, use
+ * {@link #onPasswordSucceeded(Context, Intent, UserHandle)} instead.
*/
+ @Deprecated
public void onPasswordSucceeded(Context context, Intent intent) {
}
/**
+ * Called after the user has succeeded at entering their device or profile challenge password,
+ * as a result of receiving {@link #ACTION_PASSWORD_SUCCEEDED}. This will
+ * only be received the first time they succeed after having previously
+ * failed.
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ * @param user The user of profile for whom the password check succeeded. To see whether this
+ * user is the current profile or a parent user, check for equality with
+ * {@link Process#myUserHandle}.
+ */
+ public void onPasswordSucceeded(Context context, Intent intent, UserHandle user) {
+ onPasswordSucceeded(context, intent);
+ }
+
+ /**
* Called periodically when the device or profile challenge password is about to expire
* or has expired. It will typically be called at these times: on device boot, once per day
* before the password expires, and at the time when the password expires.
@@ -540,11 +598,40 @@
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
+ *
+ * @deprecated From {@link android.os.Build.VERSION_CODES#O}, use
+ * {@link #onPasswordExpiring(Context, Intent, UserHandle)} instead.
*/
+ @Deprecated
public void onPasswordExpiring(Context context, Intent intent) {
}
/**
+ * Called periodically when the device or profile challenge password is about to expire
+ * or has expired. It will typically be called at these times: on device boot, once per day
+ * before the password expires, and at the time when the password expires.
+ *
+ * <p>If the password is not updated by the user, this method will continue to be called
+ * once per day until the password is changed or the device admin disables password expiration.
+ *
+ * <p>The admin will typically post a notification requesting the user to change their password
+ * in response to this call. The actual password expiration time can be obtained by calling
+ * {@link DevicePolicyManager#getPasswordExpiration(ComponentName) }
+ *
+ * <p>The admin should be sure to take down any notifications it posted in response to this call
+ * when it receives {@link DeviceAdminReceiver#onPasswordChanged(Context, Intent, UserHandle) }.
+ *
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ * @param user The user or profile for whom the password is expiring. To see whether this
+ * user is the current profile or a parent user, check for equality with
+ * {@link Process#myUserHandle}.
+ */
+ public void onPasswordExpiring(Context context, Intent intent, UserHandle user) {
+ onPasswordExpiring(context, intent);
+ }
+
+ /**
* Called when provisioning of a managed profile or managed device has completed successfully.
*
* <p> As a prerequisite for the execution of this callback the {@link DeviceAdminReceiver} has
@@ -741,11 +828,11 @@
String action = intent.getAction();
if (ACTION_PASSWORD_CHANGED.equals(action)) {
- onPasswordChanged(context, intent);
+ onPasswordChanged(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
} else if (ACTION_PASSWORD_FAILED.equals(action)) {
- onPasswordFailed(context, intent);
+ onPasswordFailed(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
} else if (ACTION_PASSWORD_SUCCEEDED.equals(action)) {
- onPasswordSucceeded(context, intent);
+ onPasswordSucceeded(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
} else if (ACTION_DEVICE_ADMIN_ENABLED.equals(action)) {
onEnabled(context, intent);
} else if (ACTION_DEVICE_ADMIN_DISABLE_REQUESTED.equals(action)) {
@@ -757,7 +844,7 @@
} else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
onDisabled(context, intent);
} else if (ACTION_PASSWORD_EXPIRING.equals(action)) {
- onPasswordExpiring(context, intent);
+ onPasswordExpiring(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
} else if (ACTION_PROFILE_PROVISIONING_COMPLETE.equals(action)) {
onProfileProvisioningComplete(context, intent);
} else if (ACTION_CHOOSE_PRIVATE_KEY_ALIAS.equals(action)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e5c8d02..7538c95 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2213,15 +2213,13 @@
/**
* Send an update to all admins of a user that enforce a specified policy.
*/
- void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
+ void sendAdminCommandLocked(String action, int reqPolicy, int userHandle, Bundle adminExtras) {
final DevicePolicyData policy = getUserData(userHandle);
final int count = policy.mAdminList.size();
- if (count > 0) {
- for (int i = 0; i < count; i++) {
- final ActiveAdmin admin = policy.mAdminList.get(i);
- if (admin.info.usesPolicy(reqPolicy)) {
- sendAdminCommandLocked(admin, action);
- }
+ for (int i = 0; i < count; i++) {
+ final ActiveAdmin admin = policy.mAdminList.get(i);
+ if (admin.info.usesPolicy(reqPolicy)) {
+ sendAdminCommandLocked(admin, action, adminExtras, null);
}
}
}
@@ -2231,10 +2229,10 @@
* enforce a specified policy.
*/
private void sendAdminCommandToSelfAndProfilesLocked(String action, int reqPolicy,
- int userHandle) {
+ int userHandle, Bundle adminExtras) {
int[] profileIds = mUserManager.getProfileIdsWithDisabled(userHandle);
for (int profileId : profileIds) {
- sendAdminCommandLocked(action, reqPolicy, profileId);
+ sendAdminCommandLocked(action, reqPolicy, profileId, adminExtras);
}
}
@@ -2243,10 +2241,12 @@
*/
private void sendAdminCommandForLockscreenPoliciesLocked(
String action, int reqPolicy, int userHandle) {
+ final Bundle extras = new Bundle();
+ extras.putParcelable(Intent.EXTRA_USER, UserHandle.of(userHandle));
if (isSeparateProfileChallengeEnabled(userHandle)) {
- sendAdminCommandLocked(action, reqPolicy, userHandle);
+ sendAdminCommandLocked(action, reqPolicy, userHandle, extras);
} else {
- sendAdminCommandToSelfAndProfilesLocked(action, reqPolicy, userHandle);
+ sendAdminCommandToSelfAndProfilesLocked(action, reqPolicy, userHandle, extras);
}
}
@@ -2796,6 +2796,9 @@
}
private void handlePasswordExpirationNotification(int userHandle) {
+ final Bundle adminExtras = new Bundle();
+ adminExtras.putParcelable(Intent.EXTRA_USER, UserHandle.of(userHandle));
+
synchronized (this) {
final long now = System.currentTimeMillis();
@@ -2809,7 +2812,7 @@
&& now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS
&& admin.passwordExpirationDate > 0L) {
sendAdminCommandLocked(admin,
- DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
+ DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING, adminExtras, null);
}
}
setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d392459..c5e343e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -71,6 +71,7 @@
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -544,6 +545,83 @@
}
/**
+ * Test for: @{link DevicePolicyManager#setActivePasswordState}
+ *
+ * Validates that when the password for a user changes, the notification broadcast intent
+ * {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is sent to managed profile owners, in
+ * addition to ones in the original user.
+ */
+ public void testSetActivePasswordState_sendToProfiles() throws Exception {
+ mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);
+
+ final int MANAGED_PROFILE_USER_ID = 78;
+ final int MANAGED_PROFILE_ADMIN_UID =
+ UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
+
+ // Setup device owner.
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ mContext.packageName = admin1.getPackageName();
+ setupDeviceOwner();
+
+ // Add a managed profile belonging to the system user.
+ addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+
+ // Change the parent user's password.
+ dpm.reportPasswordChanged(UserHandle.USER_SYSTEM);
+
+ // Both the device owner and the managed profile owner should receive this broadcast.
+ final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
+ intent.setComponent(admin1);
+ intent.putExtra(Intent.EXTRA_USER, UserHandle.of(UserHandle.USER_SYSTEM));
+
+ verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+ MockUtils.checkIntent(intent),
+ MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
+ verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+ MockUtils.checkIntent(intent),
+ MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID));
+ }
+
+ /**
+ * Test for: @{link DevicePolicyManager#setActivePasswordState}
+ *
+ * Validates that when the password for a managed profile changes, the notification broadcast
+ * intent {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is only sent to the profile, not
+ * its parent.
+ */
+ public void testSetActivePasswordState_notSentToParent() throws Exception {
+ mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);
+
+ final int MANAGED_PROFILE_USER_ID = 78;
+ final int MANAGED_PROFILE_ADMIN_UID =
+ UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
+
+ // Setup device owner.
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ mContext.packageName = admin1.getPackageName();
+ doReturn(true).when(mContext.lockPatternUtils)
+ .isSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID);
+ setupDeviceOwner();
+
+ // Add a managed profile belonging to the system user.
+ addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+
+ // Change the profile's password.
+ dpm.reportPasswordChanged(MANAGED_PROFILE_USER_ID);
+
+ // Both the device owner and the managed profile owner should receive this broadcast.
+ final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
+ intent.setComponent(admin1);
+ intent.putExtra(Intent.EXTRA_USER, UserHandle.of(MANAGED_PROFILE_USER_ID));
+
+ verify(mContext.spiedContext, never()).sendBroadcastAsUser(
+ MockUtils.checkIntent(intent),
+ MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
+ verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+ MockUtils.checkIntent(intent),
+ MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID));
+ }
+ /**
* Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully.
*/
public void testSetDeviceOwner() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 65255d9..a1b6769 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -18,6 +18,7 @@
import android.accounts.Account;
import android.accounts.AccountManager;
+import android.app.AlarmManager;
import android.app.IActivityManager;
import android.app.NotificationManager;
import android.app.backup.IBackupManager;
@@ -276,6 +277,7 @@
public final MockContentResolver contentResolver;
public final TelephonyManager telephonyManager;
public final AccountManager accountManager;
+ public final AlarmManager alarmManager;
/** Note this is a partial mock, not a real mock. */
public final PackageManager packageManager;
@@ -319,6 +321,7 @@
settings = mock(SettingsForMock.class);
telephonyManager = mock(TelephonyManager.class);
accountManager = mock(AccountManager.class);
+ alarmManager = mock(AlarmManager.class);
// Package manager is huge, so we use a partial mock instead.
packageManager = spy(context.getPackageManager());
@@ -327,7 +330,8 @@
contentResolver = new MockContentResolver();
- // Add the system user
+ // Add the system user with a fake profile group already set up (this can happen in the real
+ // world if a managed profile is added and then removed).
systemUserDataDir =
addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY, UserHandle.USER_SYSTEM);
@@ -410,9 +414,9 @@
if (parent == null) {
return ret;
}
- ret.add(parent);
for (UserInfo ui : mUserInfos) {
- if (ui.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+ if (ui == parent
+ || ui.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
&& ui.profileGroupId == parent.profileGroupId) {
ret.add(ui);
}
@@ -463,6 +467,8 @@
@Override
public Object getSystemService(String name) {
switch (name) {
+ case Context.ALARM_SERVICE:
+ return alarmManager;
case Context.USER_SERVICE:
return userManager;
case Context.POWER_SERVICE: