Add a DPM api to check if a pkg is restricted to use metered data.

We need this so that Settings can check if an app is
restricted by admin from using metered data.

Bug: 63700027
Test: manual
Test: atest com.android.server.devicepolicy.DevicePolicyManagerTest
Change-Id: I9a2ea9c458b0f10a3c3c6edcbe82da9eccaa51c3
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3b4511e..131abb5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8261,7 +8261,7 @@
     }
 
     /**
-     * Called by a device or profile owner to restrict packages from accessing metered data.
+     * Called by a device or profile owner to restrict packages from using metered data.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageNames the list of package names to be restricted.
@@ -8283,7 +8283,7 @@
 
     /**
      * Called by a device or profile owner to retrieve the list of packages which are restricted
-     * by the admin from accessing metered data.
+     * by the admin from using metered data.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with.
      * @return the list of restricted package names.
@@ -8302,6 +8302,30 @@
     }
 
     /**
+     * Called by the system to check if a package is restricted from using metered data
+     * by {@param admin}.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with.
+     * @param packageName the package whose restricted status is needed.
+     * @param userId the user to which {@param packageName} belongs.
+     * @return {@code true} if the package is restricted by admin, otherwise {@code false}
+     * @throws SecurityException if the caller doesn't run with {@link Process#SYSTEM_UID}
+     * @hide
+     */
+    public boolean isMeteredDataDisabledForUser(@NonNull ComponentName admin, String packageName,
+            @UserIdInt int userId) {
+        throwIfParentInstance("getMeteredDataDisabledForUser");
+        if (mService != null) {
+            try {
+                return mService.isMeteredDataDisabledForUser(admin, packageName, userId);
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Called by device owners to retrieve device logs from before the device's last reboot.
      * <p>
      * <strong> This API is not supported on all devices. Calling this API on unsupported devices
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 7fc31b1..cba9311 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -413,4 +413,6 @@
     List<ApnSetting> getOverrideApns(in ComponentName admin);
     void setOverrideApnsEnabled(in ComponentName admin, boolean enabled);
     boolean isOverrideApnEnabled(in ComponentName admin);
+
+    boolean isMeteredDataDisabledForUser(in ComponentName admin, String packageName, int userId);
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index fce5dd9..7728f66 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -363,6 +363,26 @@
     }
 
     /**
+     * Check if {@param packageName} is restricted by the profile or device owner from using
+     * metered data.
+     *
+     * @return EnforcedAdmin object containing the enforced admin component and admin user details,
+     * or {@code null} if the {@param packageName} is not restricted.
+     */
+    public static EnforcedAdmin checkIfMeteredDataRestricted(Context context,
+            String packageName, int userId) {
+        final EnforcedAdmin enforcedAdmin = getProfileOrDeviceOwner(context, userId);
+        if (enforcedAdmin == null) {
+            return null;
+        }
+
+        final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        return dpm.isMeteredDataDisabledForUser(enforcedAdmin.component, packageName, userId)
+                ? enforcedAdmin : null;
+    }
+
+    /**
      * Checks if {@link android.app.admin.DevicePolicyManager#setAutoTimeRequired} is enforced
      * on the device.
      *
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 5c73d54..3a0ae9f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -48,6 +48,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
 import android.text.format.Formatter;
 import android.util.IconDrawableFactory;
 import android.util.Log;
@@ -1282,7 +1283,8 @@
         // A location where extra info can be placed to be used by custom filters.
         public Object extraInfo;
 
-        AppEntry(Context context, ApplicationInfo info, long id) {
+        @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+        public AppEntry(Context context, ApplicationInfo info, long id) {
             apkFile = new File(info.sourceDir);
             this.id = id;
             this.info = info;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 5529426..d1cc5de 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -178,4 +178,10 @@
 
     public void clearSystemUpdatePolicyFreezePeriodRecord() {
     }
+
+    @Override
+    public boolean isMeteredDataDisabledForUser(ComponentName admin,
+            String packageName, int userId) {
+        return false;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0589790..9a51eef 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11409,6 +11409,27 @@
         }
     }
 
+    @Override
+    public boolean isMeteredDataDisabledForUser(ComponentName who,
+            String packageName, int userId) {
+        Preconditions.checkNotNull(who);
+
+        if (!mHasFeature) {
+            return false;
+        }
+        if (!isCallerWithSystemUid()) {
+            throw new SecurityException(
+                    "Only the system can query restricted pkgs for a specific user");
+        }
+        synchronized (this) {
+            final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId);
+            if (admin != null && admin.meteredDisabledPackages != null) {
+                return admin.meteredDisabledPackages.contains(packageName);
+            }
+        }
+        return false;
+    }
+
     private void pushMeteredDisabledPackagesLocked(int userId) {
         mInjector.getNetworkPolicyManagerInternal().setMeteredRestrictedPackages(
                 getMeteredDisabledPackagesLocked(userId), userId);
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 6b87ea9..00a85a5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -2160,6 +2160,51 @@
                 () -> dpm.getMeteredDataDisabled(admin1));
     }
 
+    public void testGetMeteredDataDisabledForUser() throws Exception {
+        setAsProfileOwner(admin1);
+
+        // Setup
+        final ArrayList<String> emptyList = new ArrayList<>();
+        final ArrayList<String> pkgsToRestrict = new ArrayList<>();
+        final String package1 = "com.example.one";
+        final String package2 = "com.example.two";
+        final String package3 = "com.example.three";
+        pkgsToRestrict.add(package1);
+        pkgsToRestrict.add(package2);
+        setupPackageInPackageManager(package1, DpmMockContext.CALLER_USER_HANDLE, 123, 0);
+        setupPackageInPackageManager(package2, DpmMockContext.CALLER_USER_HANDLE, 456, 0);
+        List<String> excludedPkgs = dpm.setMeteredDataDisabled(admin1, pkgsToRestrict);
+
+        // Verify
+        assertEquals(emptyList, excludedPkgs);
+        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+        assertTrue(package1 + "should be restricted",
+                dpm.isMeteredDataDisabledForUser(admin1, package1,
+                        DpmMockContext.CALLER_USER_HANDLE));
+        assertTrue(package2 + "should be restricted",
+                dpm.isMeteredDataDisabledForUser(admin1, package2,
+                        DpmMockContext.CALLER_USER_HANDLE));
+        assertFalse(package3 + "should not be restricted",
+                dpm.isMeteredDataDisabledForUser(admin1, package3,
+                        DpmMockContext.CALLER_USER_HANDLE));
+    }
+
+    public void testGetMeteredDataDisabledForUser_nonSystemUidCaller() throws Exception {
+        setAsProfileOwner(admin1);
+        assertExpectException(SecurityException.class,
+                /* messageRegex= */ "Only the system can query restricted pkgs",
+                () -> dpm.isMeteredDataDisabledForUser(
+                        admin1, "com.example.one", DpmMockContext.CALLER_USER_HANDLE));
+        dpm.clearProfileOwner(admin1);
+
+        setDeviceOwner();
+        assertExpectException(SecurityException.class,
+                /* messageRegex= */ "Only the system can query restricted pkgs",
+                () -> dpm.isMeteredDataDisabledForUser(
+                        admin1, "com.example.one", DpmMockContext.CALLER_USER_HANDLE));
+        clearDeviceOwner();
+    }
+
     public void testCreateAdminSupportIntent() throws Exception {
         // Setup device owner.
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;