|
...
|
...
|
@@ -290,6 +290,23 @@ class OHOSHealthRawDataCoreService { |
|
|
|
'${syncResults.fold<int>(0, (sum, result) => sum + result.storedCount)} '
|
|
|
|
'elapsedMs=${syncElapsed.inMilliseconds}',
|
|
|
|
);
|
|
|
|
if (willSyncRawData &&
|
|
|
|
syncSnapshot != null &&
|
|
|
|
!syncSnapshot.hasNewCalculationData) {
|
|
|
|
_logInfo(
|
|
|
|
'$_calculateLogMarker skip_no_new_base_data userId=$userId '
|
|
|
|
'checkedDataTypes=hr,hrv,sleep',
|
|
|
|
);
|
|
|
|
// Calculation and notifications require new base data. Keep the upload
|
|
|
|
// retry path active so a previous failed result upload is not stranded.
|
|
|
|
_scheduleResultUpload();
|
|
|
|
return HealthRawStressCalculationResult(
|
|
|
|
userId: userId,
|
|
|
|
hrvStressPoints: const <HealthRawHrvStressPoint>[],
|
|
|
|
realtimeStressPoints: const <HealthRawRealtimeStressPoint>[],
|
|
|
|
dailyStressPoints: const <HealthRawDailyStressPoint>[],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
final calculationStartTime = DateTime.now();
|
|
|
|
_publishCalculationEvent(
|
|
...
|
...
|
@@ -394,25 +411,26 @@ class OHOSHealthRawDataCoreService { |
|
|
|
var hasExistingSleep = false;
|
|
|
|
try {
|
|
|
|
final contextStopwatch = Stopwatch()..start();
|
|
|
|
final hrvContextStart =
|
|
|
|
await _localStore.latestHrvSourceStartTime(userId);
|
|
|
|
final realtimeContextStart =
|
|
|
|
await _localStore.latestRealtimeSourceStartTime(userId);
|
|
|
|
final latestHrvRawEndTime = await _localStore.latestHrvRawEndTime(userId);
|
|
|
|
final latestRealtimeRawEndTime =
|
|
|
|
await _localStore.latestRealtimeRawEndTime(userId);
|
|
|
|
final latestSleepResultTime = await _localStore.latestSleepResultTime(
|
|
|
|
userId,
|
|
|
|
);
|
|
|
|
final latestRawHrvDataTime = await _latestOhosRawDataTime(
|
|
|
|
HealthDataUploadType.hrv.type,
|
|
|
|
);
|
|
|
|
final latestRawHrDataTime = await _latestOhosRawDataTime(
|
|
|
|
HealthDataUploadType.heartRate.type,
|
|
|
|
);
|
|
|
|
final latestRawSleepDataTime = await _latestOhosRawDataTime(
|
|
|
|
OhosHealthRawDataType.sleepAnalysis,
|
|
|
|
);
|
|
|
|
// These reads have no dependencies. Start them together so separate
|
|
|
|
// SQLite databases/platform channels do not extend the critical path.
|
|
|
|
final context = await Future.wait<int?>([
|
|
|
|
_localStore.latestHrvSourceStartTime(userId),
|
|
|
|
_localStore.latestRealtimeSourceStartTime(userId),
|
|
|
|
_localStore.latestHrvRawEndTime(userId),
|
|
|
|
_localStore.latestRealtimeRawEndTime(userId),
|
|
|
|
_localStore.latestSleepResultTime(userId),
|
|
|
|
_latestOhosRawDataTime(HealthDataUploadType.hrv.type),
|
|
|
|
_latestOhosRawDataTime(HealthDataUploadType.heartRate.type),
|
|
|
|
_latestOhosRawDataTime(OhosHealthRawDataType.sleepAnalysis),
|
|
|
|
]);
|
|
|
|
final hrvContextStart = context[0];
|
|
|
|
final realtimeContextStart = context[1];
|
|
|
|
final latestHrvRawEndTime = context[2];
|
|
|
|
final latestRealtimeRawEndTime = context[3];
|
|
|
|
final latestSleepResultTime = context[4];
|
|
|
|
final latestRawHrvDataTime = context[5];
|
|
|
|
final latestRawHrDataTime = context[6];
|
|
|
|
final latestRawSleepDataTime = context[7];
|
|
|
|
_profileLog(
|
|
|
|
'calculate_contextQuery_finish userId=$userId '
|
|
|
|
'elapsedMs=${contextStopwatch.elapsedMilliseconds}',
|
|
...
|
...
|
@@ -500,14 +518,48 @@ class OHOSHealthRawDataCoreService { |
|
|
|
'realtimeRecomputeStartTime=$realtimeRecomputeStartTime',
|
|
|
|
);
|
|
|
|
|
|
|
|
// Raw types are independent. Create every future before awaiting one so
|
|
|
|
// their reads overlap; stress dependency is enforced only below.
|
|
|
|
final hrvFetchStopwatch = Stopwatch()..start();
|
|
|
|
final hrvPoints = await _fetchRawDataForCalculation(
|
|
|
|
final heartRateFetchStopwatch = Stopwatch()..start();
|
|
|
|
final restingHeartRateFetchStopwatch = Stopwatch()..start();
|
|
|
|
final sleepFetchStopwatch = Stopwatch()..start();
|
|
|
|
final workoutFetchStopwatch = Stopwatch()..start();
|
|
|
|
final hrvPointsFuture = _fetchRawDataForCalculation(
|
|
|
|
HealthDataUploadType.hrv.type,
|
|
|
|
hrvStartTime,
|
|
|
|
effectiveEndTime,
|
|
|
|
rawDataSnapshot: rawDataSnapshot,
|
|
|
|
readChunkDays: readChunkDays,
|
|
|
|
);
|
|
|
|
final heartRatePointsFuture = _fetchRawDataForCalculation(
|
|
|
|
HealthDataUploadType.heartRate.type,
|
|
|
|
heartRateStartTime,
|
|
|
|
effectiveEndTime,
|
|
|
|
rawDataSnapshot: rawDataSnapshot,
|
|
|
|
readChunkDays: readChunkDays,
|
|
|
|
);
|
|
|
|
final restingHeartRatePointsFuture = _fetchRawDataForCalculation(
|
|
|
|
HealthDataUploadType.restingHeartRate.type,
|
|
|
|
heartRateStartTime,
|
|
|
|
effectiveEndTime,
|
|
|
|
rawDataSnapshot: rawDataSnapshot,
|
|
|
|
readChunkDays: readChunkDays,
|
|
|
|
);
|
|
|
|
final sleepIntervalsFuture = _fetchSleepIntervalsForCalculation(
|
|
|
|
sleepStartTime,
|
|
|
|
effectiveEndTime,
|
|
|
|
rawDataSnapshot: rawDataSnapshot,
|
|
|
|
readChunkDays: readChunkDays,
|
|
|
|
);
|
|
|
|
final workoutIntervalsFuture = _fetchWorkoutIntervalsForCalculation(
|
|
|
|
heartRateStartTime,
|
|
|
|
effectiveEndTime,
|
|
|
|
rawDataSnapshot: rawDataSnapshot,
|
|
|
|
readChunkDays: readChunkDays,
|
|
|
|
);
|
|
|
|
|
|
|
|
final hrvPoints = await hrvPointsFuture;
|
|
|
|
_profileLog(
|
|
|
|
'calculate_fetchRaw_finish userId=$userId '
|
|
|
|
'name=hrv dataType=${HealthDataUploadType.hrv.type} '
|
|
...
|
...
|
@@ -515,14 +567,7 @@ class OHOSHealthRawDataCoreService { |
|
|
|
'count=${hrvPoints.length} '
|
|
|
|
'elapsedMs=${hrvFetchStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
final heartRateFetchStopwatch = Stopwatch()..start();
|
|
|
|
final heartRatePoints = await _fetchRawDataForCalculation(
|
|
|
|
HealthDataUploadType.heartRate.type,
|
|
|
|
heartRateStartTime,
|
|
|
|
effectiveEndTime,
|
|
|
|
rawDataSnapshot: rawDataSnapshot,
|
|
|
|
readChunkDays: readChunkDays,
|
|
|
|
);
|
|
|
|
final heartRatePoints = await heartRatePointsFuture;
|
|
|
|
_profileLog(
|
|
|
|
'calculate_fetchRaw_finish userId=$userId '
|
|
|
|
'name=heartRate dataType=${HealthDataUploadType.heartRate.type} '
|
|
...
|
...
|
@@ -530,14 +575,7 @@ class OHOSHealthRawDataCoreService { |
|
|
|
'count=${heartRatePoints.length} '
|
|
|
|
'elapsedMs=${heartRateFetchStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
final restingHeartRateFetchStopwatch = Stopwatch()..start();
|
|
|
|
final restingHeartRatePoints = await _fetchRawDataForCalculation(
|
|
|
|
HealthDataUploadType.restingHeartRate.type,
|
|
|
|
heartRateStartTime,
|
|
|
|
effectiveEndTime,
|
|
|
|
rawDataSnapshot: rawDataSnapshot,
|
|
|
|
readChunkDays: readChunkDays,
|
|
|
|
);
|
|
|
|
final restingHeartRatePoints = await restingHeartRatePointsFuture;
|
|
|
|
_profileLog(
|
|
|
|
'calculate_fetchRaw_finish userId=$userId '
|
|
|
|
'name=restingHeartRate '
|
|
...
|
...
|
@@ -546,26 +584,14 @@ class OHOSHealthRawDataCoreService { |
|
|
|
'count=${restingHeartRatePoints.length} '
|
|
|
|
'elapsedMs=${restingHeartRateFetchStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
final sleepFetchStopwatch = Stopwatch()..start();
|
|
|
|
final sleepIntervals = await _fetchSleepIntervalsForCalculation(
|
|
|
|
sleepStartTime,
|
|
|
|
effectiveEndTime,
|
|
|
|
rawDataSnapshot: rawDataSnapshot,
|
|
|
|
readChunkDays: readChunkDays,
|
|
|
|
);
|
|
|
|
final sleepIntervals = await sleepIntervalsFuture;
|
|
|
|
_profileLog(
|
|
|
|
'calculate_fetchRaw_finish userId=$userId name=sleep '
|
|
|
|
'startTime=$sleepStartTime endTime=$effectiveEndTime '
|
|
|
|
'count=${sleepIntervals.length} '
|
|
|
|
'elapsedMs=${sleepFetchStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
final workoutFetchStopwatch = Stopwatch()..start();
|
|
|
|
final workoutIntervals = await _fetchWorkoutIntervalsForCalculation(
|
|
|
|
heartRateStartTime,
|
|
|
|
effectiveEndTime,
|
|
|
|
rawDataSnapshot: rawDataSnapshot,
|
|
|
|
readChunkDays: readChunkDays,
|
|
|
|
);
|
|
|
|
final workoutIntervals = await workoutIntervalsFuture;
|
|
|
|
_profileLog(
|
|
|
|
'calculate_fetchRaw_finish userId=$userId name=workout '
|
|
|
|
'startTime=$heartRateStartTime endTime=$effectiveEndTime '
|
|
...
|
...
|
@@ -589,6 +615,14 @@ class OHOSHealthRawDataCoreService { |
|
|
|
'needSleep=${_needsNewResult(latestRawSleepTime, latestSleepResultTime)}',
|
|
|
|
);
|
|
|
|
|
|
|
|
// Sleep has no result dependency on either stress calculation. Run its
|
|
|
|
// CPU work alongside the HRV -> realtime-stress isolate; only storage is
|
|
|
|
// sequenced later to avoid concurrent writes to the result database.
|
|
|
|
final sleepCalculationStopwatch = Stopwatch()..start();
|
|
|
|
final sleepCalculationFuture = _calculateSleepResults(
|
|
|
|
userId: userId,
|
|
|
|
sleepIntervals: sleepIntervals,
|
|
|
|
);
|
|
|
|
final isolateStopwatch = Stopwatch()..start();
|
|
|
|
final result = await Isolate.run(
|
|
|
|
() => HuaweiHealthRawStressCalculator(userId: userId).calculate(
|
|
...
|
...
|
@@ -671,15 +705,14 @@ class OHOSHealthRawDataCoreService { |
|
|
|
'count=${dailyStressPoints.length} '
|
|
|
|
'elapsedMs=${dailyStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
final sleepStopwatch = Stopwatch()..start();
|
|
|
|
final sleepResults = await _calculateAndStoreSleepResults(
|
|
|
|
final sleepResults = await sleepCalculationFuture;
|
|
|
|
await _storeSleepResults(
|
|
|
|
userId: userId,
|
|
|
|
sleepIntervals: sleepIntervals,
|
|
|
|
latestSleepResultTime: latestSleepResultTime,
|
|
|
|
results: sleepResults,
|
|
|
|
);
|
|
|
|
_profileLog(
|
|
|
|
'calculate_sleep_finish userId=$userId count=${sleepResults.length} '
|
|
|
|
'elapsedMs=${sleepStopwatch.elapsedMilliseconds}',
|
|
|
|
'elapsedMs=${sleepCalculationStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
_logInfo(
|
|
|
|
'calculate_daily_sleep_stored userId=$userId '
|
|
...
|
...
|
@@ -1440,31 +1473,59 @@ class OHOSHealthRawDataCoreService { |
|
|
|
return dailyStressPoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<List<HealthRawSleepResult>> _calculateAndStoreSleepResults({
|
|
|
|
Future<List<HealthRawSleepResult>> _calculateSleepResults({
|
|
|
|
required int userId,
|
|
|
|
required List<HealthKitRawDataPoint> sleepIntervals,
|
|
|
|
required int? latestSleepResultTime,
|
|
|
|
}) async {
|
|
|
|
_logInfo(
|
|
|
|
'$_sleepCalcLogMarker start userId=$userId '
|
|
|
|
'sleepIntervals=${sleepIntervals.length} '
|
|
|
|
'latestSleepResultTime=$latestSleepResultTime',
|
|
|
|
'sleepIntervals=${sleepIntervals.length}',
|
|
|
|
);
|
|
|
|
if (sleepIntervals.isEmpty) {
|
|
|
|
_logInfo('$_sleepCalcLogMarker no_raw_sleep userId=$userId');
|
|
|
|
return const <HealthRawSleepResult>[];
|
|
|
|
}
|
|
|
|
final stopwatch = Stopwatch()..start();
|
|
|
|
final results = await Isolate.run(
|
|
|
|
() => _calculateSleepResultsSync(
|
|
|
|
userId: userId,
|
|
|
|
sleepIntervals: sleepIntervals,
|
|
|
|
),
|
|
|
|
debugName: 'OHOSHealthSleepCalculator',
|
|
|
|
);
|
|
|
|
_profileLog(
|
|
|
|
'sleep_isolate_finish userId=$userId '
|
|
|
|
'input=${sleepIntervals.length} result=${results.length} '
|
|
|
|
'elapsedMs=${stopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _storeSleepResults({
|
|
|
|
required int userId,
|
|
|
|
required List<HealthRawSleepResult> results,
|
|
|
|
}) async {
|
|
|
|
final sleepStoreStopwatch = Stopwatch()..start();
|
|
|
|
await _localStore.upsertSleepResults(userId: userId, results: results);
|
|
|
|
_profileLog(
|
|
|
|
'sleep_store_finish userId=$userId stored=${results.length} '
|
|
|
|
'elapsedMs=${sleepStoreStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
_logInfo(
|
|
|
|
'$_sleepCalcLogMarker stored userId=$userId stored=${results.length}',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
static List<HealthRawSleepResult> _calculateSleepResultsSync({
|
|
|
|
required int userId,
|
|
|
|
required List<HealthKitRawDataPoint> sleepIntervals,
|
|
|
|
}) {
|
|
|
|
final days = {
|
|
|
|
for (final interval in sleepIntervals) _localDay(interval.endTime),
|
|
|
|
}.toList()
|
|
|
|
..sort((a, b) => a.compareTo(b));
|
|
|
|
_logInfo(
|
|
|
|
'$_sleepCalcLogMarker days userId=$userId '
|
|
|
|
'days=${days.map(_dateKeyFromDateTime).toList()}',
|
|
|
|
);
|
|
|
|
final results = <HealthRawSleepResult>[];
|
|
|
|
for (final day in days) {
|
|
|
|
final dayStopwatch = Stopwatch()..start();
|
|
|
|
final calculation = HealthSleepCalculator.calculateDay(
|
|
|
|
day: day,
|
|
|
|
sleepIntervals: sleepIntervals,
|
|
...
|
...
|
@@ -1473,49 +1534,13 @@ class OHOSHealthRawDataCoreService { |
|
|
|
final score = calculation.score;
|
|
|
|
final state = calculation.state;
|
|
|
|
if (merged == null || score == null || state == null) {
|
|
|
|
_profileLog(
|
|
|
|
'sleep_day_finish userId=$userId '
|
|
|
|
'date=${_dateKeyFromDateTime(day)} hasResult=false '
|
|
|
|
'reason=missing_score_or_state '
|
|
|
|
'elapsedMs=${dayStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
_logInfo(
|
|
|
|
'$_sleepCalcLogMarker skip_invalid userId=$userId '
|
|
|
|
'date=${_dateKeyFromDateTime(day)} '
|
|
|
|
'reason=missing_score_or_state '
|
|
|
|
'score=$score state=${state?.value}',
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!calculation.hasValidSleep) {
|
|
|
|
_profileLog(
|
|
|
|
'sleep_day_finish userId=$userId '
|
|
|
|
'date=${_dateKeyFromDateTime(day)} hasResult=false '
|
|
|
|
'reason=no_valid_sleep '
|
|
|
|
'elapsedMs=${dayStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
_logInfo(
|
|
|
|
'$_sleepCalcLogMarker skip_invalid userId=$userId '
|
|
|
|
'date=${_dateKeyFromDateTime(day)} reason=no_valid_sleep '
|
|
|
|
'durationSeconds=${calculation.durationSeconds}',
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (latestSleepResultTime != null &&
|
|
|
|
merged.endTime <= latestSleepResultTime) {
|
|
|
|
_profileLog(
|
|
|
|
'sleep_day_finish userId=$userId '
|
|
|
|
'date=${_dateKeyFromDateTime(day)} hasResult=false '
|
|
|
|
'reason=existing mergedEnd=${merged.endTime} '
|
|
|
|
'elapsedMs=${dayStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
_logInfo(
|
|
|
|
'$_sleepCalcLogMarker skip_existing userId=$userId '
|
|
|
|
'date=${_dateKeyFromDateTime(day)} mergedEnd=${merged.endTime} '
|
|
|
|
'latestSleepResultTime=$latestSleepResultTime',
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// A newer result does not prove that older days were calculated.
|
|
|
|
// Reconcile every day in the input; the store preserves unchanged uploads.
|
|
|
|
results.add(
|
|
|
|
HealthRawSleepResult(
|
|
|
|
userId: userId,
|
|
...
|
...
|
@@ -1529,28 +1554,7 @@ class OHOSHealthRawDataCoreService { |
|
|
|
uploaded: false,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
_profileLog(
|
|
|
|
'sleep_day_finish userId=$userId '
|
|
|
|
'date=${_dateKeyFromDateTime(day)} hasResult=true '
|
|
|
|
'sleepMinutes=${calculation.summary.sleepMinutes} '
|
|
|
|
'elapsedMs=${dayStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
_logInfo(
|
|
|
|
'$_sleepCalcLogMarker result userId=$userId '
|
|
|
|
'date=${_dateKeyFromDateTime(day)} start=${merged.startTime} '
|
|
|
|
'end=${merged.endTime} score=$score state=${state.value} '
|
|
|
|
'sleepMinutes=${calculation.summary.sleepMinutes}',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
final sleepStoreStopwatch = Stopwatch()..start();
|
|
|
|
await _localStore.upsertSleepResults(userId: userId, results: results);
|
|
|
|
_profileLog(
|
|
|
|
'sleep_store_finish userId=$userId stored=${results.length} '
|
|
|
|
'elapsedMs=${sleepStoreStopwatch.elapsedMilliseconds}',
|
|
|
|
);
|
|
|
|
_logInfo(
|
|
|
|
'$_sleepCalcLogMarker stored userId=$userId stored=${results.length}',
|
|
|
|
);
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
...
|
...
|
@@ -1626,15 +1630,30 @@ class OHOSHealthRawDataCoreService { |
|
|
|
}) async {
|
|
|
|
final rawDataSource = _rawDataSource;
|
|
|
|
if (rawDataSnapshot != null && rawDataSource is OhosHealthRawDataSource) {
|
|
|
|
final points = rawDataSource.getRawDataFromSnapshot(
|
|
|
|
snapshot: rawDataSnapshot,
|
|
|
|
dataType: dataType,
|
|
|
|
startTime: startTime,
|
|
|
|
endTime: endTime,
|
|
|
|
)..sort((a, b) => a.endTime.compareTo(b.endTime));
|
|
|
|
// The snapshot is complete for this fetch, but it does not include the
|
|
|
|
// older local context required for baselines and smoothing. Overlay the
|
|
|
|
// fetched values on the indexed local range before calculating.
|
|
|
|
final localPoints = await rawDataSource.getRawData(
|
|
|
|
dataType,
|
|
|
|
startTime,
|
|
|
|
endTime,
|
|
|
|
);
|
|
|
|
final pointsByTime = <int, HealthKitRawDataPoint>{
|
|
|
|
for (final point in localPoints) point.endTime: point,
|
|
|
|
for (final point in rawDataSource.getRawDataFromSnapshot(
|
|
|
|
snapshot: rawDataSnapshot,
|
|
|
|
dataType: dataType,
|
|
|
|
startTime: startTime,
|
|
|
|
endTime: endTime,
|
|
|
|
))
|
|
|
|
point.endTime: point,
|
|
|
|
};
|
|
|
|
final points = pointsByTime.values.toList()
|
|
|
|
..sort((a, b) => a.endTime.compareTo(b.endTime));
|
|
|
|
_logInfo(
|
|
|
|
'$_calculateLogMarker raw_snapshot_hit dataType=$dataType '
|
|
|
|
'startTime=$startTime endTime=$endTime count=${points.length}',
|
|
|
|
'$_calculateLogMarker raw_local_snapshot_merged '
|
|
|
|
'dataType=$dataType startTime=$startTime endTime=$endTime '
|
|
|
|
'local=${localPoints.length} merged=${points.length}',
|
|
|
|
);
|
|
|
|
return points;
|
|
|
|
}
|
|
...
|
...
|
@@ -1669,24 +1688,35 @@ class OHOSHealthRawDataCoreService { |
|
|
|
required OhosHealthRawDataMemorySnapshot? rawDataSnapshot,
|
|
|
|
required int readChunkDays,
|
|
|
|
}) async {
|
|
|
|
// The snapshot contains only this sync's response, not all persisted sleep.
|
|
|
|
// Read the bounded local range once and overlay the snapshot so calculation
|
|
|
|
// is complete even while the snapshot is still being written in background.
|
|
|
|
final groups = await _rawDataSource.getRawSleepData(startTime, endTime);
|
|
|
|
final pointsByStart = <int, HealthKitRawDataPoint>{
|
|
|
|
for (final point in groups.expand((group) => group.sleepDataPoints))
|
|
|
|
point.startTime: point,
|
|
|
|
};
|
|
|
|
final rawDataSource = _rawDataSource;
|
|
|
|
if (rawDataSnapshot != null && rawDataSource is OhosHealthRawDataSource) {
|
|
|
|
final points = rawDataSource.getRawSleepIntervalsFromSnapshot(
|
|
|
|
for (final point in rawDataSource.getRawSleepIntervalsFromSnapshot(
|
|
|
|
snapshot: rawDataSnapshot,
|
|
|
|
startTime: startTime,
|
|
|
|
endTime: endTime,
|
|
|
|
)..sort((a, b) => a.endTime.compareTo(b.endTime));
|
|
|
|
_logInfo(
|
|
|
|
'$_calculateLogMarker sleep_snapshot_hit '
|
|
|
|
'startTime=$startTime endTime=$endTime count=${points.length}',
|
|
|
|
);
|
|
|
|
return points;
|
|
|
|
)) {
|
|
|
|
// OHOS raw sleep uses from_time as its unique key.
|
|
|
|
pointsByStart[point.startTime] = point;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return _fetchSleepIntervalsInChunks(
|
|
|
|
startTime,
|
|
|
|
endTime,
|
|
|
|
readChunkDays: readChunkDays,
|
|
|
|
final points = pointsByStart.values
|
|
|
|
.where(
|
|
|
|
(point) => point.endTime >= startTime && point.startTime <= endTime)
|
|
|
|
.toList()
|
|
|
|
..sort((a, b) => a.endTime.compareTo(b.endTime));
|
|
|
|
_logInfo(
|
|
|
|
'$_calculateLogMarker sleep_local_snapshot_merged '
|
|
|
|
'startTime=$startTime endTime=$endTime count=${points.length}',
|
|
|
|
);
|
|
|
|
return points;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<List<HealthKitRawWorkoutDataPoint>> _fetchWorkoutIntervalsInChunks(
|
|
...
|
...
|
@@ -1715,14 +1745,25 @@ class OHOSHealthRawDataCoreService { |
|
|
|
}) async {
|
|
|
|
final rawDataSource = _rawDataSource;
|
|
|
|
if (rawDataSnapshot != null && rawDataSource is OhosHealthRawDataSource) {
|
|
|
|
final points = rawDataSource.getRawWorkoutDataFromSnapshot(
|
|
|
|
snapshot: rawDataSnapshot,
|
|
|
|
startTime: startTime,
|
|
|
|
endTime: endTime,
|
|
|
|
)..sort((a, b) => a.endTime.compareTo(b.endTime));
|
|
|
|
final localPoints = await rawDataSource.getRawWorkoutData(
|
|
|
|
startTime,
|
|
|
|
endTime,
|
|
|
|
);
|
|
|
|
final pointsByStart = <int, HealthKitRawWorkoutDataPoint>{
|
|
|
|
for (final point in localPoints) point.startTime: point,
|
|
|
|
for (final point in rawDataSource.getRawWorkoutDataFromSnapshot(
|
|
|
|
snapshot: rawDataSnapshot,
|
|
|
|
startTime: startTime,
|
|
|
|
endTime: endTime,
|
|
|
|
))
|
|
|
|
point.startTime: point,
|
|
|
|
};
|
|
|
|
final points = pointsByStart.values.toList()
|
|
|
|
..sort((a, b) => a.endTime.compareTo(b.endTime));
|
|
|
|
_logInfo(
|
|
|
|
'$_calculateLogMarker workout_snapshot_hit '
|
|
|
|
'startTime=$startTime endTime=$endTime count=${points.length}',
|
|
|
|
'$_calculateLogMarker workout_local_snapshot_merged '
|
|
|
|
'startTime=$startTime endTime=$endTime '
|
|
|
|
'local=${localPoints.length} merged=${points.length}',
|
|
|
|
);
|
|
|
|
return points;
|
|
|
|
}
|
...
|
...
|
|