• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.healthconnect.controller.utils
2 
3 import android.content.Context
4 import android.provider.DeviceConfig
5 import com.android.healthfitness.flags.Flags
6 import dagger.Module
7 import dagger.Provides
8 import dagger.hilt.InstallIn
9 import dagger.hilt.android.qualifiers.ApplicationContext
10 import dagger.hilt.components.SingletonComponent
11 import javax.inject.Singleton
12 
13 interface FeatureUtils {
isSessionTypesEnablednull14     fun isSessionTypesEnabled(): Boolean
15 
16     fun isExerciseRouteReadAllEnabled(): Boolean
17 
18     fun isEntryPointsEnabled(): Boolean
19 
20     fun isNewAppPriorityEnabled(): Boolean
21 
22     fun isNewInformationArchitectureEnabled(): Boolean
23 
24     fun isBackgroundReadEnabled(): Boolean
25 
26     fun isHistoryReadEnabled(): Boolean
27 
28     fun isSkinTemperatureEnabled(): Boolean
29 
30     fun isPlannedExerciseEnabled(): Boolean
31 
32     fun isPersonalHealthRecordEnabled(): Boolean
33 }
34 
35 class FeatureUtilsImpl(context: Context) : FeatureUtils, DeviceConfig.OnPropertiesChangedListener {
36 
37     companion object {
38         private const val HEALTH_FITNESS_FLAGS_NAMESPACE = DeviceConfig.NAMESPACE_HEALTH_FITNESS
39         private const val PROPERTY_EXERCISE_ROUTE_ENABLED = "exercise_routes_enable"
40         private const val PROPERTY_EXERCISE_ROUTE_READ_ALL_ENABLED =
41             "exercise_routes_read_all_enable"
42         private const val PROPERTY_SESSIONS_TYPE_ENABLED = "session_types_enable"
43         private const val PROPERTY_ENTRY_POINTS_ENABLED = "entry_points_enable"
44         private const val PROPERTY_AGGREGATION_SOURCE_CONTROL_ENABLED =
45             "aggregation_source_controls_enable"
46         private const val PROPERTY_NEW_INFORMATION_ARCHITECTURE_ENABLED =
47             "new_information_architecture_enable"
48         private const val PROPERTY_PERSONAL_HEALTH_RECORD_ENABLED = "personal_health_record_enable"
49     }
50 
51     private val lock = Any()
52 
53     init {
54         DeviceConfig.addOnPropertiesChangedListener(
55             HEALTH_FITNESS_FLAGS_NAMESPACE, context.mainExecutor, this)
56     }
57 
58     private var isSessionTypesEnabled =
59         DeviceConfig.getBoolean(
60             HEALTH_FITNESS_FLAGS_NAMESPACE, PROPERTY_SESSIONS_TYPE_ENABLED, true)
61 
62     private var isExerciseRouteReadAllEnabled = true
63 
64     private var isEntryPointsEnabled =
65         DeviceConfig.getBoolean(HEALTH_FITNESS_FLAGS_NAMESPACE, PROPERTY_ENTRY_POINTS_ENABLED, true)
66 
67     private var isNewAppPriorityEnabled = true
68 
69     private var isNewInformationArchitectureEnabled =
70         DeviceConfig.getBoolean(
71             HEALTH_FITNESS_FLAGS_NAMESPACE, PROPERTY_NEW_INFORMATION_ARCHITECTURE_ENABLED, false)
72 
73     private var isPersonalHealthRecordEnabled = Flags.personalHealthRecord()
74 
75     override fun isNewAppPriorityEnabled(): Boolean {
76         synchronized(lock) {
77             return isNewAppPriorityEnabled
78         }
79     }
80 
81     override fun isNewInformationArchitectureEnabled(): Boolean {
82         synchronized(lock) {
83             return isNewInformationArchitectureEnabled
84         }
85     }
86 
87     override fun isSessionTypesEnabled(): Boolean {
88         synchronized(lock) {
89             return isSessionTypesEnabled
90         }
91     }
92 
93     override fun isExerciseRouteReadAllEnabled(): Boolean {
94         synchronized(lock) {
95             return isExerciseRouteReadAllEnabled
96         }
97     }
98 
99     override fun isEntryPointsEnabled(): Boolean {
100         synchronized(lock) {
101             return isEntryPointsEnabled
102         }
103     }
104 
105     override fun isBackgroundReadEnabled(): Boolean {
106         synchronized(lock) {
107             return true
108         }
109     }
110 
111     override fun isHistoryReadEnabled(): Boolean {
112         synchronized(lock) {
113             return true
114         }
115     }
116 
117     override fun isPlannedExerciseEnabled(): Boolean {
118         synchronized(lock) {
119             return true
120         }
121     }
122 
123     override fun isSkinTemperatureEnabled(): Boolean {
124         synchronized(lock) {
125             return true
126         }
127     }
128 
129     override fun isPersonalHealthRecordEnabled(): Boolean {
130         synchronized(lock) {
131             return isPersonalHealthRecordEnabled
132         }
133     }
134 
135     override fun onPropertiesChanged(properties: DeviceConfig.Properties) {
136         synchronized(lock) {
137             if (!properties.namespace.equals(HEALTH_FITNESS_FLAGS_NAMESPACE)) {
138                 return
139             }
140 
141             for (name in properties.keyset) {
142                 when (name) {
143                     PROPERTY_EXERCISE_ROUTE_READ_ALL_ENABLED -> {
144                         isExerciseRouteReadAllEnabled =
145                             properties.getBoolean(PROPERTY_EXERCISE_ROUTE_READ_ALL_ENABLED, true)
146                     }
147                     PROPERTY_SESSIONS_TYPE_ENABLED ->
148                         isSessionTypesEnabled =
149                             properties.getBoolean(PROPERTY_SESSIONS_TYPE_ENABLED, true)
150                     PROPERTY_ENTRY_POINTS_ENABLED ->
151                         isEntryPointsEnabled =
152                             properties.getBoolean(PROPERTY_ENTRY_POINTS_ENABLED, true)
153                     PROPERTY_AGGREGATION_SOURCE_CONTROL_ENABLED -> isNewAppPriorityEnabled = true
154                     PROPERTY_NEW_INFORMATION_ARCHITECTURE_ENABLED ->
155                         isNewInformationArchitectureEnabled =
156                             properties.getBoolean(
157                                 PROPERTY_NEW_INFORMATION_ARCHITECTURE_ENABLED, false)
158                     PROPERTY_PERSONAL_HEALTH_RECORD_ENABLED ->
159                         properties.getBoolean(PROPERTY_PERSONAL_HEALTH_RECORD_ENABLED, false)
160                 }
161             }
162         }
163     }
164 }
165 
166 @Module
167 @InstallIn(SingletonComponent::class)
168 class FeaturesModule {
169     @Provides
170     @Singleton
providesFeatureUtilsnull171     fun providesFeatureUtils(@ApplicationContext context: Context): FeatureUtils {
172         return FeatureUtilsImpl(context)
173     }
174 }
175