@@ -2,33 +2,33 @@ package cachet.plugins.health
22
33import android.util.Log
44import androidx.health.connect.client.HealthConnectClient
5- import androidx.health.connect.client.feature.ExperimentalFeatureAvailabilityApi
65import androidx.health.connect.client.HealthConnectFeatures
6+ import androidx.health.connect.client.feature.ExperimentalFeatureAvailabilityApi
77import androidx.health.connect.client.permission.HealthPermission
88import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_READ_HEALTH_DATA_HISTORY
99import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND
1010import androidx.health.connect.client.time.TimeRangeFilter
1111import io.flutter.plugin.common.MethodCall
1212import io.flutter.plugin.common.MethodChannel.Result
13+ import java.time.Instant
1314import kotlinx.coroutines.CoroutineScope
1415import kotlinx.coroutines.launch
15- import java.time.Instant
1616
1717/* *
18- * Handles Health Connect operational tasks including permissions, SDK status,
19- * and data deletion operations. Manages the administrative aspects of Health Connect integration.
18+ * Handles Health Connect operational tasks including permissions, SDK status, and data deletion
19+ * operations. Manages the administrative aspects of Health Connect integration.
2020 */
2121class HealthDataOperations (
22- private val healthConnectClient : HealthConnectClient ,
23- private val scope : CoroutineScope ,
24- private val healthConnectStatus : Int ,
25- private val healthConnectAvailable : Boolean
22+ private val healthConnectClient : HealthConnectClient ,
23+ private val scope : CoroutineScope ,
24+ private val healthConnectStatus : Int ,
25+ private val healthConnectAvailable : Boolean
2626) {
27-
27+
2828 /* *
29- * Retrieves the current Health Connect SDK availability status.
30- * Returns status codes indicating whether Health Connect is available, needs installation, etc.
31- *
29+ * Retrieves the current Health Connect SDK availability status. Returns status codes indicating
30+ * whether Health Connect is available, needs installation, etc.
31+ *
3232 * @param call Method call from Flutter (unused)
3333 * @param result Flutter result callback to return SDK status integer
3434 */
@@ -37,9 +37,9 @@ class HealthDataOperations(
3737 }
3838
3939 /* *
40- * Checks if the application has been granted the requested health data permissions.
41- * Verifies permission status without triggering permission request dialogs.
42- *
40+ * Checks if the application has been granted the requested health data permissions. Verifies
41+ * permission status without triggering permission request dialogs.
42+ *
4343 * @param call Method call containing 'types' (data types) and 'permissions' (access levels)
4444 * @param result Flutter result callback returning boolean permission status
4545 */
@@ -53,36 +53,38 @@ class HealthDataOperations(
5353 result.success(false )
5454 return
5555 }
56-
56+
5757 scope.launch {
5858 result.success(
59- healthConnectClient
60- .permissionController
61- .getGrantedPermissions()
62- .containsAll(permList),
59+ healthConnectClient
60+ .permissionController
61+ .getGrantedPermissions()
62+ .containsAll(permList),
6363 )
6464 }
6565 }
6666
6767 /* *
68- * Prepares a list of Health Connect permission strings for authorization requests.
69- * Converts Flutter data types and permission levels into Health Connect permission format.
70- *
68+ * Prepares a list of Health Connect permission strings for authorization requests. Converts
69+ * Flutter data types and permission levels into Health Connect permission format.
70+ *
7171 * @param call Method call containing 'types' and 'permissions' arrays
7272 * @return List<String>? List of permission strings, or null if invalid types provided
7373 */
7474 fun preparePermissionsList (call : MethodCall ): List <String >? {
75+ Log .i(" FLUTTER_HEALTH" , " preparePermissionsList" )
76+ Log .i(" FLUTTER_HEALTH" , " call: $call " )
7577 val args = call.arguments as HashMap <* , * >
7678 val types = (args[" types" ] as ? ArrayList <* >)?.filterIsInstance<String >()!!
7779 val permissions = (args[" permissions" ] as ? ArrayList <* >)?.filterIsInstance<Int >()!!
78-
80+
7981 return preparePermissionsListInternal(types, permissions)
8082 }
8183
8284 /* *
83- * Revokes all previously granted Health Connect permissions for this application.
84- * Completely removes app access to Health Connect data.
85- *
85+ * Revokes all previously granted Health Connect permissions for this application. Completely
86+ * removes app access to Health Connect data.
87+ *
8688 * @param call Method call from Flutter (unused)
8789 * @param result Flutter result callback returning success status
8890 */
@@ -95,151 +97,146 @@ class HealthDataOperations(
9597 }
9698
9799 /* *
98- * Checks if the health data history feature is available on the current device.
99- * History feature allows access to data from before the app was installed.
100- *
100+ * Checks if the health data history feature is available on the current device. History feature
101+ * allows access to data from before the app was installed.
102+ *
101103 * @param call Method call from Flutter (unused)
102104 * @param result Flutter result callback returning boolean availability status
103105 */
104106 @OptIn(ExperimentalFeatureAvailabilityApi ::class )
105107 fun isHealthDataHistoryAvailable (call : MethodCall , result : Result ) {
106108 scope.launch {
107109 result.success(
108- healthConnectClient
109- .features
110- .getFeatureStatus(HealthConnectFeatures .FEATURE_READ_HEALTH_DATA_HISTORY ) ==
111- HealthConnectFeatures .FEATURE_STATUS_AVAILABLE
110+ healthConnectClient.features.getFeatureStatus(
111+ HealthConnectFeatures .FEATURE_READ_HEALTH_DATA_HISTORY
112+ ) == HealthConnectFeatures .FEATURE_STATUS_AVAILABLE
112113 )
113114 }
114115 }
115116
116117 /* *
117- * Checks if the health data history permission has been granted.
118- * Verifies if app can access historical health data.
119- *
118+ * Checks if the health data history permission has been granted. Verifies if app can access
119+ * historical health data.
120+ *
120121 * @param call Method call from Flutter (unused)
121122 * @param result Flutter result callback returning boolean authorization status
122123 */
123124 fun isHealthDataHistoryAuthorized (call : MethodCall , result : Result ) {
124125 scope.launch {
125126 result.success(
126- healthConnectClient
127- .permissionController
128- .getGrantedPermissions()
129- .containsAll(listOf (PERMISSION_READ_HEALTH_DATA_HISTORY )),
127+ healthConnectClient
128+ .permissionController
129+ .getGrantedPermissions()
130+ .containsAll(listOf (PERMISSION_READ_HEALTH_DATA_HISTORY )),
130131 )
131132 }
132133 }
133134
134135 /* *
135- * Checks if background health data reading feature is available on device.
136- * Background feature allows data access when app is not in foreground.
137- *
136+ * Checks if background health data reading feature is available on device. Background feature
137+ * allows data access when app is not in foreground.
138+ *
138139 * @param call Method call from Flutter (unused)
139140 * @param result Flutter result callback returning boolean availability status
140141 */
141142 @OptIn(ExperimentalFeatureAvailabilityApi ::class )
142143 fun isHealthDataInBackgroundAvailable (call : MethodCall , result : Result ) {
143144 scope.launch {
144145 result.success(
145- healthConnectClient
146- .features
147- .getFeatureStatus(HealthConnectFeatures .FEATURE_READ_HEALTH_DATA_IN_BACKGROUND ) ==
148- HealthConnectFeatures .FEATURE_STATUS_AVAILABLE
146+ healthConnectClient.features.getFeatureStatus(
147+ HealthConnectFeatures .FEATURE_READ_HEALTH_DATA_IN_BACKGROUND
148+ ) == HealthConnectFeatures .FEATURE_STATUS_AVAILABLE
149149 )
150150 }
151151 }
152152
153153 /* *
154- * Checks if background health data reading permission has been granted.
155- * Verifies if app can access health data in background mode.
156- *
154+ * Checks if background health data reading permission has been granted. Verifies if app can
155+ * access health data in background mode.
156+ *
157157 * @param call Method call from Flutter (unused)
158158 * @param result Flutter result callback returning boolean authorization status
159159 */
160160 fun isHealthDataInBackgroundAuthorized (call : MethodCall , result : Result ) {
161161 scope.launch {
162162 result.success(
163- healthConnectClient
164- .permissionController
165- .getGrantedPermissions()
166- .containsAll(listOf (PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND )),
163+ healthConnectClient
164+ .permissionController
165+ .getGrantedPermissions()
166+ .containsAll(listOf (PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND )),
167167 )
168168 }
169169 }
170170
171171 /* *
172- * Deletes all health records of a specified type within a given time range.
173- * Performs bulk deletion based on data type and time window.
174- *
172+ * Deletes all health records of a specified type within a given time range. Performs bulk
173+ * deletion based on data type and time window.
174+ *
175175 * @param call Method call containing 'dataTypeKey', 'startTime', and 'endTime'
176176 * @param result Flutter result callback returning boolean success status
177177 */
178178 fun deleteData (call : MethodCall , result : Result ) {
179179 val type = call.argument<String >(" dataTypeKey" )!!
180180 val startTime = Instant .ofEpochMilli(call.argument<Long >(" startTime" )!! )
181181 val endTime = Instant .ofEpochMilli(call.argument<Long >(" endTime" )!! )
182-
182+
183183 if (! HealthConstants .mapToType.containsKey(type)) {
184184 Log .w(" FLUTTER_HEALTH::ERROR" , " Datatype $type not found in HC" )
185185 result.success(false )
186186 return
187187 }
188-
188+
189189 val classType = HealthConstants .mapToType[type]!!
190190
191191 scope.launch {
192192 try {
193193 healthConnectClient.deleteRecords(
194- recordType = classType,
195- timeRangeFilter = TimeRangeFilter .between(startTime, endTime),
194+ recordType = classType,
195+ timeRangeFilter = TimeRangeFilter .between(startTime, endTime),
196196 )
197197 result.success(true )
198198 Log .i(
199- " FLUTTER_HEALTH::SUCCESS" ,
200- " Successfully deleted $type records between $startTime and $endTime "
199+ " FLUTTER_HEALTH::SUCCESS" ,
200+ " Successfully deleted $type records between $startTime and $endTime "
201201 )
202202 } catch (e: Exception ) {
203- Log .e(
204- " FLUTTER_HEALTH::ERROR" ,
205- " Error deleting $type records: ${e.message} "
206- )
203+ Log .e(" FLUTTER_HEALTH::ERROR" , " Error deleting $type records: ${e.message} " )
207204 result.success(false )
208205 }
209206 }
210207 }
211208
212209 /* *
213- * Deletes a specific health record by its unique identifier and data type.
214- * Allows precise deletion of individual health records.
215- *
210+ * Deletes a specific health record by its unique identifier and data type. Allows precise
211+ * deletion of individual health records.
212+ *
216213 * @param call Method call containing 'dataTypeKey' and 'uuid'
217214 * @param result Flutter result callback returning boolean success status
218215 */
219216 fun deleteByUUID (call : MethodCall , result : Result ) {
220217 val arguments = call.arguments as ? HashMap <* , * >
221218 val dataTypeKey = (arguments?.get(" dataTypeKey" ) as ? String )!!
222219 val uuid = (arguments?.get(" uuid" ) as ? String )!!
223-
220+
224221 if (! HealthConstants .mapToType.containsKey(dataTypeKey)) {
225222 Log .w(" FLUTTER_HEALTH::ERROR" , " Datatype $dataTypeKey not found in HC" )
226223 result.success(false )
227224 return
228225 }
229-
226+
230227 val classType = HealthConstants .mapToType[dataTypeKey]!!
231-
228+
232229 scope.launch {
233230 try {
234231 healthConnectClient.deleteRecords(
235- recordType = classType,
236- recordIdsList = listOf (uuid),
237- clientRecordIdsList = emptyList()
232+ recordType = classType,
233+ recordIdsList = listOf (uuid),
234+ clientRecordIdsList = emptyList()
238235 )
239236 result.success(true )
240237 Log .i(
241- " FLUTTER_HEALTH::SUCCESS" ,
242- " [Health Connect] Record with UUID $uuid was successfully deleted!"
238+ " FLUTTER_HEALTH::SUCCESS" ,
239+ " [Health Connect] Record with UUID $uuid was successfully deleted!"
243240 )
244241 } catch (e: Exception ) {
245242 Log .e(" FLUTTER_HEALTH::ERROR" , " Error deleting record with UUID: $uuid " )
@@ -251,47 +248,49 @@ class HealthDataOperations(
251248 }
252249
253250 /* *
254- * Internal helper method to prepare Health Connect permission strings.
255- * Converts data type names and access levels into proper permission format.
256- *
251+ * Internal helper method to prepare Health Connect permission strings. Converts data type names
252+ * and access levels into proper permission format.
253+ *
257254 * @param types List of health data type strings
258255 * @param permissions List of permission level integers (0=read, 1=read+write)
259256 * @return List<String>? Formatted permission strings, or null if invalid input
260257 */
261258 private fun preparePermissionsListInternal (
262- types : List <String >,
263- permissions : List <Int >
259+ types : List <String >,
260+ permissions : List <Int >
264261 ): List <String >? {
265262 val permList = mutableListOf<String >()
266-
263+
267264 for ((i, typeKey) in types.withIndex()) {
268265 if (! HealthConstants .mapToType.containsKey(typeKey)) {
269- Log .w(
270- " FLUTTER_HEALTH::ERROR" ,
271- " Datatype $typeKey not found in HC"
272- )
266+ Log .w(" FLUTTER_HEALTH::ERROR" , " Datatype $typeKey not found in HC" )
273267 return null
274268 }
275-
269+
276270 val access = permissions[i]
277271 val dataType = HealthConstants .mapToType[typeKey]!!
278-
272+
279273 if (access == 0 ) {
280274 // Read permission only
281275 permList.add(
282- HealthPermission .getReadPermission(dataType),
276+ HealthPermission .getReadPermission(dataType),
277+ )
278+ } else if (access == 1 ) {
279+ // Write permission only
280+ permList.add(
281+ HealthPermission .getWritePermission(dataType),
283282 )
284283 } else {
285284 // Read and write permissions
286285 permList.addAll(
287- listOf (
288- HealthPermission .getReadPermission(dataType),
289- HealthPermission .getWritePermission(dataType),
290- ),
286+ listOf (
287+ HealthPermission .getReadPermission(dataType),
288+ HealthPermission .getWritePermission(dataType),
289+ ),
291290 )
292291 }
293292 }
294-
293+
295294 return permList
296295 }
297- }
296+ }
0 commit comments