Clean up on UserManagerService and DPMS

- Avoid the ART warning about 4.1 compatibility
- Avoid integer overflow in DPMS

Bug 27243525
Bug 27242859

Change-Id: I92af323287e348fbd0eff31e6cf9823be8e41024
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 117c663..788c44a 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -840,7 +840,7 @@
     /**
      * See {@link UserManagerInternal#setDevicePolicyUserRestrictions(int, Bundle, Bundle)}
      */
-    void setDevicePolicyUserRestrictions(int userId, @NonNull Bundle local,
+    void setDevicePolicyUserRestrictionsInner(int userId, @NonNull Bundle local,
             @Nullable Bundle global) {
         Preconditions.checkNotNull(local);
         boolean globalChanged = false;
@@ -2854,7 +2854,7 @@
         @Override
         public void setDevicePolicyUserRestrictions(int userId, @NonNull Bundle localRestrictions,
                 @Nullable Bundle globalRestrictions) {
-            UserManagerService.this.setDevicePolicyUserRestrictions(userId, localRestrictions,
+            UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, localRestrictions,
                     globalRestrictions);
         }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6ec0ba1..9cfa183 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3874,7 +3874,7 @@
         // challenge only and keep the screen on. However there is no easy way of doing that at the
         // moment so we set the screen off timeout regardless of whether it affects the parent user
         // or the profile challenge only.
-        long timeMs = Integer.MAX_VALUE;
+        long timeMs = Long.MAX_VALUE;
         List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
         for (UserInfo userInfo : profiles) {
             DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
@@ -3898,15 +3898,14 @@
 
         final long ident = mInjector.binderClearCallingIdentity();
         try {
-            if (policy.mLastMaximumTimeToLock != Integer.MAX_VALUE) {
+            if (policy.mLastMaximumTimeToLock != Long.MAX_VALUE) {
                 // Make sure KEEP_SCREEN_ON is disabled, since that
                 // would allow bypassing of the maximum time to lock.
                 mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
             }
 
-            // TODO It can overflow.  Cap it.
-            mInjector.getPowerManagerInternal()
-                    .setMaximumScreenOffTimeoutFromDeviceAdmin((int)policy.mLastMaximumTimeToLock);
+            mInjector.getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
+                    (int) Math.min(policy.mLastMaximumTimeToLock, Integer.MAX_VALUE));
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
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 6d168b0..212b37c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -32,6 +32,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
@@ -60,6 +61,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.validateMockitoUsage;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -208,7 +210,7 @@
     /**
      * Test for:
      * {@link DevicePolicyManager#setActiveAdmin}
-     *   with replace=false and replace=true
+     * with replace=false and replace=true
      * {@link DevicePolicyManager#isAdminActive}
      * {@link DevicePolicyManager#isAdminActiveAsUser}
      * {@link DevicePolicyManager#getActiveAdmins}
@@ -336,7 +338,7 @@
     /**
      * Test for:
      * {@link DevicePolicyManager#setActiveAdmin}
-     *   with replace=false
+     * with replace=false
      */
     public void testSetActiveAdmin_twiceWithoutReplace() throws Exception {
         // 1. Make sure the caller has proper permissions.
@@ -999,7 +1001,8 @@
 
     /**
      * This essentially tests
-     * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is private.)
+     * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is
+     * private.)
      *
      * We didn't use to persist the DO component class name, but now we do, and the above method
      * finds the right component from a package name upon migration.
@@ -1196,7 +1199,7 @@
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
-                );
+        );
         reset(mContext.userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1833,4 +1836,76 @@
 
         mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
     }
+
+    public void testSetMaximumTimeToLock() {
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+        dpm.setActiveAdmin(admin2, /* replace =*/ false);
+
+        reset(mMockContext.powerManagerInternal);
+        reset(mMockContext.settings);
+
+        dpm.setMaximumTimeToLock(admin1, 0);
+        verifyScreenTimeoutCall(null, false);
+        reset(mMockContext.powerManagerInternal);
+        reset(mMockContext.settings);
+
+        dpm.setMaximumTimeToLock(admin1, 1);
+        verifyScreenTimeoutCall(1, true);
+        reset(mMockContext.powerManagerInternal);
+        reset(mMockContext.settings);
+
+        dpm.setMaximumTimeToLock(admin2, 10);
+        verifyScreenTimeoutCall(null, false);
+        reset(mMockContext.powerManagerInternal);
+        reset(mMockContext.settings);
+
+        dpm.setMaximumTimeToLock(admin1, 5);
+        verifyScreenTimeoutCall(5, true);
+        reset(mMockContext.powerManagerInternal);
+        reset(mMockContext.settings);
+
+        dpm.setMaximumTimeToLock(admin2, 4);
+        verifyScreenTimeoutCall(4, true);
+        reset(mMockContext.powerManagerInternal);
+        reset(mMockContext.settings);
+
+        dpm.setMaximumTimeToLock(admin1, 0);
+        reset(mMockContext.powerManagerInternal);
+        reset(mMockContext.settings);
+
+        dpm.setMaximumTimeToLock(admin2, Integer.MAX_VALUE);
+        verifyScreenTimeoutCall(Integer.MAX_VALUE, true);
+        reset(mMockContext.powerManagerInternal);
+        reset(mMockContext.settings);
+
+        dpm.setMaximumTimeToLock(admin2, Integer.MAX_VALUE + 1);
+        verifyScreenTimeoutCall(Integer.MAX_VALUE, true);
+        reset(mMockContext.powerManagerInternal);
+        reset(mMockContext.settings);
+
+        dpm.setMaximumTimeToLock(admin2, 10);
+        verifyScreenTimeoutCall(10, true);
+        reset(mMockContext.powerManagerInternal);
+        reset(mMockContext.settings);
+
+        // There's no restriction; shold be set to MAX.
+        dpm.setMaximumTimeToLock(admin2, 0);
+        verifyScreenTimeoutCall(Integer.MAX_VALUE, false);
+    }
+
+    private void verifyScreenTimeoutCall(Integer expectedTimeout,
+            boolean shouldStayOnWhilePluggedInBeCleared) {
+        if (expectedTimeout == null) {
+            verify(mMockContext.powerManagerInternal, times(0))
+                    .setMaximumScreenOffTimeoutFromDeviceAdmin(anyInt());
+        } else {
+            verify(mMockContext.powerManagerInternal, times(1))
+                    .setMaximumScreenOffTimeoutFromDeviceAdmin(eq(expectedTimeout));
+        }
+        // TODO Verify calls to settingsGlobalPutInt.  Tried but somehow mockito threw
+        // UnfinishedVerificationException.
+    }
 }
+
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 7a00098..ef8e420 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -44,11 +44,14 @@
 import android.view.IWindowManager;
 
 import org.junit.Assert;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -294,6 +297,50 @@
 
         mUserInfos.add(uh);
         when(userManager.getUsers()).thenReturn(mUserInfos);
+        when(userManager.getUserInfo(anyInt())).thenAnswer(
+                new Answer<UserInfo>() {
+                    @Override
+                    public UserInfo answer(InvocationOnMock invocation) throws Throwable {
+                        final int userId = (int) invocation.getArguments()[0];
+                        for (UserInfo ui : mUserInfos) {
+                            if (ui.id == userId) {
+                                return ui;
+                            }
+                        }
+                        return null;
+                    }
+                }
+        );
+        when(userManager.getProfiles(anyInt())).thenAnswer(
+                new Answer<List<UserInfo>>() {
+                    @Override
+                    public List<UserInfo> answer(InvocationOnMock invocation) throws Throwable {
+                        final int userId = (int) invocation.getArguments()[0];
+                        final ArrayList<UserInfo> ret = new ArrayList<UserInfo>();
+                        UserInfo parent = null;
+                        for (UserInfo ui : mUserInfos) {
+                            if (ui.id == userId) {
+                                parent = ui;
+                                break;
+                            }
+                        }
+                        if (parent == null) {
+                            return ret;
+                        }
+                        ret.add(parent);
+                        for (UserInfo ui : mUserInfos) {
+                            if (ui.id == userId) {
+                                continue;
+                            }
+                            if (ui.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+                                    && ui.profileGroupId == parent.profileGroupId) {
+                                ret.add(ui);
+                            }
+                        }
+                        return ret;
+                    }
+                }
+        );
 
         // Create a data directory.
         final File dir = new File(dataDir, "user" + userId);