summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNickel Cheng <nickelc@google.com>2023-11-30 21:46:20 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2023-11-30 21:46:20 +0000
commit884b6debe1c18825a015de95ed8769c7d6f6aa92 (patch)
treee304a2cca0dd19a5538a93d4223d6677633b8c20
parentab59a4305c187c91248c2108f1c2bdf0fd08d32d (diff)
parentc6b6342aed7bc47a50b9f97ed38a12a7482fe72c (diff)
downloadHealthFitness-884b6debe1c18825a015de95ed8769c7d6f6aa92.tar.gz
Merge "Remove DST records where local start time is later than local end time" into udc-mainline-prod
-rw-r--r--service/java/com/android/server/healthconnect/storage/datatypehelpers/aggregation/PriorityRecordsAggregator.java7
-rw-r--r--tests/cts/src/android/healthconnect/cts/HealthConnectManagerTest.java110
2 files changed, 100 insertions, 17 deletions
diff --git a/service/java/com/android/server/healthconnect/storage/datatypehelpers/aggregation/PriorityRecordsAggregator.java b/service/java/com/android/server/healthconnect/storage/datatypehelpers/aggregation/PriorityRecordsAggregator.java
index 2e68637a..5af3e163 100644
--- a/service/java/com/android/server/healthconnect/storage/datatypehelpers/aggregation/PriorityRecordsAggregator.java
+++ b/service/java/com/android/server/healthconnect/storage/datatypehelpers/aggregation/PriorityRecordsAggregator.java
@@ -190,6 +190,13 @@ public class PriorityRecordsAggregator {
return null;
}
+ // TODO(b/313924267): workaround for b/308467442, should be remove once we have a long term
+ // solution
+ if (data.getStartTime() > data.getEndTime()) {
+ // skip records with start time > end time to keep the algorithm functional
+ return null;
+ }
+
mTimestampsBuffer.add(data.getStartTimestamp());
mTimestampsBuffer.add(data.getEndTimestamp());
return data;
diff --git a/tests/cts/src/android/healthconnect/cts/HealthConnectManagerTest.java b/tests/cts/src/android/healthconnect/cts/HealthConnectManagerTest.java
index 89532755..ae924713 100644
--- a/tests/cts/src/android/healthconnect/cts/HealthConnectManagerTest.java
+++ b/tests/cts/src/android/healthconnect/cts/HealthConnectManagerTest.java
@@ -40,10 +40,17 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import static java.time.ZoneOffset.UTC;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.HOURS;
+import static java.time.temporal.ChronoUnit.MINUTES;
+
import android.Manifest;
import android.app.UiAutomation;
import android.content.Context;
+import android.health.connect.AggregateRecordsGroupedByDurationResponse;
import android.health.connect.AggregateRecordsRequest;
+import android.health.connect.AggregateRecordsResponse;
import android.health.connect.DeleteUsingFiltersRequest;
import android.health.connect.HealthConnectDataState;
import android.health.connect.HealthConnectException;
@@ -99,7 +106,6 @@ import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneOffset;
-import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -656,7 +662,7 @@ public class HealthConnectManagerTest {
@Test
public void testReadRecords_multiplePagesSameStartTimeRecords_paginatedCorrectly()
throws Exception {
- Instant startTime = Instant.now().minus(1, ChronoUnit.DAYS);
+ Instant startTime = Instant.now().minus(1, DAYS);
insertRecords(
List.of(
@@ -712,6 +718,60 @@ public class HealthConnectManagerTest {
}
@Test
+ public void testAggregation_stepsCountTotal_acrossDST_works() throws Exception {
+ ZoneOffset utcPlusOne = ZoneOffset.ofTotalSeconds(UTC.getTotalSeconds() + 3600);
+
+ Instant midNight = Instant.now().truncatedTo(DAYS);
+
+ Instant t0057 = midNight.plus(57, MINUTES);
+ Instant t0058 = midNight.plus(58, MINUTES);
+ Instant t0059 = midNight.plus(59, MINUTES);
+ Instant t0100 = midNight.plus(1, HOURS);
+ Instant t0300 = midNight.plus(3, HOURS);
+ Instant t0400 = midNight.plus(4, HOURS);
+
+ List<Record> records =
+ Arrays.asList(
+ getStepsRecord(
+ t0057, utcPlusOne, t0058, utcPlusOne, 12), // 1:57-1:58 in test
+ // this will be removed by the workaround
+ getStepsRecord(t0059, utcPlusOne, t0100, UTC, 16), // 1:59-1:00 in test
+ getStepsRecord(t0300, UTC, t0400, UTC, 250));
+ TestUtils.insertRecords(records);
+ LocalDateTime startOfToday = LocalDateTime.now(UTC).truncatedTo(DAYS);
+ AggregateRecordsRequest<Long> aggregateRecordsRequest =
+ new AggregateRecordsRequest.Builder<Long>(
+ new LocalTimeRangeFilter.Builder()
+ .setStartTime(startOfToday.plus(1, HOURS))
+ .setEndTime(startOfToday.plus(4, HOURS))
+ .build())
+ .addAggregationType(STEPS_COUNT_TOTAL)
+ .build();
+ assertThat(aggregateRecordsRequest.getAggregationTypes()).isNotNull();
+ assertThat(aggregateRecordsRequest.getTimeRangeFilter()).isNotNull();
+ assertThat(aggregateRecordsRequest.getDataOriginsFilters()).isNotNull();
+
+ AggregateRecordsResponse<Long> aggregateResponse =
+ TestUtils.getAggregateResponse(aggregateRecordsRequest);
+ assertThat(aggregateResponse.get(STEPS_COUNT_TOTAL)).isEqualTo(262);
+
+ List<AggregateRecordsGroupedByDurationResponse<Long>> groupByResponse =
+ TestUtils.getAggregateResponseGroupByDuration(
+ aggregateRecordsRequest, Duration.ofHours(1));
+ assertThat(groupByResponse.get(0).getStartTime()).isEqualTo(midNight);
+ assertThat(groupByResponse.get(0).getEndTime()).isEqualTo(t0100);
+ assertThat(groupByResponse.get(0).getZoneOffset(STEPS_COUNT_TOTAL)).isEqualTo(utcPlusOne);
+ assertThat(groupByResponse.get(0).get(STEPS_COUNT_TOTAL)).isEqualTo(12);
+ assertThat(groupByResponse.get(1).getStartTime()).isEqualTo(t0100.plus(1, HOURS));
+ assertThat(groupByResponse.get(1).getEndTime()).isEqualTo(t0300);
+ assertThat(groupByResponse.get(1).getZoneOffset(STEPS_COUNT_TOTAL)).isNull();
+ assertThat(groupByResponse.get(2).getStartTime()).isEqualTo(t0300);
+ assertThat(groupByResponse.get(2).getEndTime()).isEqualTo(t0400);
+ assertThat(groupByResponse.get(2).getZoneOffset(STEPS_COUNT_TOTAL)).isEqualTo(UTC);
+ assertThat(groupByResponse.get(2).get(STEPS_COUNT_TOTAL)).isEqualTo(250);
+ }
+
+ @Test
public void testAutoDeleteApis() throws InterruptedException {
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
@@ -1652,7 +1712,7 @@ public class HealthConnectManagerTest {
AggregateRecordsRequest<Long> aggregateRecordsRequest =
new AggregateRecordsRequest.Builder<Long>(
new TimeInstantRangeFilter.Builder()
- .setStartTime(Instant.now().minus(3, ChronoUnit.DAYS))
+ .setStartTime(Instant.now().minus(3, DAYS))
.setEndTime(Instant.now())
.build())
.addAggregationType(STEPS_COUNT_TOTAL)
@@ -1682,9 +1742,8 @@ public class HealthConnectManagerTest {
TestUtils.getAggregateResponseGroupByPeriod(
new AggregateRecordsRequest.Builder<Long>(
new LocalTimeRangeFilter.Builder()
- .setStartTime(
- LocalDateTime.now(ZoneOffset.UTC).minusDays(2))
- .setEndTime(LocalDateTime.now(ZoneOffset.UTC))
+ .setStartTime(LocalDateTime.now(UTC).minusDays(2))
+ .setEndTime(LocalDateTime.now(UTC))
.build())
.addAggregationType(STEPS_COUNT_TOTAL)
.build(),
@@ -1895,7 +1954,7 @@ public class HealthConnectManagerTest {
.anyMatch(list -> !list.isEmpty());
}
- private void deleteAllStagedRemoteData()
+ private static void deleteAllStagedRemoteData()
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
try {
Context context = ApplicationProvider.getApplicationContext();
@@ -1916,7 +1975,7 @@ public class HealthConnectManagerTest {
}
}
- private void verifyRecordTypeResponse(
+ private static void verifyRecordTypeResponse(
Map<Class<? extends Record>, RecordTypeInfoResponse> responses,
HashMap<Class<? extends Record>, TestUtils.RecordTypeInfoTestResponse>
expectedResponse) {
@@ -1940,14 +1999,14 @@ public class HealthConnectManagerTest {
});
}
- private List<Record> getTestRecords() {
+ private static List<Record> getTestRecords() {
return Arrays.asList(
getStepsRecord(/*clientRecordId=*/ null, /*packageName=*/ ""),
getHeartRateRecord(),
getBasalMetabolicRateRecord());
}
- private Record setTestRecordId(Record record, String id) {
+ private static Record setTestRecordId(Record record, String id) {
Metadata metadata = record.getMetadata();
Metadata metadataWithId =
new Metadata.Builder()
@@ -2018,7 +2077,7 @@ public class HealthConnectManagerTest {
return readRecords;
}
- private StepsRecord getStepsRecord(String clientRecordId, String packageName) {
+ private static StepsRecord getStepsRecord(String clientRecordId, String packageName) {
return getStepsRecord(
clientRecordId,
packageName,
@@ -2027,7 +2086,7 @@ public class HealthConnectManagerTest {
Instant.now().plusMillis(1000));
}
- private StepsRecord getStepsRecord(
+ private static StepsRecord getStepsRecord(
String clientRecordId,
String packageName,
int count,
@@ -2044,7 +2103,24 @@ public class HealthConnectManagerTest {
.build();
}
- private HeartRateRecord getHeartRateRecord() {
+ private static StepsRecord getStepsRecord(
+ Instant startTime,
+ ZoneOffset startOffset,
+ Instant endTime,
+ ZoneOffset endOffset,
+ int count) {
+ StepsRecord.Builder builder =
+ new StepsRecord.Builder(new Metadata.Builder().build(), startTime, endTime, count);
+ if (startOffset != null) {
+ builder.setStartZoneOffset(startOffset);
+ }
+ if (endOffset != null) {
+ builder.setEndZoneOffset(endOffset);
+ }
+ return builder.build();
+ }
+
+ private static HeartRateRecord getHeartRateRecord() {
HeartRateRecord.HeartRateSample heartRateSample =
new HeartRateRecord.HeartRateSample(72, Instant.now().plusMillis(100));
ArrayList<HeartRateRecord.HeartRateSample> heartRateSamples = new ArrayList<>();
@@ -2062,12 +2138,12 @@ public class HealthConnectManagerTest {
.build();
}
- private BasalMetabolicRateRecord getBasalMetabolicRateRecord() {
+ private static BasalMetabolicRateRecord getBasalMetabolicRateRecord() {
return getBasalMetabolicRateRecord(
/*clientRecordId=*/ null, /*bmr=*/ Power.fromWatts(100.0), Instant.now());
}
- private BasalMetabolicRateRecord getBasalMetabolicRateRecord(
+ private static BasalMetabolicRateRecord getBasalMetabolicRateRecord(
String clientRecordId, Power bmr, Instant time) {
Device device = getPhoneDevice();
DataOrigin dataOrigin = getDataOrigin();
@@ -2079,7 +2155,7 @@ public class HealthConnectManagerTest {
return new BasalMetabolicRateRecord.Builder(testMetadataBuilder.build(), time, bmr).build();
}
- private HydrationRecord getHydrationRecord(
+ private static HydrationRecord getHydrationRecord(
String clientRecordId, Instant startTime, Instant endTime, Volume volume) {
Device device = getPhoneDevice();
DataOrigin dataOrigin = getDataOrigin();
@@ -2092,7 +2168,7 @@ public class HealthConnectManagerTest {
.build();
}
- private NutritionRecord getNutritionRecord(
+ private static NutritionRecord getNutritionRecord(
String clientRecordId, Instant startTime, Instant endTime, Mass protein) {
Device device = getPhoneDevice();
DataOrigin dataOrigin = getDataOrigin();