Add health connect permissions to FGS type "health"

Bug: 246792057
Bug: 254662338
Test: atest CtsAppFgsTestCases
Change-Id: I95be5f3f69c35299bb0edc998b40b103f3963d17
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index e419e06..fbc11e9 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -53,6 +53,7 @@
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
+import android.healthconnect.HealthConnectManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.ArraySet;
@@ -65,8 +66,10 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Optional;
+import java.util.Set;
 
 /**
  * This class enforces the policies around the foreground service types.
@@ -640,11 +643,12 @@
          *
          * For test only.
          */
-        public @NonNull Optional<String[]> getRequiredAllOfPermissionsForTest() {
+        public @NonNull Optional<String[]> getRequiredAllOfPermissionsForTest(
+                @NonNull Context context) {
             if (mAllOfPermissions == null) {
                 return Optional.empty();
             }
-            return Optional.of(mAllOfPermissions.toStringArray());
+            return Optional.of(mAllOfPermissions.toStringArray(context));
         }
 
         /**
@@ -653,11 +657,12 @@
          *
          * For test only.
          */
-        public @NonNull Optional<String[]> getRequiredAnyOfPermissionsForTest() {
+        public @NonNull Optional<String[]> getRequiredAnyOfPermissionsForTest(
+                @NonNull Context context) {
             if (mAnyOfPermissions == null) {
                 return Optional.empty();
             }
-            return Optional.of(mAnyOfPermissions.toStringArray());
+            return Optional.of(mAnyOfPermissions.toStringArray(context));
         }
 
         /**
@@ -793,12 +798,12 @@
             return sb.toString();
         }
 
-        @NonNull String[] toStringArray() {
-            final String[] names = new String[mPermissions.length];
+        @NonNull String[] toStringArray(Context context) {
+            final ArrayList<String> list = new ArrayList<>();
             for (int i = 0; i < mPermissions.length; i++) {
-                names[i] = mPermissions[i].mName;
+                mPermissions[i].addToList(context, list);
             }
-            return names;
+            return list.toArray(new String[list.size()]);
         }
     }
 
@@ -811,7 +816,7 @@
         /**
          * The name of this permission.
          */
-        final @NonNull String mName;
+        protected final @NonNull String mName;
 
         /**
          * Constructor.
@@ -831,6 +836,10 @@
         public String toString() {
             return mName;
         }
+
+        void addToList(@NonNull Context context, @NonNull ArrayList<String> list) {
+            list.add(mName);
+        }
     }
 
     /**
@@ -844,15 +853,23 @@
         @Override
         @SuppressLint("AndroidFrameworkRequiresPermission")
         @PackageManager.PermissionResult
-        public int checkPermission(Context context, int callerUid, int callerPid,
+        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
                 String packageName, boolean allowWhileInUse) {
+            return checkPermission(context, mName, callerUid, callerPid, packageName,
+                    allowWhileInUse);
+        }
+
+        @SuppressLint("AndroidFrameworkRequiresPermission")
+        @PackageManager.PermissionResult
+        int checkPermission(@NonNull Context context, @NonNull String name, int callerUid,
+                int callerPid, String packageName, boolean allowWhileInUse) {
             // Simple case, check if it's already granted.
-            if (context.checkPermission(mName, callerPid, callerUid) == PERMISSION_GRANTED) {
+            if (context.checkPermission(name, callerPid, callerUid) == PERMISSION_GRANTED) {
                 return PERMISSION_GRANTED;
             }
             if (allowWhileInUse) {
                 // Check its appops
-                final int opCode = AppOpsManager.permissionToOpCode(mName);
+                final int opCode = AppOpsManager.permissionToOpCode(name);
                 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
                 if (opCode != AppOpsManager.OP_NONE) {
                     final int currentMode = appOpsManager.unsafeCheckOpRawNoThrow(opCode, callerUid,
@@ -880,7 +897,7 @@
 
         @Override
         @PackageManager.PermissionResult
-        public int checkPermission(Context context, int callerUid, int callerPid,
+        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
                 String packageName, boolean allowWhileInUse) {
             final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
             final int mode = appOpsManager.unsafeCheckOpRawNoThrow(mOpCode, callerUid, packageName);
@@ -900,7 +917,7 @@
         @Override
         @SuppressLint("AndroidFrameworkRequiresPermission")
         @PackageManager.PermissionResult
-        public int checkPermission(Context context, int callerUid, int callerPid,
+        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
                 String packageName, boolean allowWhileInUse) {
             final UsbManager usbManager = context.getSystemService(UsbManager.class);
             final HashMap<String, UsbDevice> devices = usbManager.getDeviceList();
@@ -926,7 +943,7 @@
         @Override
         @SuppressLint("AndroidFrameworkRequiresPermission")
         @PackageManager.PermissionResult
-        public int checkPermission(Context context, int callerUid, int callerPid,
+        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
                 String packageName, boolean allowWhileInUse) {
             final UsbManager usbManager = context.getSystemService(UsbManager.class);
             final UsbAccessory[] accessories = usbManager.getAccessoryList();
@@ -941,6 +958,45 @@
         }
     }
 
+    static class HealthConnectPermission extends RegularPermission {
+        private @Nullable String[] mPermissionNames;
+
+        HealthConnectPermission() {
+            super("Health Connect");
+        }
+
+        @Override
+        @SuppressLint("AndroidFrameworkRequiresPermission")
+        @PackageManager.PermissionResult
+        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
+                String packageName, boolean allowWhileInUse) {
+            final String[] perms = getPermissions(context);
+            for (String perm : perms) {
+                if (checkPermission(context, perm, callerUid, callerPid,
+                        packageName, allowWhileInUse) == PERMISSION_GRANTED) {
+                    return PERMISSION_GRANTED;
+                }
+            }
+            return PERMISSION_DENIED;
+        }
+
+        @Override
+        void addToList(@NonNull Context context, @NonNull ArrayList<String> list) {
+            final String[] perms = getPermissions(context);
+            for (String perm : perms) {
+                list.add(perm);
+            }
+        }
+
+        private @NonNull String[] getPermissions(@NonNull Context context) {
+            if (mPermissionNames != null) {
+                return mPermissionNames;
+            }
+            final Set<String> healthPerms = HealthConnectManager.getHealthPermissions(context);
+            return mPermissionNames = healthPerms.toArray(new String[healthPerms.size()]);
+        }
+    }
+
     /**
      * The default policy for the foreground service types.
      *
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 14f03ea..c2c6130 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -308,7 +308,9 @@
      * permissions:
      * {@link android.Manifest.permission#ACTIVITY_RECOGNITION},
      * {@link android.Manifest.permission#BODY_SENSORS},
-     * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS}.
+     * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS},
+     * or one of the {@code "android.permission.health.*"} permissions defined in the
+     * {@link android.healthconnect.HealthPermissions}.
      */
     @RequiresPermission(
             allOf = {
@@ -424,7 +426,7 @@
      *      android:name=".MySpecialForegroundService"
      *      android:foregroundServiceType="specialUse|foo"&gt;
      *      &lt;property
-     *          android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE""
+     *          android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
      *          android:value="foo"
      *      /&gt;
      * &lt;/service&gt;
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 01c0809..680a0a1 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -771,6 +771,80 @@
     <!-- Permissions required for CTS test - CtsAppFgsTestCases -->
     <uses-permission android:name="android.permission.USE_EXACT_ALARM" />
 
+    <!-- Permissions required for CTS test - CtsAppFgsTestCases -->
+    <uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED" />
+    <uses-permission android:name="android.permission.health.READ_BASAL_BODY_TEMPERATURE" />
+    <uses-permission android:name="android.permission.health.READ_BASAL_METABOLIC_RATE" />
+    <uses-permission android:name="android.permission.health.READ_BLOOD_GLUCOSE" />
+    <uses-permission android:name="android.permission.health.READ_BLOOD_PRESSURE" />
+    <uses-permission android:name="android.permission.health.READ_BODY_FAT" />
+    <uses-permission android:name="android.permission.health.READ_BODY_TEMPERATURE" />
+    <uses-permission android:name="android.permission.health.READ_BODY_WATER_MASS" />
+    <uses-permission android:name="android.permission.health.READ_BONE_MASS" />
+    <uses-permission android:name="android.permission.health.READ_CERVICAL_MUCUS" />
+    <uses-permission android:name="android.permission.health.READ_DISTANCE" />
+    <uses-permission android:name="android.permission.health.READ_ELEVATION_GAINED" />
+    <uses-permission android:name="android.permission.health.READ_EXERCISE" />
+    <uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED" />
+    <uses-permission android:name="android.permission.health.READ_HEART_RATE" />
+    <uses-permission android:name="android.permission.health.READ_HEART_RATE_VARIABILITY" />
+    <uses-permission android:name="android.permission.health.READ_HEIGHT" />
+    <uses-permission android:name="android.permission.health.READ_HIP_CIRCUMFERENCE" />
+    <uses-permission android:name="android.permission.health.READ_HYDRATION" />
+    <uses-permission android:name="android.permission.health.READ_LEAN_BODY_MASS" />
+    <uses-permission android:name="android.permission.health.READ_MENSTRUATION" />
+    <uses-permission android:name="android.permission.health.READ_NUTRITION" />
+    <uses-permission android:name="android.permission.health.READ_OVULATION_TEST" />
+    <uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION" />
+    <uses-permission android:name="android.permission.health.READ_POWER" />
+    <uses-permission android:name="android.permission.health.READ_RESPIRATORY_RATE" />
+    <uses-permission android:name="android.permission.health.READ_RESTING_HEART_RATE" />
+    <uses-permission android:name="android.permission.health.READ_SEXUAL_ACTIVITY" />
+    <uses-permission android:name="android.permission.health.READ_SLEEP" />
+    <uses-permission android:name="android.permission.health.READ_SPEED" />
+    <uses-permission android:name="android.permission.health.READ_STEPS" />
+    <uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED" />
+    <uses-permission android:name="android.permission.health.READ_VO2_MAX" />
+    <uses-permission android:name="android.permission.health.READ_WAIST_CIRCUMFERENCE" />
+    <uses-permission android:name="android.permission.health.READ_WEIGHT" />
+    <uses-permission android:name="android.permission.health.READ_WHEELCHAIR_PUSHES" />
+    <uses-permission android:name="android.permission.health.WRITE_ACTIVE_CALORIES_BURNED" />
+    <uses-permission android:name="android.permission.health.WRITE_BASAL_BODY_TEMPERATURE" />
+    <uses-permission android:name="android.permission.health.WRITE_BASAL_METABOLIC_RATE" />
+    <uses-permission android:name="android.permission.health.WRITE_BLOOD_GLUCOSE" />
+    <uses-permission android:name="android.permission.health.WRITE_BLOOD_PRESSURE" />
+    <uses-permission android:name="android.permission.health.WRITE_BODY_FAT" />
+    <uses-permission android:name="android.permission.health.WRITE_BODY_TEMPERATURE" />
+    <uses-permission android:name="android.permission.health.WRITE_BODY_WATER_MASS" />
+    <uses-permission android:name="android.permission.health.WRITE_BONE_MASS" />
+    <uses-permission android:name="android.permission.health.WRITE_CERVICAL_MUCUS" />
+    <uses-permission android:name="android.permission.health.WRITE_DISTANCE" />
+    <uses-permission android:name="android.permission.health.WRITE_ELEVATION_GAINED" />
+    <uses-permission android:name="android.permission.health.WRITE_EXERCISE" />
+    <uses-permission android:name="android.permission.health.WRITE_FLOORS_CLIMBED" />
+    <uses-permission android:name="android.permission.health.WRITE_HEART_RATE" />
+    <uses-permission android:name="android.permission.health.WRITE_HEART_RATE_VARIABILITY" />
+    <uses-permission android:name="android.permission.health.WRITE_HEIGHT" />
+    <uses-permission android:name="android.permission.health.WRITE_HIP_CIRCUMFERENCE" />
+    <uses-permission android:name="android.permission.health.WRITE_HYDRATION" />
+    <uses-permission android:name="android.permission.health.WRITE_LEAN_BODY_MASS" />
+    <uses-permission android:name="android.permission.health.WRITE_MENSTRUATION" />
+    <uses-permission android:name="android.permission.health.WRITE_NUTRITION" />
+    <uses-permission android:name="android.permission.health.WRITE_OVULATION_TEST" />
+    <uses-permission android:name="android.permission.health.WRITE_OXYGEN_SATURATION" />
+    <uses-permission android:name="android.permission.health.WRITE_POWER" />
+    <uses-permission android:name="android.permission.health.WRITE_RESPIRATORY_RATE" />
+    <uses-permission android:name="android.permission.health.WRITE_RESTING_HEART_RATE" />
+    <uses-permission android:name="android.permission.health.WRITE_SEXUAL_ACTIVITY" />
+    <uses-permission android:name="android.permission.health.WRITE_SLEEP" />
+    <uses-permission android:name="android.permission.health.WRITE_SPEED" />
+    <uses-permission android:name="android.permission.health.WRITE_STEPS" />
+    <uses-permission android:name="android.permission.health.WRITE_TOTAL_CALORIES_BURNED" />
+    <uses-permission android:name="android.permission.health.WRITE_VO2_MAX" />
+    <uses-permission android:name="android.permission.health.WRITE_WAIST_CIRCUMFERENCE" />
+    <uses-permission android:name="android.permission.health.WRITE_WEIGHT" />
+    <uses-permission android:name="android.permission.health.WRITE_WHEELCHAIR_PUSHES" />
+
     <!-- Permission required for CTS test - ApplicationExemptionsTests -->
     <uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS" />