Add SkinTemperature aggregation types.

Test: Added conversion test and tested locally with Api 35.
Relnote: Add SkinTemperature aggregation types.

Bug: 350445998

Change-Id: Ibe1238dd4658f3cd786e3daf0ee37700f91d6643
diff --git a/health/connect/connect-client/api/current.txt b/health/connect/connect-client/api/current.txt
index a7fde6f..59a0825 100644
--- a/health/connect/connect-client/api/current.txt
+++ b/health/connect/connect-client/api/current.txt
@@ -1350,6 +1350,9 @@
     field public static final int MEASUREMENT_LOCATION_TOE = 2; // 0x2
     field public static final int MEASUREMENT_LOCATION_UNKNOWN = 0; // 0x0
     field public static final int MEASUREMENT_LOCATION_WRIST = 3; // 0x3
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.TemperatureDelta> TEMPERATURE_DELTA_AVG;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.TemperatureDelta> TEMPERATURE_DELTA_MAX;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.TemperatureDelta> TEMPERATURE_DELTA_MIN;
   }
 
   public static final class SkinTemperatureRecord.Companion {
diff --git a/health/connect/connect-client/api/restricted_current.txt b/health/connect/connect-client/api/restricted_current.txt
index 9ea4048..00b08ec 100644
--- a/health/connect/connect-client/api/restricted_current.txt
+++ b/health/connect/connect-client/api/restricted_current.txt
@@ -1373,6 +1373,9 @@
     field public static final int MEASUREMENT_LOCATION_TOE = 2; // 0x2
     field public static final int MEASUREMENT_LOCATION_UNKNOWN = 0; // 0x0
     field public static final int MEASUREMENT_LOCATION_WRIST = 3; // 0x3
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.TemperatureDelta> TEMPERATURE_DELTA_AVG;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.TemperatureDelta> TEMPERATURE_DELTA_MAX;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.TemperatureDelta> TEMPERATURE_DELTA_MIN;
   }
 
   public static final class SkinTemperatureRecord.Companion {
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/records/ResponseConvertersTest.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/records/ResponseConvertersTest.kt
index a4fed6d..9e1112b 100644
--- a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/records/ResponseConvertersTest.kt
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/records/ResponseConvertersTest.kt
@@ -16,6 +16,7 @@
 
 package androidx.health.connect.client.impl.platform.records
 
+import android.annotation.SuppressLint
 import android.annotation.TargetApi
 import android.health.connect.datatypes.units.Energy as PlatformEnergy
 import android.health.connect.datatypes.units.Length as PlatformLength
@@ -37,6 +38,7 @@
 import androidx.health.connect.client.records.HydrationRecord
 import androidx.health.connect.client.records.NutritionRecord
 import androidx.health.connect.client.records.PowerRecord
+import androidx.health.connect.client.records.SkinTemperatureRecord
 import androidx.health.connect.client.records.SpeedRecord
 import androidx.health.connect.client.records.WeightRecord
 import androidx.health.connect.client.records.metadata.DataOrigin
@@ -204,6 +206,21 @@
         assertThat(metricValues).containsExactly(BloodPressureRecord.SYSTOLIC_MAX.metricKey, 120.0)
     }
 
+    @SuppressLint("NewApi") // Api 35 is covered by sdk extension check
+    @Test
+    fun getDoubleMetricValues_convertsTemperatureDeltaToCelsius() {
+        assumeTrue(SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 13)
+        val metricValues =
+            getDoubleMetricValues(
+                mapOf(
+                    SkinTemperatureRecord.TEMPERATURE_DELTA_AVG as AggregateMetric<Any> to
+                        PlatformTemperatureDelta.fromCelsius(25.0)
+                )
+            )
+        assertThat(metricValues)
+            .containsExactly(SkinTemperatureRecord.TEMPERATURE_DELTA_AVG.metricKey, 25.0)
+    }
+
     @Test
     fun getDoubleMetricValues_convertsVelocityToMetersPerSecond() {
         assumeTrue(SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 10)
@@ -290,6 +307,7 @@
                         PlatformEnergy.fromCalories(836_800.0),
                 )
             )
+
         assertThat(metricValues)
             .comparingValuesUsing(tolerance)
             .containsExactly(
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/AggregationMappings.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/AggregationMappings.kt
index 1cc7a38..1b725cf 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/AggregationMappings.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/AggregationMappings.kt
@@ -19,6 +19,7 @@
 
 package androidx.health.connect.client.impl.platform.aggregate
 
+import android.annotation.SuppressLint
 import android.health.connect.datatypes.ActiveCaloriesBurnedRecord as PlatformActiveCaloriesBurnedRecord
 import android.health.connect.datatypes.AggregationType as PlatformAggregateMetric
 import android.health.connect.datatypes.BasalMetabolicRateRecord as PlatformBasalMetabolicRateRecord
@@ -49,6 +50,7 @@
 import androidx.health.connect.client.impl.platform.records.PlatformExerciseSessionRecord
 import androidx.health.connect.client.impl.platform.records.PlatformPressure
 import androidx.health.connect.client.impl.platform.records.PlatformRestingHeartRateRecord
+import androidx.health.connect.client.impl.platform.records.PlatformSkinTemperatureRecord
 import androidx.health.connect.client.impl.platform.records.PlatformSleepSessionRecord
 import androidx.health.connect.client.impl.platform.records.PlatformSpeedRecord
 import androidx.health.connect.client.impl.platform.records.PlatformStepsCadenceRecord
@@ -67,6 +69,7 @@
 import androidx.health.connect.client.records.NutritionRecord
 import androidx.health.connect.client.records.PowerRecord
 import androidx.health.connect.client.records.RestingHeartRateRecord
+import androidx.health.connect.client.records.SkinTemperatureRecord
 import androidx.health.connect.client.records.SleepSessionRecord
 import androidx.health.connect.client.records.SpeedRecord
 import androidx.health.connect.client.records.StepsCadenceRecord
@@ -79,6 +82,7 @@
 import androidx.health.connect.client.units.Mass
 import androidx.health.connect.client.units.Power
 import androidx.health.connect.client.units.Pressure
+import androidx.health.connect.client.units.TemperatureDelta
 import androidx.health.connect.client.units.Velocity
 import androidx.health.connect.client.units.Volume
 import java.time.Duration
@@ -235,6 +239,23 @@
         }
         .toMap()
 
+@SuppressLint("NewApi") // API 35 is covered by sdk extension check
+internal val TEMPERATURE_DELTA_METRIC_TYPE_MAP:
+    Map<AggregateMetric<TemperatureDelta>, PlatformAggregateMetric<*>> =
+    if (SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 13) {
+            arrayOf(
+                SkinTemperatureRecord.TEMPERATURE_DELTA_AVG to
+                    PlatformSkinTemperatureRecord.SKIN_TEMPERATURE_DELTA_AVG,
+                SkinTemperatureRecord.TEMPERATURE_DELTA_MAX to
+                    PlatformSkinTemperatureRecord.SKIN_TEMPERATURE_DELTA_MAX,
+                SkinTemperatureRecord.TEMPERATURE_DELTA_MIN to
+                    PlatformSkinTemperatureRecord.SKIN_TEMPERATURE_DELTA_MIN
+            )
+        } else {
+            emptyArray()
+        }
+        .toMap()
+
 internal val VELOCITY_AGGREGATION_METRIC_TYPE_MAP:
     Map<AggregateMetric<Velocity>, PlatformAggregateMetric<PlatformVelocity>> =
     if (SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 10) {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/request/RequestConverters.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/request/RequestConverters.kt
index f2966dd..b12909e 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/request/RequestConverters.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/request/RequestConverters.kt
@@ -39,6 +39,7 @@
 import androidx.health.connect.client.impl.platform.aggregate.LONG_AGGREGATION_METRIC_TYPE_MAP
 import androidx.health.connect.client.impl.platform.aggregate.POWER_AGGREGATION_METRIC_TYPE_MAP
 import androidx.health.connect.client.impl.platform.aggregate.PRESSURE_AGGREGATION_METRIC_TYPE_MAP
+import androidx.health.connect.client.impl.platform.aggregate.TEMPERATURE_DELTA_METRIC_TYPE_MAP
 import androidx.health.connect.client.impl.platform.aggregate.VELOCITY_AGGREGATION_METRIC_TYPE_MAP
 import androidx.health.connect.client.impl.platform.aggregate.VOLUME_AGGREGATION_METRIC_TYPE_MAP
 import androidx.health.connect.client.impl.platform.aggregate.platformMetrics
@@ -149,6 +150,7 @@
         ?: KILOGRAMS_AGGREGATION_METRIC_TYPE_MAP[this] as AggregationType<Any>?
         ?: POWER_AGGREGATION_METRIC_TYPE_MAP[this] as AggregationType<Any>?
         ?: PRESSURE_AGGREGATION_METRIC_TYPE_MAP[this] as AggregationType<Any>?
+        ?: TEMPERATURE_DELTA_METRIC_TYPE_MAP[this] as AggregationType<Any>?
         ?: VELOCITY_AGGREGATION_METRIC_TYPE_MAP[this] as AggregationType<Any>?
         ?: VOLUME_AGGREGATION_METRIC_TYPE_MAP[this] as AggregationType<Any>?
         ?: throw IllegalArgumentException("Unsupported aggregation type $metricKey")
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/response/ResponseConverters.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/response/ResponseConverters.kt
index 07c77a4..e23a08e 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/response/ResponseConverters.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/response/ResponseConverters.kt
@@ -19,12 +19,15 @@
 
 package androidx.health.connect.client.impl.platform.response
 
+import android.annotation.SuppressLint
 import android.health.connect.AggregateRecordsGroupedByDurationResponse
 import android.health.connect.AggregateRecordsGroupedByPeriodResponse
 import android.health.connect.AggregateRecordsResponse
 import android.health.connect.datatypes.AggregationType
 import android.health.connect.datatypes.units.Energy as PlatformEnergy
 import android.health.connect.datatypes.units.Volume as PlatformVolume
+import android.os.Build
+import android.os.ext.SdkExtensions
 import androidx.annotation.RequiresApi
 import androidx.annotation.RestrictTo
 import androidx.annotation.VisibleForTesting
@@ -41,6 +44,7 @@
 import androidx.health.connect.client.impl.platform.aggregate.LONG_AGGREGATION_METRIC_TYPE_MAP
 import androidx.health.connect.client.impl.platform.aggregate.POWER_AGGREGATION_METRIC_TYPE_MAP
 import androidx.health.connect.client.impl.platform.aggregate.PRESSURE_AGGREGATION_METRIC_TYPE_MAP
+import androidx.health.connect.client.impl.platform.aggregate.TEMPERATURE_DELTA_METRIC_TYPE_MAP
 import androidx.health.connect.client.impl.platform.aggregate.VELOCITY_AGGREGATION_METRIC_TYPE_MAP
 import androidx.health.connect.client.impl.platform.aggregate.VOLUME_AGGREGATION_METRIC_TYPE_MAP
 import androidx.health.connect.client.impl.platform.records.PlatformDataOrigin
@@ -48,6 +52,7 @@
 import androidx.health.connect.client.impl.platform.records.PlatformMass
 import androidx.health.connect.client.impl.platform.records.PlatformPower
 import androidx.health.connect.client.impl.platform.records.PlatformPressure
+import androidx.health.connect.client.impl.platform.records.PlatformTemperatureDelta
 import androidx.health.connect.client.impl.platform.records.PlatformVelocity
 import androidx.health.connect.client.impl.platform.records.toSdkDataOrigin
 import androidx.health.connect.client.impl.platform.request.toAggregationType
@@ -126,6 +131,7 @@
     }
 }
 
+@SuppressLint("NewApi") // Api 35 covered by sdk extension check
 @VisibleForTesting
 internal fun getDoubleMetricValues(
     metricValueMap: Map<AggregateMetric<Any>, Any>
@@ -155,6 +161,13 @@
                 in POWER_AGGREGATION_METRIC_TYPE_MAP -> {
                     this[key.metricKey] = (value as PlatformPower).inWatts
                 }
+                in TEMPERATURE_DELTA_METRIC_TYPE_MAP -> {
+                    require(
+                        SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >=
+                            13
+                    )
+                    this[key.metricKey] = (value as PlatformTemperatureDelta).inCelsius
+                }
                 in VELOCITY_AGGREGATION_METRIC_TYPE_MAP -> {
                     this[key.metricKey] = (value as PlatformVelocity).inMetersPerSecond
                 }
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/records/SkinTemperatureRecord.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/records/SkinTemperatureRecord.kt
index 1c3d1ae..31dafc7 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/records/SkinTemperatureRecord.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/records/SkinTemperatureRecord.kt
@@ -18,6 +18,11 @@
 import androidx.annotation.IntDef
 import androidx.annotation.RestrictTo
 import androidx.health.connect.client.HealthConnectFeatures
+import androidx.health.connect.client.aggregate.AggregateMetric
+import androidx.health.connect.client.aggregate.AggregateMetric.AggregationType.AVERAGE
+import androidx.health.connect.client.aggregate.AggregateMetric.AggregationType.MAXIMUM
+import androidx.health.connect.client.aggregate.AggregateMetric.AggregationType.MINIMUM
+import androidx.health.connect.client.aggregate.AggregateMetric.Companion.doubleMetric
 import androidx.health.connect.client.records.metadata.Metadata
 import androidx.health.connect.client.units.Temperature
 import androidx.health.connect.client.units.TemperatureDelta
@@ -118,9 +123,57 @@
     }
 
     companion object {
+
+        private const val SKIN_TEMPERATURE_TYPE_NAME = "SkinTemperature"
+        private const val TEMPERATURE_DELTA_FIELD_NAME = "temperatureDelta"
         private val MIN_TEMPERATURE = 0.celsius
         private val MAX_TEMPERATURE = 100.celsius
 
+        /**
+         * Metric identifier for retrieving the average skin temperature delta from
+         * [androidx.health.connect.client.aggregate.AggregationResult]. To check if this metric is
+         * available, use [HealthConnectFeatures.getFeatureStatus] with
+         * [HealthConnectFeatures.FEATURE_SKIN_TEMPERATURE] as the argument.
+         */
+        @JvmField
+        val TEMPERATURE_DELTA_AVG: AggregateMetric<TemperatureDelta> =
+            doubleMetric(
+                SKIN_TEMPERATURE_TYPE_NAME,
+                AVERAGE,
+                TEMPERATURE_DELTA_FIELD_NAME,
+                TemperatureDelta::celsius
+            )
+
+        /**
+         * Metric identifier for retrieving the minimum skin temperature delta from
+         * [androidx.health.connect.client.aggregate.AggregationResult]. To check if this metric is
+         * available, use [HealthConnectFeatures.getFeatureStatus] with
+         * [HealthConnectFeatures.FEATURE_SKIN_TEMPERATURE] as the argument.
+         */
+        @JvmField
+        val TEMPERATURE_DELTA_MIN: AggregateMetric<TemperatureDelta> =
+            doubleMetric(
+                SKIN_TEMPERATURE_TYPE_NAME,
+                MINIMUM,
+                TEMPERATURE_DELTA_FIELD_NAME,
+                TemperatureDelta::celsius
+            )
+
+        /**
+         * Metric identifier for retrieving the maximum skin temperature delta from
+         * [androidx.health.connect.client.aggregate.AggregationResult]. To check if this metric is
+         * available, use [HealthConnectFeatures.getFeatureStatus] with
+         * [HealthConnectFeatures.FEATURE_SKIN_TEMPERATURE] as the argument.
+         */
+        @JvmField
+        val TEMPERATURE_DELTA_MAX: AggregateMetric<TemperatureDelta> =
+            doubleMetric(
+                SKIN_TEMPERATURE_TYPE_NAME,
+                MAXIMUM,
+                TEMPERATURE_DELTA_FIELD_NAME,
+                TemperatureDelta::celsius
+            )
+
         /** Use this if the location is unknown. */
         const val MEASUREMENT_LOCATION_UNKNOWN: Int = 0
         /** Skin temperature measurement was taken from finger. */