Don't expose default strong auth timeout as constant

The admin can instead use the value of 0 to reset to default.

Test: runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java

Bug: 31430135
Change-Id: I0d6b29ca4eca65d7ca72a8975a0c28c9050a946c
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a207a52..4ddcfe5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2352,18 +2352,23 @@
      * <p>The calling device admin must be a device or profile owner. If it is not,
      * a {@link SecurityException} will be thrown.
      *
+     * <p>The calling device admin can verify the value it has set by calling
+     * {@link #getRequiredStrongAuthTimeout(ComponentName)} and passing in its instance.
+     *
      * <p>This method can be called on the {@link DevicePolicyManager} instance returned by
      * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
      * profile.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param timeoutMs The new timeout, after which the user will have to unlock with strong
-     *         authentication method. If the timeout is lower than 1 hour (minimum) or higher than
-     *         72 hours (default and maximum) an {@link IllegalArgumentException} is thrown.
+     *         authentication method. A value of 0 means the admin is not participating in
+     *         controlling the timeout.
+     *         The minimum and maximum timeouts are platform-defined and are typically 1 hour and
+     *         72 hours, respectively. Though discouraged, the admin may choose to require strong
+     *         auth at all times using {@link #KEYGUARD_DISABLE_FINGERPRINT} and/or
+     *         {@link #KEYGUARD_DISABLE_TRUST_AGENTS}.
      *
      * @throws SecurityException if {@code admin} is not a device or profile owner.
-     * @throws IllegalArgumentException if the timeout is lower than 1 hour (minimum) or higher than
-     *         72 hours (default and maximum)
      *
      * @hide
      */
@@ -2389,7 +2394,7 @@
      *
      * @param admin The name of the admin component to check, or {@code null} to aggregate
      *         accross all participating admins.
-     * @return The timeout or default timeout if not configured
+     * @return The timeout or 0 if not configured for the provided admin.
      *
      * @hide
      */
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e7772f3..f9fa005 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -617,7 +617,7 @@
         static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
         long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
 
-        long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+        long strongAuthUnlockTimeout = 0; // admin doesn't participate by default
 
         static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
         int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
@@ -4254,10 +4254,15 @@
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkArgument(timeoutMs >= MINIMUM_STRONG_AUTH_TIMEOUT_MS,
-                "Timeout must not be lower than the minimum strong auth timeout.");
-        Preconditions.checkArgument(timeoutMs <= DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS,
-                "Timeout must not be higher than the default strong auth timeout.");
+        Preconditions.checkArgument(timeoutMs >= 0, "Timeout must not be a negative number.");
+        // timeoutMs with value 0 means that the admin doesn't participate
+        // timeoutMs is clamped to the interval in case the internal constants change in the future
+        if (timeoutMs != 0 && timeoutMs < MINIMUM_STRONG_AUTH_TIMEOUT_MS) {
+            timeoutMs = MINIMUM_STRONG_AUTH_TIMEOUT_MS;
+        }
+        if (timeoutMs > DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) {
+            timeoutMs = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+        }
 
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
@@ -4273,7 +4278,7 @@
     /**
      * Return a single admin's strong auth unlock timeout or minimum value (strictest) of all
      * admins if who is null.
-     * Returns default timeout if not configured.
+     * Returns 0 if not configured for the provided admin.
      */
     @Override
     public long getRequiredStrongAuthTimeout(ComponentName who, int userId, boolean parent) {
@@ -4284,9 +4289,7 @@
         synchronized (this) {
             if (who != null) {
                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId, parent);
-                return admin != null ? Math.max(admin.strongAuthUnlockTimeout,
-                        MINIMUM_STRONG_AUTH_TIMEOUT_MS)
-                        : DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+                return admin != null ? admin.strongAuthUnlockTimeout : 0;
             }
 
             // Return the strictest policy across all participating admins.
@@ -4294,8 +4297,10 @@
 
             long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
             for (int i = 0; i < admins.size(); i++) {
-                strongAuthUnlockTimeout = Math.min(admins.get(i).strongAuthUnlockTimeout,
-                        strongAuthUnlockTimeout);
+                final long timeout = admins.get(i).strongAuthUnlockTimeout;
+                if (timeout != 0) { // take only participating admins into account
+                    strongAuthUnlockTimeout = Math.min(timeout, strongAuthUnlockTimeout);
+                }
             }
             return Math.max(strongAuthUnlockTimeout, MINIMUM_STRONG_AUTH_TIMEOUT_MS);
         }
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 01b2c3b..56ff621 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1915,6 +1915,61 @@
         verifyScreenTimeoutCall(Integer.MAX_VALUE, false);
     }
 
+    public void testSetRequiredStrongAuthTimeout_DeviceOwner() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h
+        final long ONE_MINUTE = 60 * 1000;
+
+        // aggregation should be the default if unset by any admin
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null),
+                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+        // admin not participating by default
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
+
+        //clamping from the top
+        dpm.setRequiredStrongAuthTimeout(admin1,
+                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1),
+                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null),
+                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+        // 0 means default
+        dpm.setRequiredStrongAuthTimeout(admin1, 0);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null),
+                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+        // clamping from the bottom
+        dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS - ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS);
+
+        // value within range
+        dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS
+                + ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS
+                + ONE_MINUTE);
+
+        // reset to default
+        dpm.setRequiredStrongAuthTimeout(admin1, 0);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null),
+                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+        // negative value
+        try {
+            dpm.setRequiredStrongAuthTimeout(admin1, -ONE_MINUTE);
+            fail("Didn't throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+        }
+    }
+
     private void verifyScreenTimeoutCall(Integer expectedTimeout,
             boolean shouldStayOnWhilePluggedInBeCleared) {
         if (expectedTimeout == null) {