1 /** 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * ``` 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * ``` 10 * 11 * Unless required by applicable law or agreed to in writing, software distributed under the License 12 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 * or implied. See the License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.android.healthconnect.controller.shared 17 18 import android.content.Context 19 import android.graphics.drawable.Drawable 20 import android.health.connect.HealthDataCategory 21 import androidx.annotation.StringRes 22 import com.android.healthconnect.controller.R 23 import com.android.healthconnect.controller.permissions.data.HealthPermissionType 24 import com.android.healthconnect.controller.shared.CategoriesMappers.ACTIVITY_PERMISSION_GROUPS 25 import com.android.healthconnect.controller.shared.CategoriesMappers.BODY_MEASUREMENTS_PERMISSION_GROUPS 26 import com.android.healthconnect.controller.shared.CategoriesMappers.CYCLE_TRACKING_PERMISSION_GROUPS 27 import com.android.healthconnect.controller.shared.CategoriesMappers.NUTRITION_PERMISSION_GROUPS 28 import com.android.healthconnect.controller.shared.CategoriesMappers.SLEEP_PERMISSION_GROUPS 29 import com.android.healthconnect.controller.shared.CategoriesMappers.VITALS_PERMISSION_GROUPS 30 import com.android.healthconnect.controller.utils.AttributeResolver 31 32 object HealthDataCategoryExtensions { healthPermissionTypesnull33 fun @receiver:HealthDataCategoryInt Int.healthPermissionTypes(): List<HealthPermissionType> { 34 return when (this) { 35 HealthDataCategory.ACTIVITY -> ACTIVITY_PERMISSION_GROUPS 36 HealthDataCategory.BODY_MEASUREMENTS -> BODY_MEASUREMENTS_PERMISSION_GROUPS 37 HealthDataCategory.CYCLE_TRACKING -> CYCLE_TRACKING_PERMISSION_GROUPS 38 HealthDataCategory.NUTRITION -> NUTRITION_PERMISSION_GROUPS 39 HealthDataCategory.SLEEP -> SLEEP_PERMISSION_GROUPS 40 HealthDataCategory.VITALS -> VITALS_PERMISSION_GROUPS 41 else -> throw IllegalArgumentException("Category $this is not supported.") 42 } 43 } 44 45 @StringRes lowercaseTitlenull46 fun @receiver:HealthDataCategoryInt Int.lowercaseTitle(): Int { 47 return when (this) { 48 HealthDataCategory.ACTIVITY -> R.string.activity_category_lowercase 49 HealthDataCategory.BODY_MEASUREMENTS -> R.string.body_measurements_category_lowercase 50 HealthDataCategory.CYCLE_TRACKING -> R.string.cycle_tracking_category_lowercase 51 HealthDataCategory.NUTRITION -> R.string.nutrition_category_lowercase 52 HealthDataCategory.SLEEP -> R.string.sleep_category_lowercase 53 HealthDataCategory.VITALS -> R.string.vitals_category_lowercase 54 else -> throw IllegalArgumentException("Category $this is not supported.") 55 } 56 } 57 58 @StringRes uppercaseTitlenull59 fun @receiver:HealthDataCategoryInt Int.uppercaseTitle(): Int { 60 return when (this) { 61 HealthDataCategory.ACTIVITY -> R.string.activity_category_uppercase 62 HealthDataCategory.BODY_MEASUREMENTS -> R.string.body_measurements_category_uppercase 63 HealthDataCategory.CYCLE_TRACKING -> R.string.cycle_tracking_category_uppercase 64 HealthDataCategory.NUTRITION -> R.string.nutrition_category_uppercase 65 HealthDataCategory.SLEEP -> R.string.sleep_category_uppercase 66 HealthDataCategory.VITALS -> R.string.vitals_category_uppercase 67 else -> throw IllegalArgumentException("Category $this is not supported.") 68 } 69 } 70 iconnull71 fun @receiver:HealthDataCategoryInt Int.icon(context: Context): Drawable? { 72 val attrRes: Int = 73 when (this) { 74 HealthDataCategory.ACTIVITY -> R.attr.activityCategoryIcon 75 HealthDataCategory.BODY_MEASUREMENTS -> R.attr.bodyMeasurementsCategoryIcon 76 HealthDataCategory.CYCLE_TRACKING -> R.attr.cycleTrackingCategoryIcon 77 HealthDataCategory.NUTRITION -> R.attr.nutritionCategoryIcon 78 HealthDataCategory.SLEEP -> R.attr.sleepCategoryIcon 79 HealthDataCategory.VITALS -> R.attr.vitalsCategoryIcon 80 else -> throw IllegalArgumentException("Category $this is not supported.") 81 } 82 return AttributeResolver.getDrawable(context, attrRes) 83 } 84 85 @HealthDataCategoryInt fromHealthPermissionTypenull86 fun fromHealthPermissionType(type: HealthPermissionType): Int { 87 for (category in HEALTH_DATA_CATEGORIES) { 88 if (category.healthPermissionTypes().contains(type)) { 89 return category 90 } 91 } 92 throw IllegalArgumentException("No Category for permission type $type") 93 } 94 } 95 96 /** Permission groups for each {@link HealthDataCategory}. */ 97 private object CategoriesMappers { 98 val ACTIVITY_PERMISSION_GROUPS = 99 listOf( 100 HealthPermissionType.ACTIVE_CALORIES_BURNED, 101 HealthPermissionType.DISTANCE, 102 HealthPermissionType.ELEVATION_GAINED, 103 HealthPermissionType.EXERCISE, 104 HealthPermissionType.EXERCISE_ROUTE, 105 HealthPermissionType.FLOORS_CLIMBED, 106 HealthPermissionType.POWER, 107 HealthPermissionType.SPEED, 108 HealthPermissionType.STEPS, 109 HealthPermissionType.TOTAL_CALORIES_BURNED, 110 HealthPermissionType.VO2_MAX, 111 HealthPermissionType.WHEELCHAIR_PUSHES, 112 HealthPermissionType.PLANNED_EXERCISE, 113 ) 114 115 val BODY_MEASUREMENTS_PERMISSION_GROUPS = 116 listOf( 117 HealthPermissionType.BASAL_METABOLIC_RATE, 118 HealthPermissionType.BODY_FAT, 119 HealthPermissionType.BODY_WATER_MASS, 120 HealthPermissionType.BONE_MASS, 121 HealthPermissionType.HEIGHT, 122 HealthPermissionType.LEAN_BODY_MASS, 123 HealthPermissionType.WEIGHT) 124 125 val CYCLE_TRACKING_PERMISSION_GROUPS = 126 listOf( 127 HealthPermissionType.CERVICAL_MUCUS, 128 HealthPermissionType.INTERMENSTRUAL_BLEEDING, 129 HealthPermissionType.MENSTRUATION, 130 HealthPermissionType.OVULATION_TEST, 131 HealthPermissionType.SEXUAL_ACTIVITY) 132 133 val NUTRITION_PERMISSION_GROUPS = 134 listOf(HealthPermissionType.HYDRATION, HealthPermissionType.NUTRITION) 135 136 val SLEEP_PERMISSION_GROUPS = listOf(HealthPermissionType.SLEEP) 137 138 val VITALS_PERMISSION_GROUPS = 139 listOf( 140 HealthPermissionType.BASAL_BODY_TEMPERATURE, 141 HealthPermissionType.BLOOD_GLUCOSE, 142 HealthPermissionType.BLOOD_PRESSURE, 143 HealthPermissionType.BODY_TEMPERATURE, 144 HealthPermissionType.HEART_RATE, 145 HealthPermissionType.HEART_RATE_VARIABILITY, 146 HealthPermissionType.OXYGEN_SATURATION, 147 HealthPermissionType.RESPIRATORY_RATE, 148 HealthPermissionType.RESTING_HEART_RATE, 149 HealthPermissionType.SKIN_TEMPERATURE) 150 } 151 152 /** List of available Health data categories. */ 153 val HEALTH_DATA_CATEGORIES = 154 listOf( 155 HealthDataCategory.ACTIVITY, 156 HealthDataCategory.BODY_MEASUREMENTS, 157 HealthDataCategory.CYCLE_TRACKING, 158 HealthDataCategory.NUTRITION, 159 HealthDataCategory.SLEEP, 160 HealthDataCategory.VITALS, 161 ) 162 163 /** Denotes that the annotated [Integer] represents a [HealthDataCategory]. */ 164 @Retention(AnnotationRetention.BINARY) 165 @Target( 166 AnnotationTarget.VALUE_PARAMETER, 167 AnnotationTarget.FUNCTION, 168 AnnotationTarget.PROPERTY_GETTER, 169 AnnotationTarget.PROPERTY_SETTER, 170 AnnotationTarget.LOCAL_VARIABLE, 171 AnnotationTarget.FIELD, 172 AnnotationTarget.TYPE) 173 annotation class HealthDataCategoryInt 174