API change for cross profile calendar feature.

According to new requirements in b/121179845, we are changing the
API pattern from "add/remove" to "set(set<string>)" to support
"enable all packages" operation. Setting the whitelist to null
will enable all packages. This behavior is consistent with existing
methods in DevicePolicyManager, e.g. setPermittedInputMethods.

Also corrected some languages in the comments and annotations.

Bug: 121179845
Test: atest ManagedProfileTest#testCrossProfileCalendar
atest DevicePolicyManagerTest

Change-Id: I87f17a2094792e44fdeb672658bddb871c2c1eeb
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index d8225b3..2bf6f35 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -108,12 +108,7 @@
             ParcelFileDescriptor updateFileDescriptor, StartInstallingUpdateCallback listener) {}
 
     @Override
-    public void addCrossProfileCalendarPackage(ComponentName admin, String packageName) {
-    }
-
-    @Override
-    public boolean removeCrossProfileCalendarPackage(ComponentName admin, String packageName) {
-        return false;
+    public void setCrossProfileCalendarPackages(ComponentName admin, List<String> packageNames) {
     }
 
     @Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 54053a8..23c68b2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -949,8 +949,8 @@
                 "metered_data_disabled_packages";
         private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES =
                 "cross-profile-calendar-packages";
-        private static final String TAG_PACKAGE = "package";
-
+        private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL =
+                "cross-profile-calendar-packages-null";
 
         DeviceAdminInfo info;
 
@@ -1072,7 +1072,9 @@
         String endUserSessionMessage = null;
 
         // The whitelist of packages that can access cross profile calendar APIs.
-        final Set<String> mCrossProfileCalendarPackages = new ArraySet<>();
+        // This whitelist should be in default an empty list, which indicates that no package
+        // is whitelisted.
+        List<String> mCrossProfileCalendarPackages = Collections.emptyList();
 
         ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
             info = _info;
@@ -1343,11 +1345,12 @@
                 out.text(endUserSessionMessage);
                 out.endTag(null, TAG_END_USER_SESSION_MESSAGE);
             }
-            if (!mCrossProfileCalendarPackages.isEmpty()) {
-                out.startTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES);
-                writeAttributeValuesToXml(
-                        out, TAG_PACKAGE, mCrossProfileCalendarPackages);
-                out.endTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES);
+            if (mCrossProfileCalendarPackages == null) {
+                out.startTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL);
+                out.endTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL);
+            } else {
+                writePackageListToXml(out, TAG_CROSS_PROFILE_CALENDAR_PACKAGES,
+                        mCrossProfileCalendarPackages);
             }
         }
 
@@ -1542,8 +1545,9 @@
                         Log.w(LOG_TAG, "Missing text when loading end session message");
                     }
                 } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES.equals(tag)) {
-                    readAttributeValues(
-                            parser, TAG_PACKAGE, mCrossProfileCalendarPackages);
+                    mCrossProfileCalendarPackages = readPackageList(parser, tag);
+                } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL.equals(tag)) {
+                    mCrossProfileCalendarPackages = null;
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -1759,8 +1763,10 @@
                 pw.print(prefix);  pw.println("parentAdmin:");
                 parentAdmin.dump(prefix + "  ", pw);
             }
-            pw.print(prefix); pw.print("mCrossProfileCalendarPackages=");
-            pw.println(mCrossProfileCalendarPackages);
+            if (mCrossProfileCalendarPackages != null) {
+                pw.print(prefix); pw.print("mCrossProfileCalendarPackages=");
+                pw.println(mCrossProfileCalendarPackages);
+            }
         }
     }
 
@@ -13988,55 +13994,27 @@
     }
 
     @Override
-    public void addCrossProfileCalendarPackage(ComponentName who, String packageName) {
+    public void setCrossProfileCalendarPackages(ComponentName who, List<String> packageNames) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkStringNotEmpty(packageName, "Package name is null or empty");
 
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            if (admin.mCrossProfileCalendarPackages.add(packageName)) {
-                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
-            }
+            admin.mCrossProfileCalendarPackages = packageNames;
+            saveSettingsLocked(mInjector.userHandleGetCallingUserId());
         }
         DevicePolicyEventLogger
-                .createEvent(DevicePolicyEnums.ADD_CROSS_PROFILE_CALENDAR_PACKAGE)
+                .createEvent(DevicePolicyEnums.SET_CROSS_PROFILE_CALENDAR_PACKAGES)
                 .setAdmin(who)
-                .setStrings(packageName)
+                .setStrings(packageNames == null ? null
+                        : packageNames.toArray(new String[packageNames.size()]))
                 .write();
     }
 
     @Override
-    public boolean removeCrossProfileCalendarPackage(ComponentName who, String packageName) {
-        if (!mHasFeature) {
-            return false;
-        }
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkStringNotEmpty(packageName, "Package name is null or empty");
-
-        boolean isRemoved = false;
-        synchronized (getLockObject()) {
-            final ActiveAdmin admin = getActiveAdminForCallerLocked(
-                    who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            isRemoved = admin.mCrossProfileCalendarPackages.remove(packageName);
-            if (isRemoved) {
-                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
-            }
-        }
-        if (isRemoved) {
-            DevicePolicyEventLogger
-                    .createEvent(DevicePolicyEnums.REMOVE_CROSS_PROFILE_CALENDAR_PACKAGE)
-                    .setAdmin(who)
-                    .setStrings(packageName)
-                    .write();
-        }
-        return isRemoved;
-    }
-
-    @Override
     public List<String> getCrossProfileCalendarPackages(ComponentName who) {
         if (!mHasFeature) {
             return Collections.emptyList();
@@ -14046,7 +14024,7 @@
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            return new ArrayList<String>(admin.mCrossProfileCalendarPackages);
+            return admin.mCrossProfileCalendarPackages;
         }
     }
 
@@ -14062,6 +14040,9 @@
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
             if (admin != null) {
+                if (admin.mCrossProfileCalendarPackages == null) {
+                    return true;
+                }
                 return admin.mCrossProfileCalendarPackages.contains(packageName);
             }
         }
@@ -14077,7 +14058,7 @@
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
             if (admin != null) {
-                return new ArrayList<String>(admin.mCrossProfileCalendarPackages);
+                return admin.mCrossProfileCalendarPackages;
             }
         }
         return Collections.emptyList();
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 0813e6fa..535198b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5239,6 +5239,45 @@
         assertEquals(PASSWORD_COMPLEXITY_HIGH, dpm.getPasswordComplexity());
     }
 
+    public void testCrossProfileCalendarPackages_initiallyEmpty() {
+        setAsProfileOwner(admin1);
+        final Set<String> packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertCrossProfileCalendarPackagesEqual(packages, Collections.emptySet());
+    }
+
+    public void testCrossProfileCalendarPackages_reopenDpms() {
+        setAsProfileOwner(admin1);
+        dpm.setCrossProfileCalendarPackages(admin1, null);
+        Set<String> packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertTrue(packages == null);
+        initializeDpms();
+        packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertTrue(packages == null);
+
+        dpm.setCrossProfileCalendarPackages(admin1, Collections.emptySet());
+        packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertCrossProfileCalendarPackagesEqual(packages, Collections.emptySet());
+        initializeDpms();
+        packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertCrossProfileCalendarPackagesEqual(packages, Collections.emptySet());
+
+        final String dummyPackageName = "test";
+        final Set<String> testPackages = new ArraySet<String>(Arrays.asList(dummyPackageName));
+        dpm.setCrossProfileCalendarPackages(admin1, testPackages);
+        packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertCrossProfileCalendarPackagesEqual(packages, testPackages);
+        initializeDpms();
+        packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertCrossProfileCalendarPackagesEqual(packages, testPackages);
+    }
+
+    private void assertCrossProfileCalendarPackagesEqual(Set<String> expected, Set<String> actual) {
+        assertTrue(expected != null);
+        assertTrue(actual != null);
+        assertTrue(expected.containsAll(actual));
+        assertTrue(actual.containsAll(expected));
+    }
+
     private void configureProfileOwnerForDeviceIdAccess(ComponentName who, int userId) {
         final long ident = mServiceContext.binder.clearCallingIdentity();
         mServiceContext.binder.callingUid =