Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 5 more health connect sensors #4836

Merged
merged 3 commits into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/src/full/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,25 @@
<uses-permission android:name="com.google.android.gms.permission.CAR_MILEAGE" />
<uses-permission android:name="com.google.android.gms.permission.CAR_SPEED" />
<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_WATER_MASS" />
<uses-permission android:name="android.permission.health.READ_BODY_TEMPERATURE" />
<uses-permission android:name="android.permission.health.READ_BONE_MASS" />
<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_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_HYDRATION" />
<uses-permission android:name="android.permission.health.READ_LEAN_BODY_MASS" />
<uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION" />
<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_SLEEP" />
<uses-permission android:name="android.permission.health.READ_STEPS" />
<uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,28 @@ import androidx.health.connect.client.aggregate.AggregateMetric
import androidx.health.connect.client.aggregate.AggregationResult
import androidx.health.connect.client.permission.HealthPermission
import androidx.health.connect.client.records.ActiveCaloriesBurnedRecord
import androidx.health.connect.client.records.BasalBodyTemperatureRecord
import androidx.health.connect.client.records.BasalMetabolicRateRecord
import androidx.health.connect.client.records.BloodGlucoseRecord
import androidx.health.connect.client.records.BloodPressureRecord
import androidx.health.connect.client.records.BodyFatRecord
import androidx.health.connect.client.records.BodyTemperatureMeasurementLocation
import androidx.health.connect.client.records.BodyTemperatureRecord
import androidx.health.connect.client.records.BodyWaterMassRecord
import androidx.health.connect.client.records.BoneMassRecord
import androidx.health.connect.client.records.DistanceRecord
import androidx.health.connect.client.records.ElevationGainedRecord
import androidx.health.connect.client.records.FloorsClimbedRecord
import androidx.health.connect.client.records.HeartRateRecord
import androidx.health.connect.client.records.HeartRateVariabilityRmssdRecord
import androidx.health.connect.client.records.HeightRecord
import androidx.health.connect.client.records.HydrationRecord
import androidx.health.connect.client.records.LeanBodyMassRecord
import androidx.health.connect.client.records.MealType
import androidx.health.connect.client.records.OxygenSaturationRecord
import androidx.health.connect.client.records.Record
import androidx.health.connect.client.records.RespiratoryRateRecord
import androidx.health.connect.client.records.RestingHeartRateRecord
import androidx.health.connect.client.records.SleepSessionRecord
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.records.TotalCaloriesBurnedRecord
Expand Down Expand Up @@ -70,6 +75,17 @@ class HealthConnectSensorManager : SensorManager {
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val basalBodyTemperature = SensorManager.BasicSensor(
id = "health_connect_basal_body_temperature",
type = "sensor",
commonR.string.basic_sensor_name_basal_body_temperature,
commonR.string.sensor_description_basal_body_temperature,
"mdi:thermometer",
deviceClass = "temperature",
unitOfMeasurement = "°C",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val basalMetabolicRate = SensorManager.BasicSensor(
id = "health_connect_basal_metabolic_rate",
type = "sensor",
Expand Down Expand Up @@ -101,6 +117,17 @@ class HealthConnectSensorManager : SensorManager {
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val bodyWaterMass = SensorManager.BasicSensor(
id = "health_connect_body_water_mass",
type = "sensor",
commonR.string.basic_sensor_name_body_water_mass,
commonR.string.sensor_description_body_water_mass,
"mdi:water",
deviceClass = "weight",
unitOfMeasurement = "g",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val bodyTemperature = SensorManager.BasicSensor(
id = "health_connect_body_temperature",
type = "sensor",
Expand Down Expand Up @@ -179,6 +206,17 @@ class HealthConnectSensorManager : SensorManager {
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val heartRateVariability = SensorManager.BasicSensor(
id = "health_connect_heart_rate_variability",
type = "sensor",
commonR.string.basic_sensor_name_heart_rate_variability,
commonR.string.sensor_description_heart_rate_variability,
"mdi:heart-pulse",
deviceClass = "duration",
unitOfMeasurement = "ms",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val height = SensorManager.BasicSensor(
id = "health_connect_height",
type = "sensor",
Expand All @@ -190,6 +228,18 @@ class HealthConnectSensorManager : SensorManager {
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val hydration = SensorManager.BasicSensor(
id = "health_connect_hydration",
type = "sensor",
commonR.string.basic_sensor_name_hydration,
commonR.string.sensor_description_hydration,
"mdi:cup-water",
unitOfMeasurement = "ml",
deviceClass = "volume",
stateClass = SensorManager.STATE_CLASS_TOTAL_INCREASING,
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val leanBodyMass = SensorManager.BasicSensor(
id = "health_connect_lean_body_mass",
type = "sensor",
Expand Down Expand Up @@ -221,6 +271,16 @@ class HealthConnectSensorManager : SensorManager {
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val restingHeartRate = SensorManager.BasicSensor(
id = "health_connect_resting_heart_rate",
type = "sensor",
commonR.string.basic_sensor_name_resting_heart_rate,
commonR.string.sensor_description_resting_heart_rate,
"mdi:heart-pulse",
unitOfMeasurement = "bpm",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val sleepDuration = SensorManager.BasicSensor(
id = "health_connect_sleep_duration",
type = "sensor",
Expand Down Expand Up @@ -295,20 +355,25 @@ class HealthConnectSensorManager : SensorManager {
return try {
when {
(sensorId == activeCaloriesBurned.id) -> arrayOf(HealthPermission.getReadPermission(ActiveCaloriesBurnedRecord::class))
(sensorId == basalBodyTemperature.id) -> arrayOf(HealthPermission.getReadPermission(BasalBodyTemperatureRecord::class))
(sensorId == basalMetabolicRate.id) -> arrayOf(HealthPermission.getReadPermission(BasalMetabolicRateRecord::class))
(sensorId == bloodGlucose.id) -> arrayOf(HealthPermission.getReadPermission(BloodGlucoseRecord::class))
(sensorId == bodyFat.id) -> arrayOf(HealthPermission.getReadPermission(BodyFatRecord::class))
(sensorId == bodyWaterMass.id) -> arrayOf(HealthPermission.getReadPermission(BodyWaterMassRecord::class))
(sensorId == bodyTemperature.id) -> arrayOf(HealthPermission.getReadPermission(BodyTemperatureRecord::class))
(sensorId == boneMass.id) -> arrayOf(HealthPermission.getReadPermission(BoneMassRecord::class))
(sensorId == diastolicBloodPressure.id) -> arrayOf(HealthPermission.getReadPermission(BloodPressureRecord::class))
(sensorId == distance.id) -> arrayOf(HealthPermission.getReadPermission(DistanceRecord::class))
(sensorId == elevationGained.id) -> arrayOf(HealthPermission.getReadPermission(ElevationGainedRecord::class))
(sensorId == floorsClimbed.id) -> arrayOf(HealthPermission.getReadPermission(FloorsClimbedRecord::class))
(sensorId == heartRate.id) -> arrayOf(HealthPermission.getReadPermission(HeartRateRecord::class))
(sensorId == heartRateVariability.id) -> arrayOf(HealthPermission.getReadPermission(HeartRateVariabilityRmssdRecord::class))
(sensorId == height.id) -> arrayOf(HealthPermission.getReadPermission(HeightRecord::class))
(sensorId == hydration.id) -> arrayOf(HealthPermission.getReadPermission(HydrationRecord::class))
(sensorId == leanBodyMass.id) -> arrayOf(HealthPermission.getReadPermission(LeanBodyMassRecord::class))
(sensorId == oxygenSaturation.id) -> arrayOf(HealthPermission.getReadPermission(OxygenSaturationRecord::class))
(sensorId == respiratoryRate.id) -> arrayOf(HealthPermission.getReadPermission(RespiratoryRateRecord::class))
(sensorId == restingHeartRate.id) -> arrayOf(HealthPermission.getReadPermission(RestingHeartRateRecord::class))
(sensorId == sleepDuration.id) -> arrayOf(HealthPermission.getReadPermission(SleepSessionRecord::class))
(sensorId == steps.id) -> arrayOf(HealthPermission.getReadPermission(StepsRecord::class))
(sensorId == systolicBloodPressure.id) -> arrayOf(HealthPermission.getReadPermission(BloodPressureRecord::class))
Expand All @@ -327,6 +392,9 @@ class HealthConnectSensorManager : SensorManager {
if (isEnabled(context, activeCaloriesBurned)) {
updateActiveCaloriesBurnedSensor(context)
}
if (isEnabled(context, basalBodyTemperature)) {
updateBasalBodyTemperatureSensor(context)
}
if (isEnabled(context, basalMetabolicRate)) {
updateBasalMetabolicRateSensor(context)
}
Expand All @@ -336,6 +404,9 @@ class HealthConnectSensorManager : SensorManager {
if (isEnabled(context, bodyFat)) {
updateBodyFatSensor(context)
}
if (isEnabled(context, bodyWaterMass)) {
updateBodyWaterMassSensor(context)
}
if (isEnabled(context, bodyTemperature)) {
updateBodyTemperatureSensor(context)
}
Expand All @@ -357,9 +428,15 @@ class HealthConnectSensorManager : SensorManager {
if (isEnabled(context, heartRate)) {
updateHeartRateSensor(context)
}
if (isEnabled(context, heartRateVariability)) {
updateHeartRateVariabilitySensor(context)
}
if (isEnabled(context, height)) {
updateHeightSensor(context)
}
if (isEnabled(context, hydration)) {
updateHydrationSensor(context)
}
if (isEnabled(context, leanBodyMass)) {
updateLeanBodyMassSensor(context)
}
Expand All @@ -369,6 +446,9 @@ class HealthConnectSensorManager : SensorManager {
if (isEnabled(context, respiratoryRate)) {
updateRespiratoryRateSensor(context)
}
if (isEnabled(context, restingHeartRate)) {
updateRestingHeartRateSensor(context)
}
if (isEnabled(context, sleepDuration)) {
updateSleepDurationSensor(context)
}
Expand Down Expand Up @@ -408,6 +488,25 @@ class HealthConnectSensorManager : SensorManager {
)
}

private suspend fun updateBasalBodyTemperatureSensor(context: Context) {
val healthConnectClient = getOrCreateHealthConnectClient(context) ?: return
val basalBodyTemperatureRequest = buildReadRecordsRequest(BasalBodyTemperatureRecord::class) as ReadRecordsRequest<BasalBodyTemperatureRecord>
val response = healthConnectClient.readRecordsOrNull(basalBodyTemperatureRequest)
if (response == null || response.records.isEmpty()) {
return
}
onSensorUpdated(
context,
basalBodyTemperature,
response.records.last().temperature.inCelsius,
basalBodyTemperature.statelessIcon,
attributes = mapOf(
"date" to response.records.last().time,
"source" to response.records.last().metadata.dataOrigin.packageName
)
)
}

private suspend fun updateBasalMetabolicRateSensor(context: Context) {
val healthConnectClient = getOrCreateHealthConnectClient(context) ?: return
val basalMetabolicRateRequest = buildReadRecordsRequest(BasalMetabolicRateRecord::class) as ReadRecordsRequest<BasalMetabolicRateRecord>
Expand Down Expand Up @@ -489,6 +588,25 @@ class HealthConnectSensorManager : SensorManager {
)
}

private suspend fun updateBodyWaterMassSensor(context: Context) {
val healthConnectClient = getOrCreateHealthConnectClient(context) ?: return
val bodyWaterMassRequest = buildReadRecordsRequest(BodyWaterMassRecord::class) as ReadRecordsRequest<BodyWaterMassRecord>
val response = healthConnectClient.readRecordsOrNull(bodyWaterMassRequest)
if (response == null || response.records.isEmpty()) {
return
}
onSensorUpdated(
context,
bodyWaterMass,
response.records.last().mass.inGrams,
bodyWaterMass.statelessIcon,
attributes = mapOf(
"date" to response.records.last().time,
"source" to response.records.last().metadata.dataOrigin.packageName
)
)
}

private suspend fun updateBodyTemperatureSensor(context: Context) {
val healthConnectClient = getOrCreateHealthConnectClient(context) ?: return
val bodyTemperatureRequest = buildReadRecordsRequest(BodyTemperatureRecord::class) as ReadRecordsRequest<BodyTemperatureRecord>
Expand Down Expand Up @@ -586,6 +704,25 @@ class HealthConnectSensorManager : SensorManager {
)
}

private suspend fun updateHeartRateVariabilitySensor(context: Context) {
val healthConnectClient = getOrCreateHealthConnectClient(context) ?: return
val heartRateVariabilityRequest = buildReadRecordsRequest(HeartRateVariabilityRmssdRecord::class) as ReadRecordsRequest<HeartRateVariabilityRmssdRecord>
val response = healthConnectClient.readRecordsOrNull(heartRateVariabilityRequest)
if (response == null || response.records.isEmpty()) {
return
}
onSensorUpdated(
context,
heartRateVariability,
response.records.last().heartRateVariabilityMillis,
heartRateVariability.statelessIcon,
attributes = mapOf(
"date" to response.records.last().time,
"source" to response.records.last().metadata.dataOrigin.packageName
)
)
}

private suspend fun updateHeightSensor(context: Context) {
val healthConnectClient = getOrCreateHealthConnectClient(context) ?: return
val heightRequest = buildReadRecordsRequest(HeightRecord::class) as ReadRecordsRequest<HeightRecord>
Expand All @@ -605,6 +742,19 @@ class HealthConnectSensorManager : SensorManager {
)
}

private suspend fun updateHydrationSensor(context: Context) {
val healthConnectClient = getOrCreateHealthConnectClient(context) ?: return
val hydrationRequest = healthConnectClient.aggregateOrNull(buildAggregationRequest(HydrationRecord.VOLUME_TOTAL)) ?: return
val hydrationTotal = hydrationRequest[HydrationRecord.VOLUME_TOTAL]?.inMilliliters ?: 0
onSensorUpdated(
context,
hydration,
hydrationTotal,
hydration.statelessIcon,
attributes = buildAggregationAttributes(hydrationRequest)
)
}

private suspend fun updateLeanBodyMassSensor(context: Context) {
val healthConnectClient = getOrCreateHealthConnectClient(context) ?: return
val leanBodyMassRequest = buildReadRecordsRequest(LeanBodyMassRecord::class) as ReadRecordsRequest<LeanBodyMassRecord>
Expand Down Expand Up @@ -662,6 +812,25 @@ class HealthConnectSensorManager : SensorManager {
)
}

private suspend fun updateRestingHeartRateSensor(context: Context) {
val healthConnectClient = getOrCreateHealthConnectClient(context) ?: return
val restingHeartRateRequest = buildReadRecordsRequest(RestingHeartRateRecord::class) as ReadRecordsRequest<RestingHeartRateRecord>
val response = healthConnectClient.readRecordsOrNull(restingHeartRateRequest)
if (response == null || response.records.isEmpty()) {
return
}
onSensorUpdated(
context,
restingHeartRate,
response.records.last().beatsPerMinute,
restingHeartRate.statelessIcon,
attributes = mapOf(
"date" to response.records.last().time,
"source" to response.records.last().metadata.dataOrigin.packageName
)
)
}

private suspend fun updateSleepDurationSensor(context: Context) {
val healthConnectClient = getOrCreateHealthConnectClient(context) ?: return
val sleepRequest = buildReadRecordsRequest(SleepSessionRecord::class) as ReadRecordsRequest<SleepSessionRecord>
Expand Down Expand Up @@ -758,20 +927,25 @@ class HealthConnectSensorManager : SensorManager {
return if (hasSensor(context)) {
listOf(
activeCaloriesBurned,
basalBodyTemperature,
basalMetabolicRate,
bloodGlucose,
bodyFat,
bodyWaterMass,
bodyTemperature,
boneMass,
diastolicBloodPressure,
distance,
elevationGained,
floorsClimbed,
heartRate,
heartRateVariability,
height,
hydration,
leanBodyMass,
oxygenSaturation,
respiratoryRate,
restingHeartRate,
sleepDuration,
steps,
systolicBloodPressure,
Expand Down
Loading