|
...
|
...
|
@@ -25,6 +25,11 @@ import '../health_sleep_calculator.dart'; |
|
|
|
class AppleHealthRawDataCoreService {
|
|
|
|
static const int defaultLookbackDays = 183;
|
|
|
|
static const int defaultReadChunkDays = 7;
|
|
|
|
static String _executionEngineType = 'main';
|
|
|
|
|
|
|
|
static void setExecutionEngineType(String value) {
|
|
|
|
_executionEngineType = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
AppleHealthRawDataCoreService({
|
|
|
|
HealthKitHostApi? healthApi,
|
|
...
|
...
|
@@ -108,6 +113,11 @@ class AppleHealthRawDataCoreService { |
|
|
|
_healthDataUpdatedController.stream;
|
|
|
|
|
|
|
|
Future<bool> onHealthDataUpdated({List<int>? dataTypes}) async {
|
|
|
|
await _saveLocalNotificationDebugEvent(<String, Object?>{
|
|
|
|
'event': 'flutterHealthDataReceived',
|
|
|
|
'identifier': 'flutter.health_data.received',
|
|
|
|
'data_types': dataTypes ?? const <int>[],
|
|
|
|
});
|
|
|
|
await _saveNativeCallFlutterChange(dataTypes);
|
|
|
|
if (_healthDataUpdatedCalculation != null) {
|
|
|
|
_pendingHealthDataUpdatedTypes = _mergeHealthDataTypes(
|
|
...
|
...
|
@@ -283,6 +293,11 @@ class AppleHealthRawDataCoreService { |
|
|
|
}
|
|
|
|
|
|
|
|
final userId = _userId;
|
|
|
|
await _saveLocalNotificationDebugEvent(<String, Object?>{
|
|
|
|
'event': 'flutterCalculationStarted',
|
|
|
|
'identifier': 'flutter.calculation.started',
|
|
|
|
'user_id': userId,
|
|
|
|
});
|
|
|
|
final hasAuthorization = await _hasHealthReadAuthorization();
|
|
|
|
if (!hasAuthorization) {
|
|
|
|
return HealthRawStressCalculationResult(
|
|
...
|
...
|
@@ -393,6 +408,21 @@ class AppleHealthRawDataCoreService { |
|
|
|
),
|
|
|
|
);
|
|
|
|
await _localStore.upsertResult(newResult);
|
|
|
|
await _saveLocalNotificationDebugEvent(<String, Object?>{
|
|
|
|
'event': 'flutterCalculationResultStored',
|
|
|
|
'identifier': 'flutter.calculation.result_stored',
|
|
|
|
'user_id': userId,
|
|
|
|
'hrv_count': newResult.hrvStressPoints.length,
|
|
|
|
'realtime_count': newResult.realtimeStressPoints.length,
|
|
|
|
'latest_hrv': _latestHrvStressPointPayload(newResult.hrvStressPoints),
|
|
|
|
'latest_realtime':
|
|
|
|
_latestRealtimeStressPointPayload(newResult.realtimeStressPoints),
|
|
|
|
});
|
|
|
|
await _sendLocalNotificationsAfterCalculation(
|
|
|
|
result: newResult,
|
|
|
|
hasExistingHrv: latestHrvRawEndTime != null,
|
|
|
|
hasExistingSleep: latestSleepResultTime != null,
|
|
|
|
);
|
|
|
|
_scheduleResultUpload('upload hrv results', _uploadHrvResults);
|
|
|
|
_scheduleResultUpload(
|
|
|
|
'upload realtime stress results',
|
|
...
|
...
|
@@ -418,7 +448,10 @@ class AppleHealthRawDataCoreService { |
|
|
|
sleepResults: sleepResults,
|
|
|
|
);
|
|
|
|
await _sendLocalNotificationsAfterCalculation(
|
|
|
|
result: storedResult,
|
|
|
|
result: storedResult.copyWith(
|
|
|
|
hrvStressPoints: const <HealthRawHrvStressPoint>[],
|
|
|
|
realtimeStressPoints: const <HealthRawRealtimeStressPoint>[],
|
|
|
|
),
|
|
|
|
hasExistingHrv: latestHrvRawEndTime != null,
|
|
|
|
hasExistingSleep: latestSleepResultTime != null,
|
|
|
|
);
|
|
...
|
...
|
@@ -426,6 +459,15 @@ class AppleHealthRawDataCoreService { |
|
|
|
_logInfo(
|
|
|
|
'calculateEndAt=${_formatDateTimeMilliseconds(calculateFinishedAt)}',
|
|
|
|
);
|
|
|
|
await _saveLocalNotificationDebugEvent(<String, Object?>{
|
|
|
|
'event': 'flutterCalculationFinished',
|
|
|
|
'identifier': 'flutter.calculation.finished',
|
|
|
|
'user_id': userId,
|
|
|
|
'hrv_count': storedResult.hrvStressPoints.length,
|
|
|
|
'realtime_count': storedResult.realtimeStressPoints.length,
|
|
|
|
'daily_stress_count': storedResult.dailyStressPoints.length,
|
|
|
|
'sleep_count': storedResult.sleepResults.length,
|
|
|
|
});
|
|
|
|
return storedResult;
|
|
|
|
}
|
|
|
|
|
|
...
|
...
|
@@ -437,6 +479,7 @@ class AppleHealthRawDataCoreService { |
|
|
|
await _saveLocalNotificationDebugEvent(
|
|
|
|
<String, Object?>{
|
|
|
|
'event': 'flutterNotificationCalculationFinished',
|
|
|
|
'identifier': 'flutter.notification.calculation_finished',
|
|
|
|
'user_id': result.userId,
|
|
|
|
'has_existing_hrv': hasExistingHrv,
|
|
|
|
'has_existing_sleep': hasExistingSleep,
|
|
...
|
...
|
@@ -453,6 +496,7 @@ class AppleHealthRawDataCoreService { |
|
|
|
await _saveLocalNotificationDebugEvent(
|
|
|
|
<String, Object?>{
|
|
|
|
'event': 'flutterNotificationRecordRead',
|
|
|
|
'identifier': 'flutter.notification.record_read',
|
|
|
|
'user_id': result.userId,
|
|
|
|
'record': _localNotificationRecordPayload(record),
|
|
|
|
},
|
|
...
|
...
|
@@ -464,6 +508,7 @@ class AppleHealthRawDataCoreService { |
|
|
|
await _saveLocalNotificationDebugEvent(
|
|
|
|
<String, Object?>{
|
|
|
|
'event': 'flutterNotificationLatestDataTimeChecked',
|
|
|
|
'identifier': 'flutter.notification.latest_data_checked',
|
|
|
|
'user_id': result.userId,
|
|
|
|
'record': _localNotificationRecordPayload(record),
|
|
|
|
'latest_data_time': candidateData.latestDataTimePayload,
|
|
...
|
...
|
@@ -476,6 +521,7 @@ class AppleHealthRawDataCoreService { |
|
|
|
await _saveLocalNotificationDebugEvent(
|
|
|
|
<String, Object?>{
|
|
|
|
'event': 'flutterNotificationNotBuilt',
|
|
|
|
'identifier': 'flutter.notification.not_built',
|
|
|
|
'reason': 'empty_calculation_result',
|
|
|
|
'user_id': result.userId,
|
|
|
|
},
|
|
...
|
...
|
@@ -523,6 +569,7 @@ class AppleHealthRawDataCoreService { |
|
|
|
await _saveLocalNotificationDebugEvent(
|
|
|
|
<String, Object?>{
|
|
|
|
'event': 'flutterNotificationBuildDecisions',
|
|
|
|
'identifier': 'flutter.notification.selection_result',
|
|
|
|
'user_id': candidateResult.userId,
|
|
|
|
'decisions': _localNotificationDecisionPayloads(
|
|
|
|
result: notificationResult,
|
|
...
|
...
|
@@ -543,6 +590,7 @@ class AppleHealthRawDataCoreService { |
|
|
|
await _saveLocalNotificationDebugEvent(
|
|
|
|
<String, Object?>{
|
|
|
|
'event': 'flutterNotificationBuildFinished',
|
|
|
|
'identifier': 'flutter.notification.selection_finished',
|
|
|
|
'user_id': candidateResult.userId,
|
|
|
|
'notification_count': notifications.length,
|
|
|
|
'notifications': notifications.map(_localNotificationPayload).toList(),
|
|
...
|
...
|
@@ -552,6 +600,7 @@ class AppleHealthRawDataCoreService { |
|
|
|
await _saveLocalNotificationDebugEvent(
|
|
|
|
<String, Object?>{
|
|
|
|
'event': 'flutterNotificationNotSent',
|
|
|
|
'identifier': 'flutter.notification.not_triggered',
|
|
|
|
'reason': 'no_built_notifications',
|
|
|
|
'user_id': candidateResult.userId,
|
|
|
|
},
|
|
...
|
...
|
@@ -564,6 +613,7 @@ class AppleHealthRawDataCoreService { |
|
|
|
await _saveLocalNotificationDebugEvent(
|
|
|
|
<String, Object?>{
|
|
|
|
'event': 'flutterNotificationSendStart',
|
|
|
|
'identifier': 'flutter.notification.triggered',
|
|
|
|
'user_id': candidateResult.userId,
|
|
|
|
'notification': _localNotificationPayload(notification),
|
|
|
|
},
|
|
...
|
...
|
@@ -575,6 +625,7 @@ class AppleHealthRawDataCoreService { |
|
|
|
await _saveLocalNotificationDebugEvent(
|
|
|
|
<String, Object?>{
|
|
|
|
'event': 'flutterNotificationSendFinished',
|
|
|
|
'identifier': 'flutter.notification.trigger_finished',
|
|
|
|
'user_id': candidateResult.userId,
|
|
|
|
'sent': sent,
|
|
|
|
'reason': sent ? null : 'native_or_dispatcher_returned_false',
|
|
...
|
...
|
@@ -1326,6 +1377,11 @@ class AppleHealthRawDataCoreService { |
|
|
|
if (!_uploadResultsAfterCalculation) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
unawaited(_saveLocalNotificationDebugEvent(<String, Object?>{
|
|
|
|
'event': 'flutterCalculationResultUploadTriggered',
|
|
|
|
'identifier': 'flutter.calculation_result_upload.triggered',
|
|
|
|
'upload_action': action,
|
|
|
|
}));
|
|
|
|
unawaited(
|
|
|
|
(() async {
|
|
|
|
try {
|
|
...
|
...
|
@@ -1506,14 +1562,21 @@ class AppleHealthRawDataCoreService { |
|
|
|
|
|
|
|
Future<void> _saveLocalNotificationDebugEvent(
|
|
|
|
Map<String, Object?> event,
|
|
|
|
) async {
|
|
|
|
try {
|
|
|
|
await _localNotificationDebugStore.append(event);
|
|
|
|
await _saveNativeLocalNotificationDebugEvent(event);
|
|
|
|
} catch (error, stackTrace) {
|
|
|
|
_logError(
|
|
|
|
'save local notification debug event failed', error, stackTrace);
|
|
|
|
}
|
|
|
|
) {
|
|
|
|
final pipelineEvent = <String, Object?>{
|
|
|
|
...event,
|
|
|
|
'engine_type': _executionEngineType,
|
|
|
|
};
|
|
|
|
unawaited(() async {
|
|
|
|
try {
|
|
|
|
await _saveNativeLocalNotificationDebugEvent(pipelineEvent).timeout(
|
|
|
|
const Duration(seconds: 1),
|
|
|
|
);
|
|
|
|
} catch (error, stackTrace) {
|
|
|
|
_logError('save health pipeline event failed', error, stackTrace);
|
|
|
|
}
|
|
|
|
}());
|
|
|
|
return Future<void>.value();
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<bool> _saveNativeLocalNotificationDebugEvent(
|
...
|
...
|
|