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