|
...
|
...
|
@@ -109,9 +109,10 @@ class OhosHealthRawDataSyncService { |
|
|
|
);
|
|
|
|
final List<OhosHealthRawDataSyncResult> results;
|
|
|
|
try {
|
|
|
|
results = await Future.wait(
|
|
|
|
final activityGoalFuture = _remoteDataSource.fetchActivityGoal();
|
|
|
|
final rawFetchesFuture = Future.wait(
|
|
|
|
resolvedDataTypes.map(
|
|
|
|
(dataType) => syncRawData(
|
|
|
|
(dataType) => _fetchRawDataForSync(
|
|
|
|
dataType: dataType,
|
|
|
|
startTime: startTime,
|
|
|
|
endTime: resolvedEndTime,
|
|
...
|
...
|
@@ -119,6 +120,27 @@ class OhosHealthRawDataSyncService { |
|
|
|
),
|
|
|
|
eagerError: true,
|
|
|
|
);
|
|
|
|
final fetched = await Future.wait<Object?>(
|
|
|
|
<Future<Object?>>[
|
|
|
|
activityGoalFuture,
|
|
|
|
rawFetchesFuture,
|
|
|
|
],
|
|
|
|
eagerError: true,
|
|
|
|
);
|
|
|
|
final activityGoal = fetched[0] as V2ActivityTarget?;
|
|
|
|
final rawFetches = fetched[1] as List<_FetchedRawDataSync>;
|
|
|
|
if (activityGoal != null) {
|
|
|
|
await _localStore.upsertActivityGoal(activityGoal);
|
|
|
|
_log(
|
|
|
|
'calculation_sync_activity_goal_stored '
|
|
|
|
'move=${activityGoal.move} step=${activityGoal.step} '
|
|
|
|
'exercise=${activityGoal.exercise} stand=${activityGoal.stand}',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
results = <OhosHealthRawDataSyncResult>[];
|
|
|
|
for (final fetch in rawFetches) {
|
|
|
|
results.add(await _storeFetchedRawData(fetch));
|
|
|
|
}
|
|
|
|
} catch (error, stackTrace) {
|
|
|
|
_log(
|
|
|
|
'calculation_sync_failed dataTypes=${resolvedDataTypes.join(',')} '
|
|
...
|
...
|
@@ -142,6 +164,26 @@ class OhosHealthRawDataSyncService { |
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<_FetchedRawDataSync> _fetchRawDataForSync({
|
|
|
|
required int dataType,
|
|
|
|
required int? startTime,
|
|
|
|
required int endTime,
|
|
|
|
}) async {
|
|
|
|
final resolvedStartTime = await _resolveStartTime(
|
|
|
|
dataType: dataType,
|
|
|
|
requestedStartTime: startTime,
|
|
|
|
endTime: endTime,
|
|
|
|
);
|
|
|
|
if (endTime < resolvedStartTime) {
|
|
|
|
throw ArgumentError.value(endTime, 'endTime');
|
|
|
|
}
|
|
|
|
return _fetchResolvedRawData(
|
|
|
|
dataType: dataType,
|
|
|
|
startTime: resolvedStartTime,
|
|
|
|
endTime: endTime,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<List<OhosHealthRawDataItem>> queryRawData({
|
|
|
|
required int dataType,
|
|
|
|
required int startTime,
|
|
...
|
...
|
@@ -187,6 +229,19 @@ class OhosHealthRawDataSyncService { |
|
|
|
required int startTime,
|
|
|
|
required int endTime,
|
|
|
|
}) async {
|
|
|
|
final fetched = await _fetchResolvedRawData(
|
|
|
|
dataType: dataType,
|
|
|
|
startTime: startTime,
|
|
|
|
endTime: endTime,
|
|
|
|
);
|
|
|
|
return _storeFetchedRawData(fetched);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<_FetchedRawDataSync> _fetchResolvedRawData({
|
|
|
|
required int dataType,
|
|
|
|
required int startTime,
|
|
|
|
required int endTime,
|
|
|
|
}) async {
|
|
|
|
final fetchRanges = _splitIntoFetchRanges(
|
|
|
|
dataType: dataType,
|
|
|
|
startTime: startTime,
|
|
...
|
...
|
@@ -199,72 +254,105 @@ class OhosHealthRawDataSyncService { |
|
|
|
'chunkDays=$fetchChunkDays rangeCount=${fetchRanges.length}',
|
|
|
|
);
|
|
|
|
|
|
|
|
final segments = await Future.wait(
|
|
|
|
<Future<_FetchedRawDataSegment>>[
|
|
|
|
for (var index = 0; index < fetchRanges.length; index++)
|
|
|
|
_fetchRawDataSegment(
|
|
|
|
dataType: dataType,
|
|
|
|
range: fetchRanges[index],
|
|
|
|
segmentIndex: index,
|
|
|
|
segmentCount: fetchRanges.length,
|
|
|
|
fetchChunkDays: fetchChunkDays,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
eagerError: true,
|
|
|
|
);
|
|
|
|
segments.sort((a, b) => a.segmentIndex.compareTo(b.segmentIndex));
|
|
|
|
return _FetchedRawDataSync(
|
|
|
|
dataType: dataType,
|
|
|
|
startTime: startTime,
|
|
|
|
endTime: endTime,
|
|
|
|
fetchChunkDays: fetchChunkDays,
|
|
|
|
segments: segments,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<_FetchedRawDataSegment> _fetchRawDataSegment({
|
|
|
|
required int dataType,
|
|
|
|
required OhosHealthRawDataFetchRange range,
|
|
|
|
required int segmentIndex,
|
|
|
|
required int segmentCount,
|
|
|
|
required int fetchChunkDays,
|
|
|
|
}) async {
|
|
|
|
_log(
|
|
|
|
'segment_start dataType=$dataType '
|
|
|
|
'segment=${segmentIndex + 1}/$segmentCount '
|
|
|
|
'chunkDays=$fetchChunkDays '
|
|
|
|
'startTime=${range.startTime} endTime=${range.endTime} '
|
|
|
|
'startDate=${_dateKeyFromUnixSeconds(range.startTime)} '
|
|
|
|
'endDate=${_dateKeyFromUnixSeconds(range.endTime)}',
|
|
|
|
);
|
|
|
|
|
|
|
|
final page = await _remoteDataSource.fetchRawDataPage(
|
|
|
|
dataType: dataType,
|
|
|
|
startTime: range.startTime,
|
|
|
|
endTime: range.endTime,
|
|
|
|
);
|
|
|
|
_log(
|
|
|
|
'page_fetched dataType=$dataType '
|
|
|
|
'segment=${segmentIndex + 1}/$segmentCount '
|
|
|
|
'items=${page.items.length}',
|
|
|
|
);
|
|
|
|
|
|
|
|
return _FetchedRawDataSegment(
|
|
|
|
segmentIndex: segmentIndex,
|
|
|
|
range: range,
|
|
|
|
page: page,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<OhosHealthRawDataSyncResult> _storeFetchedRawData(
|
|
|
|
_FetchedRawDataSync fetched,
|
|
|
|
) async {
|
|
|
|
var pageCount = 0;
|
|
|
|
var storedCount = 0;
|
|
|
|
|
|
|
|
for (var rangeIndex = 0; rangeIndex < fetchRanges.length; rangeIndex++) {
|
|
|
|
final range = fetchRanges[rangeIndex];
|
|
|
|
_log(
|
|
|
|
'segment_start dataType=$dataType '
|
|
|
|
'segment=${rangeIndex + 1}/${fetchRanges.length} '
|
|
|
|
'chunkDays=$fetchChunkDays '
|
|
|
|
'startTime=${range.startTime} endTime=${range.endTime} '
|
|
|
|
'startDate=${_dateKeyFromUnixSeconds(range.startTime)} '
|
|
|
|
'endDate=${_dateKeyFromUnixSeconds(range.endTime)}',
|
|
|
|
);
|
|
|
|
|
|
|
|
String? pageToken;
|
|
|
|
do {
|
|
|
|
final page = await _remoteDataSource.fetchRawDataPage(
|
|
|
|
dataType: dataType,
|
|
|
|
startTime: range.startTime,
|
|
|
|
endTime: range.endTime,
|
|
|
|
pageToken: pageToken,
|
|
|
|
for (final segment in fetched.segments) {
|
|
|
|
final page = segment.page;
|
|
|
|
pageCount += 1;
|
|
|
|
if (page.items.isNotEmpty) {
|
|
|
|
final pageStoredCount = await _localStore.upsertRawDataBatch(
|
|
|
|
dataType: fetched.dataType,
|
|
|
|
items: page.items,
|
|
|
|
);
|
|
|
|
pageCount += 1;
|
|
|
|
storedCount += pageStoredCount;
|
|
|
|
_log(
|
|
|
|
'page_fetched dataType=$dataType '
|
|
|
|
'segment=${rangeIndex + 1}/${fetchRanges.length} '
|
|
|
|
'page=$pageCount items=${page.items.length} '
|
|
|
|
'nextPageToken=${page.nextPageToken ?? ''}',
|
|
|
|
'page_stored dataType=${fetched.dataType} '
|
|
|
|
'segment=${segment.segmentIndex + 1}/${fetched.segmentCount} '
|
|
|
|
'fetchedItems=${page.items.length} '
|
|
|
|
'storedItems=$pageStoredCount totalStored=$storedCount',
|
|
|
|
);
|
|
|
|
|
|
|
|
if (page.items.isNotEmpty) {
|
|
|
|
final pageStoredCount = await _localStore.upsertRawDataBatch(
|
|
|
|
dataType: dataType,
|
|
|
|
items: page.items,
|
|
|
|
);
|
|
|
|
storedCount += pageStoredCount;
|
|
|
|
_log(
|
|
|
|
'page_stored dataType=$dataType '
|
|
|
|
'segment=${rangeIndex + 1}/${fetchRanges.length} '
|
|
|
|
'fetchedItems=${page.items.length} '
|
|
|
|
'storedItems=$pageStoredCount totalStored=$storedCount',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
pageToken = page.nextPageToken;
|
|
|
|
} while (pageToken != null && pageToken.isNotEmpty);
|
|
|
|
}
|
|
|
|
|
|
|
|
_log(
|
|
|
|
'segment_finish dataType=$dataType '
|
|
|
|
'segment=${rangeIndex + 1}/${fetchRanges.length}',
|
|
|
|
'segment_finish dataType=${fetched.dataType} '
|
|
|
|
'segment=${segment.segmentIndex + 1}/${fetched.segmentCount}',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_log(
|
|
|
|
'sync_finish dataType=$dataType '
|
|
|
|
'startTime=$startTime endTime=$endTime '
|
|
|
|
'chunkDays=$fetchChunkDays rangeCount=${fetchRanges.length} '
|
|
|
|
'sync_finish dataType=${fetched.dataType} '
|
|
|
|
'startTime=${fetched.startTime} endTime=${fetched.endTime} '
|
|
|
|
'chunkDays=${fetched.fetchChunkDays} rangeCount=${fetched.segmentCount} '
|
|
|
|
'pageCount=$pageCount '
|
|
|
|
'storedCount=$storedCount',
|
|
|
|
);
|
|
|
|
|
|
|
|
return OhosHealthRawDataSyncResult(
|
|
|
|
dataType: dataType,
|
|
|
|
startTime: startTime,
|
|
|
|
endTime: endTime,
|
|
|
|
segmentCount: fetchRanges.length,
|
|
|
|
dataType: fetched.dataType,
|
|
|
|
startTime: fetched.startTime,
|
|
|
|
endTime: fetched.endTime,
|
|
|
|
segmentCount: fetched.segmentCount,
|
|
|
|
pageCount: pageCount,
|
|
|
|
storedCount: storedCount,
|
|
|
|
);
|
|
...
|
...
|
@@ -350,7 +438,6 @@ abstract class OhosHealthRawDataRemoteDataSource { |
|
|
|
required int dataType,
|
|
|
|
required int startTime,
|
|
|
|
required int endTime,
|
|
|
|
String? pageToken,
|
|
|
|
});
|
|
|
|
|
|
|
|
Future<V2ActivityTarget?> fetchActivityGoal();
|
|
...
|
...
|
@@ -410,7 +497,6 @@ class OhosHarmonyHealthRawDataRemoteDataSource |
|
|
|
required int dataType,
|
|
|
|
required int startTime,
|
|
|
|
required int endTime,
|
|
|
|
String? pageToken,
|
|
|
|
}) async {
|
|
|
|
final startDate = _dateKeyFromUnixSeconds(startTime);
|
|
|
|
final endDate = _endDateKeyFromUnixSeconds(endTime);
|
|
...
|
...
|
@@ -552,7 +638,6 @@ class TodoOhosHealthRawDataRemoteDataSource |
|
|
|
required int dataType,
|
|
|
|
required int startTime,
|
|
|
|
required int endTime,
|
|
|
|
String? pageToken,
|
|
|
|
}) async {
|
|
|
|
// TODO: Call the OHOS raw-data API after the endpoint and response schema
|
|
|
|
// are available.
|
|
...
|
...
|
@@ -607,11 +692,9 @@ class TodoOhosHealthRawDataLocalStore implements OhosHealthRawDataLocalStore { |
|
|
|
class OhosHealthRawDataPage {
|
|
|
|
const OhosHealthRawDataPage({
|
|
|
|
required this.items,
|
|
|
|
this.nextPageToken,
|
|
|
|
});
|
|
|
|
|
|
|
|
final List<OhosHealthRawDataItem> items;
|
|
|
|
final String? nextPageToken;
|
|
|
|
}
|
|
|
|
|
|
|
|
class OhosHealthRawDataItem {
|
|
...
|
...
|
@@ -636,6 +719,36 @@ class OhosHealthRawDataFetchRange { |
|
|
|
final int endTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
class _FetchedRawDataSync {
|
|
|
|
const _FetchedRawDataSync({
|
|
|
|
required this.dataType,
|
|
|
|
required this.startTime,
|
|
|
|
required this.endTime,
|
|
|
|
required this.fetchChunkDays,
|
|
|
|
required this.segments,
|
|
|
|
});
|
|
|
|
|
|
|
|
final int dataType;
|
|
|
|
final int startTime;
|
|
|
|
final int endTime;
|
|
|
|
final int fetchChunkDays;
|
|
|
|
final List<_FetchedRawDataSegment> segments;
|
|
|
|
|
|
|
|
int get segmentCount => segments.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
class _FetchedRawDataSegment {
|
|
|
|
const _FetchedRawDataSegment({
|
|
|
|
required this.segmentIndex,
|
|
|
|
required this.range,
|
|
|
|
required this.page,
|
|
|
|
});
|
|
|
|
|
|
|
|
final int segmentIndex;
|
|
|
|
final OhosHealthRawDataFetchRange range;
|
|
|
|
final OhosHealthRawDataPage page;
|
|
|
|
}
|
|
|
|
|
|
|
|
class OhosHealthRawDataSyncResult {
|
|
|
|
const OhosHealthRawDataSyncResult({
|
|
|
|
required this.dataType,
|
...
|
...
|
|