Skip to content

Commit 0294e69

Browse files
authored
Merge pull request #1186 from cph-cachet:health-12/data-in-bg
Add background health data permissions for Android
2 parents 8105c7d + 0329a6f commit 0294e69

5 files changed

Lines changed: 124 additions & 0 deletions

File tree

packages/health/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 12.2.0
22

33
* iOS: Add `deviceModel` in returned Health data to identify the device that generated the data of the receiver. (in iOS `source_name` represents the revision of the source responsible for saving the receiver.)
4+
* Android: Add read health data in background - PR [#1184](https://github.com/cph-cachet/flutter-plugins/pull/1184)
45

56
## 12.1.0
67

packages/health/android/src/main/kotlin/cachet/plugins/health/HealthPlugin.kt

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import androidx.health.connect.client.HealthConnectFeatures
1515
import androidx.health.connect.client.PermissionController
1616
import androidx.health.connect.client.permission.HealthPermission
1717
import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_READ_HEALTH_DATA_HISTORY
18+
import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND
1819
import androidx.health.connect.client.records.*
1920
import androidx.health.connect.client.records.MealType.MEAL_TYPE_BREAKFAST
2021
import androidx.health.connect.client.records.MealType.MEAL_TYPE_DINNER
@@ -153,6 +154,9 @@ class HealthPlugin(private var channel: MethodChannel? = null) :
153154
"isHealthDataHistoryAvailable" -> isHealthDataHistoryAvailable(call, result)
154155
"isHealthDataHistoryAuthorized" -> isHealthDataHistoryAuthorized(call, result)
155156
"requestHealthDataHistoryAuthorization" -> requestHealthDataHistoryAuthorization(call, result)
157+
"isHealthDataInBackgroundAvailable" -> isHealthDataInBackgroundAvailable(call, result)
158+
"isHealthDataInBackgroundAuthorized" -> isHealthDataInBackgroundAuthorized(call, result)
159+
"requestHealthDataInBackgroundAuthorization" -> requestHealthDataInBackgroundAuthorization(call, result)
156160
"hasPermissions" -> hasPermissions(call, result)
157161
"requestAuthorization" -> requestAuthorization(call, result)
158162
"revokePermissions" -> revokePermissions(call, result)
@@ -568,6 +572,55 @@ class HealthPlugin(private var channel: MethodChannel? = null) :
568572
healthConnectRequestPermissionsLauncher!!.launch(setOf(PERMISSION_READ_HEALTH_DATA_HISTORY))
569573
}
570574

575+
/**
576+
* Checks if the health data in background feature is available on this device
577+
*/
578+
@OptIn(ExperimentalFeatureAvailabilityApi::class)
579+
private fun isHealthDataInBackgroundAvailable(call: MethodCall, result: Result) {
580+
scope.launch {
581+
result.success(
582+
healthConnectClient
583+
.features
584+
.getFeatureStatus(HealthConnectFeatures.FEATURE_READ_HEALTH_DATA_IN_BACKGROUND) ==
585+
HealthConnectFeatures.FEATURE_STATUS_AVAILABLE)
586+
}
587+
}
588+
589+
/**
590+
* Checks if PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND has been granted
591+
*/
592+
private fun isHealthDataInBackgroundAuthorized(call: MethodCall, result: Result) {
593+
scope.launch {
594+
result.success(
595+
healthConnectClient
596+
.permissionController
597+
.getGrantedPermissions()
598+
.containsAll(listOf(PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND)),
599+
)
600+
}
601+
}
602+
603+
/**
604+
* Requests authorization for PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND
605+
*/
606+
private fun requestHealthDataInBackgroundAuthorization(call: MethodCall, result: Result) {
607+
if (context == null) {
608+
result.success(false)
609+
return
610+
}
611+
612+
if (healthConnectRequestPermissionsLauncher == null) {
613+
result.success(false)
614+
Log.i("FLUTTER_HEALTH", "Permission launcher not found")
615+
return
616+
}
617+
618+
// Store the result to be called in [onHealthConnectPermissionCallback]
619+
mResult = result
620+
isReplySubmitted = false
621+
healthConnectRequestPermissionsLauncher!!.launch(setOf(PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND))
622+
}
623+
571624
private fun hasPermissions(call: MethodCall, result: Result) {
572625
val args = call.arguments as HashMap<*, *>
573626
val types = (args["types"] as? ArrayList<*>)?.filterIsInstance<String>()!!

packages/health/example/android/app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
<!-- For reading historical data - more than 30 days ago since permission given -->
5858
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY"/>
5959

60+
<!-- For reading data in background -->
61+
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND"/>
62+
6063
<application
6164
android:label="health_example"
6265
android:name="${applicationName}"

packages/health/example/lib/main.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ class HealthAppState extends State<HealthApp> {
126126
// request access to read historic data
127127
await health.requestHealthDataHistoryAuthorization();
128128

129+
// request access in background
130+
await health.requestHealthDataInBackgroundAuthorization();
131+
129132
} catch (error) {
130133
debugPrint("Exception in authorize: $error");
131134
}

packages/health/lib/src/health_plugin.dart

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,70 @@ class Health {
264264
}
265265
}
266266

267+
/// Checks if the Health Data in Background feature is available.
268+
///
269+
/// See this for more info: https://developer.android.com/reference/androidx/health/connect/client/permission/HealthPermission#PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND()
270+
///
271+
///
272+
/// Android only. Returns false on iOS or if an error occurs.
273+
Future<bool> isHealthDataInBackgroundAvailable() async {
274+
if (Platform.isIOS) return false;
275+
276+
try {
277+
final status =
278+
await _channel.invokeMethod<bool>('isHealthDataInBackgroundAvailable');
279+
return status ?? false;
280+
} catch (e) {
281+
debugPrint(
282+
'$runtimeType - Exception in isHealthDataInBackgroundAvailable(): $e');
283+
return false;
284+
}
285+
}
286+
287+
/// Checks the current status of the Health Data in Background permission.
288+
/// Make sure to check [isHealthConnectAvailable] before calling this method.
289+
///
290+
/// See this for more info: https://developer.android.com/reference/androidx/health/connect/client/permission/HealthPermission#PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND()
291+
///
292+
///
293+
/// Android only. Returns true on iOS or false if an error occurs.
294+
Future<bool> isHealthDataInBackgroundAuthorized() async {
295+
if (Platform.isIOS) return true;
296+
297+
try {
298+
final status =
299+
await _channel.invokeMethod<bool>('isHealthDataInBackgroundAuthorized');
300+
return status ?? false;
301+
} catch (e) {
302+
debugPrint(
303+
'$runtimeType - Exception in isHealthDataInBackgroundAuthorized(): $e');
304+
return false;
305+
}
306+
}
307+
308+
/// Requests the Health Data in Background permission.
309+
///
310+
/// Returns true if successful, false otherwise.
311+
///
312+
/// See this for more info: https://developer.android.com/reference/androidx/health/connect/client/permission/HealthPermission#PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND()
313+
///
314+
///
315+
/// Android only. Returns true on iOS or false if an error occurs.
316+
Future<bool> requestHealthDataInBackgroundAuthorization() async {
317+
if (Platform.isIOS) return true;
318+
319+
await _checkIfHealthConnectAvailableOnAndroid();
320+
try {
321+
final bool? isAuthorized =
322+
await _channel.invokeMethod('requestHealthDataInBackgroundAuthorization');
323+
return isAuthorized ?? false;
324+
} catch (e) {
325+
debugPrint(
326+
'$runtimeType - Exception in requestHealthDataInBackgroundAuthorization(): $e');
327+
return false;
328+
}
329+
}
330+
267331
/// Requests permissions to access health data [types].
268332
///
269333
/// Returns true if successful, false otherwise.

0 commit comments

Comments
 (0)