1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.healthconnect.cts.utils; 18 19 import static android.health.connect.datatypes.Metadata.RECORDING_METHOD_ACTIVELY_RECORDED; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import android.content.Context; 24 import android.health.connect.changelog.ChangeLogTokenRequest; 25 import android.health.connect.datatypes.BasalMetabolicRateRecord; 26 import android.health.connect.datatypes.DataOrigin; 27 import android.health.connect.datatypes.Device; 28 import android.health.connect.datatypes.DistanceRecord; 29 import android.health.connect.datatypes.ExerciseCompletionGoal; 30 import android.health.connect.datatypes.ExerciseLap; 31 import android.health.connect.datatypes.ExerciseRoute; 32 import android.health.connect.datatypes.ExerciseSegment; 33 import android.health.connect.datatypes.ExerciseSegmentType; 34 import android.health.connect.datatypes.ExerciseSessionRecord; 35 import android.health.connect.datatypes.ExerciseSessionType; 36 import android.health.connect.datatypes.HeartRateRecord; 37 import android.health.connect.datatypes.Metadata; 38 import android.health.connect.datatypes.PlannedExerciseBlock; 39 import android.health.connect.datatypes.PlannedExerciseSessionRecord; 40 import android.health.connect.datatypes.PlannedExerciseStep; 41 import android.health.connect.datatypes.Record; 42 import android.health.connect.datatypes.SleepSessionRecord; 43 import android.health.connect.datatypes.StepsRecord; 44 import android.health.connect.datatypes.TotalCaloriesBurnedRecord; 45 import android.health.connect.datatypes.WeightRecord; 46 import android.health.connect.datatypes.units.Energy; 47 import android.health.connect.datatypes.units.Length; 48 import android.health.connect.datatypes.units.Mass; 49 import android.health.connect.datatypes.units.Power; 50 51 import androidx.annotation.Nullable; 52 import androidx.test.core.app.ApplicationProvider; 53 54 import java.time.Instant; 55 import java.time.ZoneOffset; 56 import java.time.temporal.ChronoUnit; 57 import java.util.ArrayList; 58 import java.util.Arrays; 59 import java.util.List; 60 import java.util.UUID; 61 62 public final class DataFactory { 63 // truncate to MILLIS because HC does, so reduce flakiness in some tests. 64 public static final Instant NOW = Instant.now().truncatedTo(ChronoUnit.MILLIS); 65 public static final Instant SESSION_START_TIME = NOW.minus(10, ChronoUnit.DAYS); 66 public static final Instant SESSION_END_TIME = SESSION_START_TIME.plus(1, ChronoUnit.HOURS); 67 public static final long DEFAULT_LONG = -1; 68 public static final int DEFAULT_PAGE_SIZE = 1000; 69 public static final int MINIMUM_PAGE_SIZE = 1; 70 public static final int MAXIMUM_PAGE_SIZE = 5000; 71 buildDevice()72 public static Device buildDevice() { 73 return new Device.Builder() 74 .setManufacturer("google") 75 .setModel("Pixel4a") 76 .setType(2) 77 .build(); 78 } 79 generateMetadata()80 public static Metadata generateMetadata() { 81 return generateMetadata(UUID.randomUUID().toString()); 82 } 83 84 /** Generates a {@link Metadata} with specific {@code id}. */ generateMetadata(String id)85 public static Metadata generateMetadata(String id) { 86 return generateMetadata(id, "clientRecordId" + Math.random()); 87 } 88 89 /** Generates a {@link Metadata} with specific {@code id} and {@code clientId}. */ generateMetadata(String id, String clientId)90 public static Metadata generateMetadata(String id, String clientId) { 91 Context context = ApplicationProvider.getApplicationContext(); 92 return new Metadata.Builder() 93 .setDevice(buildDevice()) 94 .setId(id) 95 .setClientRecordId(clientId) 96 .setDataOrigin( 97 new DataOrigin.Builder().setPackageName(context.getPackageName()).build()) 98 .setRecordingMethod(Metadata.RECORDING_METHOD_UNKNOWN) 99 .build(); 100 } 101 102 /** Generates a {@link Metadata} with a specific {@code clientId}. */ generateMetadataWithClientId(String clientId)103 public static Metadata generateMetadataWithClientId(String clientId) { 104 return generateMetadata(UUID.randomUUID().toString(), clientId); 105 } 106 getEmptyMetadata()107 public static Metadata getEmptyMetadata() { 108 return new Metadata.Builder().build(); 109 } 110 111 /** Creates a {@link Metadata} with the given record id. */ getMetadataForId(String id)112 public static Metadata getMetadataForId(String id) { 113 return new Metadata.Builder().setId(id).build(); 114 } 115 116 /** Creates a {@link Metadata} with the given record id and data origin. */ getMetadataForId(String id, DataOrigin dataOrigin)117 public static Metadata getMetadataForId(String id, DataOrigin dataOrigin) { 118 return new Metadata.Builder().setId(id).setDataOrigin(dataOrigin).build(); 119 } 120 121 /** Creates a {@link Metadata} with the given client record id. */ getMetadataForClientId(String clientId)122 public static Metadata getMetadataForClientId(String clientId) { 123 return new Metadata.Builder().setClientRecordId(clientId).build(); 124 } 125 126 /** Creates a {@link Metadata} with the given client record id. */ getMetadataForClientId(String clientId, DataOrigin dataOrigin)127 public static Metadata getMetadataForClientId(String clientId, DataOrigin dataOrigin) { 128 return new Metadata.Builder().setClientRecordId(clientId).setDataOrigin(dataOrigin).build(); 129 } 130 131 /** Creates a {@link Metadata} with the given client record id. */ getMetadataForClientIdAndVersion(String clientId, long clientVersion)132 public static Metadata getMetadataForClientIdAndVersion(String clientId, long clientVersion) { 133 return new Metadata.Builder() 134 .setClientRecordId(clientId) 135 .setClientRecordVersion(clientVersion) 136 .build(); 137 } 138 139 /** Creates a {@link Metadata} with the given data origin. */ getMetadata(DataOrigin dataOrigin)140 public static Metadata getMetadata(DataOrigin dataOrigin) { 141 return new Metadata.Builder().setDataOrigin(dataOrigin).build(); 142 } 143 144 /** Creates a {@link DataOrigin} with the given package name. */ getDataOrigin(String packageName)145 public static DataOrigin getDataOrigin(String packageName) { 146 return new DataOrigin.Builder().setPackageName(packageName).build(); 147 } 148 149 /** Creates a list of {@link DataOrigin} from a list of package names. */ getDataOrigins(String... packageNames)150 public static List<DataOrigin> getDataOrigins(String... packageNames) { 151 return Arrays.stream(packageNames).map(DataFactory::getDataOrigin).toList(); 152 } 153 buildSleepSession()154 public static SleepSessionRecord buildSleepSession() { 155 return buildSleepSession(generateMetadata()); 156 } 157 158 /** Builds a {@link SleepSessionRecord} with a specific {@code clientId}. */ buildSleepSessionWithClientId(String clientId)159 public static SleepSessionRecord buildSleepSessionWithClientId(String clientId) { 160 return buildSleepSession(generateMetadataWithClientId(clientId)); 161 } 162 163 /** Builds a {@link SleepSessionRecord} with empty {@link Metadata}. */ buildSleepSessionWithEmptyMetadata()164 public static SleepSessionRecord buildSleepSessionWithEmptyMetadata() { 165 return buildSleepSession(getEmptyMetadata()); 166 } 167 168 /** Builds a {@link SleepSessionRecord} with a specific {@link Metadata}. */ buildSleepSession(Metadata metadata)169 public static SleepSessionRecord buildSleepSession(Metadata metadata) { 170 return new SleepSessionRecord.Builder(metadata, SESSION_START_TIME, SESSION_END_TIME) 171 .setNotes("warm") 172 .setTitle("Afternoon nap") 173 .setStages( 174 List.of( 175 new SleepSessionRecord.Stage( 176 SESSION_START_TIME, 177 SESSION_START_TIME.plusSeconds(300), 178 SleepSessionRecord.StageType.STAGE_TYPE_SLEEPING_LIGHT), 179 new SleepSessionRecord.Stage( 180 SESSION_START_TIME.plusSeconds(300), 181 SESSION_START_TIME.plusSeconds(600), 182 SleepSessionRecord.StageType.STAGE_TYPE_SLEEPING_REM), 183 new SleepSessionRecord.Stage( 184 SESSION_START_TIME.plusSeconds(900), 185 SESSION_START_TIME.plusSeconds(1200), 186 SleepSessionRecord.StageType.STAGE_TYPE_SLEEPING_DEEP))) 187 .build(); 188 } 189 190 /** Builds a {@link ExerciseSessionRecord} with {@link #generateMetadata()}. */ buildExerciseSession()191 public static ExerciseSessionRecord buildExerciseSession() { 192 return buildExerciseSession(generateMetadata()); 193 } 194 195 /** Builds a {@link ExerciseSessionRecord} with an empty {@link Metadata}. */ buildExerciseSessionWithEmptyMetadata()196 public static ExerciseSessionRecord buildExerciseSessionWithEmptyMetadata() { 197 return buildExerciseSession(getEmptyMetadata()); 198 } 199 200 /** Builds a {@link ExerciseSessionRecord} with a specific {@code clientId}. */ buildExerciseSessionWithClientId(String clientId)201 public static ExerciseSessionRecord buildExerciseSessionWithClientId(String clientId) { 202 return buildExerciseSession(generateMetadataWithClientId(clientId)); 203 } 204 205 /** Builds a {@link ExerciseSessionRecord} with a specific {@link Metadata}. */ buildExerciseSession(Metadata metadata)206 public static ExerciseSessionRecord buildExerciseSession(Metadata metadata) { 207 return new ExerciseSessionRecord.Builder( 208 metadata, 209 SESSION_START_TIME, 210 SESSION_END_TIME, 211 ExerciseSessionType.EXERCISE_SESSION_TYPE_OTHER_WORKOUT) 212 .setRoute(buildExerciseRoute()) 213 .setLaps( 214 List.of( 215 new ExerciseLap.Builder( 216 SESSION_START_TIME, 217 SESSION_START_TIME.plusSeconds(20)) 218 .setLength(Length.fromMeters(10)) 219 .build(), 220 new ExerciseLap.Builder( 221 SESSION_END_TIME.minusSeconds(20), SESSION_END_TIME) 222 .build())) 223 .setSegments( 224 List.of( 225 new ExerciseSegment.Builder( 226 SESSION_START_TIME.plusSeconds(1), 227 SESSION_START_TIME.plusSeconds(10), 228 ExerciseSegmentType 229 .EXERCISE_SEGMENT_TYPE_BENCH_PRESS) 230 .build(), 231 new ExerciseSegment.Builder( 232 SESSION_START_TIME.plusSeconds(21), 233 SESSION_START_TIME.plusSeconds(124), 234 ExerciseSegmentType.EXERCISE_SEGMENT_TYPE_BURPEE) 235 .setRepetitionsCount(15) 236 .build())) 237 .setEndZoneOffset(ZoneOffset.MAX) 238 .setStartZoneOffset(ZoneOffset.MIN) 239 .setNotes("rain") 240 .setTitle("Morning training") 241 .build(); 242 } 243 buildExerciseRoute()244 public static ExerciseRoute buildExerciseRoute() { 245 return new ExerciseRoute( 246 List.of( 247 buildLocationTimePoint(SESSION_START_TIME), 248 buildLocationTimePoint(SESSION_START_TIME), 249 buildLocationTimePoint(SESSION_START_TIME))); 250 } 251 buildLocationTimePoint(Instant startTime)252 public static ExerciseRoute.Location buildLocationTimePoint(Instant startTime) { 253 return new ExerciseRoute.Location.Builder( 254 Instant.ofEpochMilli( 255 (long) (startTime.toEpochMilli() + 10 + Math.random() * 50)), 256 Math.random() * 50, 257 Math.random() * 50) 258 .build(); 259 } 260 261 /** Returns a training plan builder, prepopulated with test data. */ plannedExerciseSession(Metadata metadata)262 public static PlannedExerciseSessionRecord.Builder plannedExerciseSession(Metadata metadata) { 263 PlannedExerciseSessionRecord.Builder sessionBuilder = 264 new PlannedExerciseSessionRecord.Builder( 265 metadata, 266 ExerciseSessionType.EXERCISE_SESSION_TYPE_BIKING, 267 SESSION_START_TIME, 268 SESSION_END_TIME); 269 sessionBuilder.setNotes("Some notes"); 270 sessionBuilder.setTitle("Some training plan"); 271 sessionBuilder.setStartZoneOffset(ZoneOffset.UTC); 272 sessionBuilder.setEndZoneOffset(ZoneOffset.UTC); 273 var stepBuilder = 274 new PlannedExerciseStep.Builder( 275 ExerciseSegmentType.EXERCISE_SEGMENT_TYPE_BIKING, 276 PlannedExerciseStep.EXERCISE_CATEGORY_ACTIVE, 277 new ExerciseCompletionGoal.DistanceGoal(Length.fromMeters(100))); 278 var blockBuilder = new PlannedExerciseBlock.Builder(3).setDescription("Main set"); 279 blockBuilder.setSteps(List.of(stepBuilder.build())); 280 sessionBuilder.setBlocks(List.of(blockBuilder.build())); 281 282 return sessionBuilder; 283 } 284 285 /** Gets a {@link HeartRateRecord} with an empty {@link Metadata}. */ getHeartRateRecordWithEmptyMetadata()286 public static HeartRateRecord getHeartRateRecordWithEmptyMetadata() { 287 return getHeartRateRecord(72, getEmptyMetadata()); 288 } 289 290 /** Gets a {@link HeartRateRecord} with a specific heart rate and {@link Metadata}. */ getHeartRateRecord(int heartRate, Metadata metadata)291 public static HeartRateRecord getHeartRateRecord(int heartRate, Metadata metadata) { 292 Instant instant = NOW; 293 HeartRateRecord.HeartRateSample heartRateSample = 294 new HeartRateRecord.HeartRateSample(heartRate, instant.plusMillis(10)); 295 return new HeartRateRecord.Builder( 296 metadata, instant, instant.plusMillis(1000), List.of(heartRateSample)) 297 .build(); 298 } 299 getHeartRateRecord()300 public static HeartRateRecord getHeartRateRecord() { 301 return getHeartRateRecord(72); 302 } 303 getHeartRateRecord(int heartRate, String clientId)304 public static HeartRateRecord getHeartRateRecord(int heartRate, String clientId) { 305 return getHeartRateRecord(heartRate, NOW.plusMillis(100), clientId); 306 } 307 getHeartRateRecord(int heartRate)308 public static HeartRateRecord getHeartRateRecord(int heartRate) { 309 return getHeartRateRecord(heartRate, NOW.plusMillis(100)); 310 } 311 getHeartRateRecord(int heartRate, Instant instant)312 public static HeartRateRecord getHeartRateRecord(int heartRate, Instant instant) { 313 return getHeartRateRecord(heartRate, instant, "HR" + Math.random()); 314 } 315 getHeartRateRecord( List<HeartRateRecord.HeartRateSample> samples, Instant start, Instant end)316 public static HeartRateRecord getHeartRateRecord( 317 List<HeartRateRecord.HeartRateSample> samples, Instant start, Instant end) { 318 return new HeartRateRecord.Builder(getEmptyMetadata(), start, end, samples).build(); 319 } 320 getHeartRateRecord( int heartRate, Instant instant, String clientId)321 public static HeartRateRecord getHeartRateRecord( 322 int heartRate, Instant instant, String clientId) { 323 String packageName = ApplicationProvider.getApplicationContext().getPackageName(); 324 HeartRateRecord.HeartRateSample heartRateSample = 325 new HeartRateRecord.HeartRateSample(heartRate, instant); 326 ArrayList<HeartRateRecord.HeartRateSample> heartRateSamples = new ArrayList<>(); 327 heartRateSamples.add(heartRateSample); 328 heartRateSamples.add(heartRateSample); 329 Device device = buildDevice(); 330 DataOrigin dataOrigin = new DataOrigin.Builder().setPackageName(packageName).build(); 331 332 return new HeartRateRecord.Builder( 333 new Metadata.Builder() 334 .setDevice(device) 335 .setDataOrigin(dataOrigin) 336 .setClientRecordId(clientId) 337 .build(), 338 instant.minusMillis(100), 339 instant.plusMillis(100), 340 heartRateSamples) 341 .build(); 342 } 343 344 /** Creates and returns a {@link WeightRecord} with the specified arguments. */ getWeightRecord(double grams, Instant time)345 public static WeightRecord getWeightRecord(double grams, Instant time) { 346 return new WeightRecord.Builder(new Metadata.Builder().build(), time, Mass.fromGrams(grams)) 347 .build(); 348 } 349 getWeightRecord(double weight, Instant time, ZoneOffset offset)350 public static WeightRecord getWeightRecord(double weight, Instant time, ZoneOffset offset) { 351 return new WeightRecord.Builder(getEmptyMetadata(), time, Mass.fromGrams(weight)) 352 .setZoneOffset(offset) 353 .build(); 354 } 355 356 /** Returns a new weight record with the specified fields. */ getWeightRecord(double grams, Instant time, String clientId)357 public static WeightRecord getWeightRecord(double grams, Instant time, String clientId) { 358 return new WeightRecord.Builder( 359 getMetadataForClientId(clientId), time, Mass.fromGrams(grams)) 360 .build(); 361 } 362 getStepsRecordWithEmptyMetaData()363 public static StepsRecord getStepsRecordWithEmptyMetaData() { 364 return getStepsRecord(10, getEmptyMetadata()); 365 } 366 getStepsRecord()367 public static StepsRecord getStepsRecord() { 368 return getStepsRecord(10); 369 } 370 371 /** Creates and returns a {@link StepsRecord} with the specified arguments. */ getStepsRecord(long steps)372 public static StepsRecord getStepsRecord(long steps) { 373 return getStepsRecord(steps, generateMetadata()); 374 } 375 376 /** Creates and returns a {@link StepsRecord} with the specified arguments. */ getStepsRecord(long steps, String clientId)377 public static StepsRecord getStepsRecord(long steps, String clientId) { 378 return getStepsRecord(steps, getMetadataForClientId(clientId)); 379 } 380 381 /** Creates and returns a {@link StepsRecord} with the specified metadata. */ getStepsRecord(long steps, Metadata metadata)382 public static StepsRecord getStepsRecord(long steps, Metadata metadata) { 383 return new StepsRecord.Builder(metadata, NOW, NOW.plusMillis(1000), steps).build(); 384 } 385 386 /** Creates and returns a {@link StepsRecord} with the specified arguments. */ getStepsRecord(long steps, Instant start, Instant end)387 public static StepsRecord getStepsRecord(long steps, Instant start, Instant end) { 388 return new StepsRecord.Builder(getEmptyMetadata(), start, end, steps).build(); 389 } 390 391 /** Creates and returns a {@link StepsRecord} with the specified arguments. */ getStepsRecord( long steps, Instant start, Instant end, String clientId)392 public static StepsRecord getStepsRecord( 393 long steps, Instant start, Instant end, String clientId) { 394 return new StepsRecord.Builder(getMetadataForClientId(clientId), start, end, steps).build(); 395 } 396 getStepsRecord(String id)397 public static StepsRecord getStepsRecord(String id) { 398 return new StepsRecord.Builder(generateMetadata(id), NOW, NOW.plusMillis(1000), 10).build(); 399 } 400 401 /** Creates and returns a {@link StepsRecord} with default arguments. */ getCompleteStepsRecord()402 public static StepsRecord getCompleteStepsRecord() { 403 return getCompleteStepsRecord( 404 NOW, NOW.plusMillis(1000), /* clientRecordId= */ "SR" + Math.random()); 405 } 406 407 /** Creates and returns a {@link StepsRecord} with the specified arguments. */ getCompleteStepsRecord( Instant startTime, Instant endTime, String clientRecordId)408 public static StepsRecord getCompleteStepsRecord( 409 Instant startTime, Instant endTime, String clientRecordId) { 410 return getCompleteStepsRecord(startTime, endTime, clientRecordId, /* count= */ 10); 411 } 412 413 /** Creates and returns a {@link StepsRecord} with the specified arguments. */ getCompleteStepsRecord( String id, Instant startTime, Instant endTime, long count)414 public static StepsRecord getCompleteStepsRecord( 415 String id, Instant startTime, Instant endTime, long count) { 416 return getCompleteStepsRecord( 417 id, 418 startTime, 419 endTime, 420 /* clientRecordId= */ null, 421 /* clientRecordVersion= */ 0L, 422 count); 423 } 424 425 /** Creates and returns a {@link StepsRecord} with the specified arguments. */ getCompleteStepsRecord( Instant startTime, Instant endTime, long count)426 public static StepsRecord getCompleteStepsRecord( 427 Instant startTime, Instant endTime, long count) { 428 return getCompleteStepsRecord( 429 startTime, 430 endTime, 431 /* clientRecordId= */ null, 432 /* clientRecordVersion= */ 0L, 433 count); 434 } 435 436 /** Creates and returns a {@link StepsRecord} with the specified arguments. */ getCompleteStepsRecord( Instant startTime, Instant endTime, String clientRecordId, long count)437 public static StepsRecord getCompleteStepsRecord( 438 Instant startTime, Instant endTime, String clientRecordId, long count) { 439 return getCompleteStepsRecord( 440 startTime, endTime, clientRecordId, /* clientRecordVersion= */ 0L, count); 441 } 442 443 /** Creates and returns a {@link StepsRecord} with the specified arguments. */ getCompleteStepsRecord( Instant startTime, Instant endTime, String clientRecordId, long clientRecordVersion, long count)444 public static StepsRecord getCompleteStepsRecord( 445 Instant startTime, 446 Instant endTime, 447 String clientRecordId, 448 long clientRecordVersion, 449 long count) { 450 return getCompleteStepsRecord( 451 /* id= */ null, startTime, endTime, clientRecordId, clientRecordVersion, count); 452 } 453 454 /** Creates and returns a {@link StepsRecord} with the specified arguments. */ getCompleteStepsRecord( String id, Instant startTime, Instant endTime, String clientRecordId, long clientRecordVersion, long count)455 public static StepsRecord getCompleteStepsRecord( 456 String id, 457 Instant startTime, 458 Instant endTime, 459 String clientRecordId, 460 long clientRecordVersion, 461 long count) { 462 Device device = 463 new Device.Builder().setManufacturer("google").setModel("Pixel").setType(1).build(); 464 DataOrigin dataOrigin = 465 new DataOrigin.Builder().setPackageName("android.healthconnect.cts").build(); 466 467 Metadata.Builder testMetadataBuilder = new Metadata.Builder(); 468 if (id != null) { 469 testMetadataBuilder.setId(id); 470 } 471 testMetadataBuilder.setDevice(device).setDataOrigin(dataOrigin); 472 testMetadataBuilder.setClientRecordId(clientRecordId); 473 testMetadataBuilder.setClientRecordVersion(clientRecordVersion); 474 testMetadataBuilder.setRecordingMethod(RECORDING_METHOD_ACTIVELY_RECORDED); 475 Metadata testMetaData = testMetadataBuilder.build(); 476 assertThat(testMetaData.getRecordingMethod()).isEqualTo(RECORDING_METHOD_ACTIVELY_RECORDED); 477 return new StepsRecord.Builder(testMetaData, startTime, endTime, count).build(); 478 } 479 getUpdatedStepsRecord( Record record, String id, String clientRecordId)480 public static StepsRecord getUpdatedStepsRecord( 481 Record record, String id, String clientRecordId) { 482 Metadata metadata = record.getMetadata(); 483 Metadata metadataWithId = 484 new Metadata.Builder() 485 .setId(id) 486 .setClientRecordId(clientRecordId) 487 .setClientRecordVersion(metadata.getClientRecordVersion()) 488 .setDataOrigin(metadata.getDataOrigin()) 489 .setDevice(metadata.getDevice()) 490 .setLastModifiedTime(metadata.getLastModifiedTime()) 491 .build(); 492 return new StepsRecord.Builder(metadataWithId, NOW, NOW.plusMillis(2000), 20) 493 .setStartZoneOffset(ZoneOffset.systemDefault().getRules().getOffset(NOW)) 494 .setEndZoneOffset(ZoneOffset.systemDefault().getRules().getOffset(NOW)) 495 .build(); 496 } 497 498 /** Creates a {@link DistanceRecord}. */ getDistanceRecord()499 public static DistanceRecord getDistanceRecord() { 500 return getDistanceRecord(10.0, NOW, NOW.plusMillis(1000)); 501 } 502 503 /** Creates a {@link DistanceRecord} with a specified {@code clientId}. */ getDistanceRecordWithClientId(String clientId)504 public static DistanceRecord getDistanceRecordWithClientId(String clientId) { 505 return getDistanceRecord( 506 10, 507 NOW, 508 NOW.plusMillis(1000), 509 /* startZoneOffset= */ null, 510 /* endZoneOffset= */ null, 511 generateMetadataWithClientId(clientId)); 512 } 513 514 /** Create a {@link DistanceRecord} with non empty record ID. */ getDistanceRecordWithNonEmptyId()515 public static DistanceRecord getDistanceRecordWithNonEmptyId() { 516 return getDistanceRecord( 517 10, 518 NOW, 519 NOW.plusMillis(1000), 520 /* startZoneOffset= */ null, 521 /* endZoneOffset= */ null, 522 generateMetadata()); 523 } 524 525 /** Create a {@link DistanceRecord} with empty {@link Metadata}. */ getDistanceRecordWithEmptyMetadata()526 public static DistanceRecord getDistanceRecordWithEmptyMetadata() { 527 return getDistanceRecord( 528 10, 529 NOW, 530 NOW.plusMillis(1000), 531 /* startZoneOffset= */ null, 532 /* endZoneOffset= */ null, 533 getEmptyMetadata()); 534 } 535 536 /** Create a {@link DistanceRecord} with the specified arguments. */ getDistanceRecord(double distance, Instant start, Instant end)537 public static DistanceRecord getDistanceRecord(double distance, Instant start, Instant end) { 538 return getDistanceRecord( 539 distance, 540 start, 541 end, 542 /* startZoneOffset= */ null, 543 /* endZoneOffset= */ null, 544 getEmptyMetadata()); 545 } 546 547 /** Create a {@link DistanceRecord} with the specified arguments. */ getDistanceRecord( double distance, Instant start, Instant end, ZoneOffset offset)548 public static DistanceRecord getDistanceRecord( 549 double distance, Instant start, Instant end, ZoneOffset offset) { 550 return getDistanceRecord(distance, start, end, offset, offset, getEmptyMetadata()); 551 } 552 553 /** Create a {@link DistanceRecord} with the specified arguments. */ getDistanceRecord( double distance, Instant start, Instant end, String clientId)554 public static DistanceRecord getDistanceRecord( 555 double distance, Instant start, Instant end, String clientId) { 556 return getDistanceRecord( 557 distance, 558 start, 559 end, 560 /* startZoneOffset= */ null, 561 /* endZoneOffset= */ null, 562 getMetadataForClientId(clientId)); 563 } 564 565 /** Create a {@link DistanceRecord} with the specified arguments. */ getDistanceRecord( double distance, Instant start, Instant end, @Nullable ZoneOffset startZoneOffset, @Nullable ZoneOffset endZoneOffset, Metadata metadata)566 public static DistanceRecord getDistanceRecord( 567 double distance, 568 Instant start, 569 Instant end, 570 @Nullable ZoneOffset startZoneOffset, 571 @Nullable ZoneOffset endZoneOffset, 572 Metadata metadata) { 573 DistanceRecord.Builder builder = 574 new DistanceRecord.Builder(metadata, start, end, Length.fromMeters(distance)); 575 if (startZoneOffset != null) { 576 builder.setStartZoneOffset(startZoneOffset); 577 } 578 if (endZoneOffset != null) { 579 builder.setEndZoneOffset(endZoneOffset); 580 } 581 return builder.build(); 582 } 583 584 /** Gets a {@link TotalCaloriesBurnedRecord} with a specific {@code clientId}. */ getTotalCaloriesBurnedRecord(String clientId)585 public static TotalCaloriesBurnedRecord getTotalCaloriesBurnedRecord(String clientId) { 586 return getTotalCaloriesBurnedRecord(getMetadataForClientId(clientId)); 587 } 588 589 /** Gets a {@link TotalCaloriesBurnedRecord} with a specific {@link Metadata}. */ getTotalCaloriesBurnedRecord(Metadata metadata)590 public static TotalCaloriesBurnedRecord getTotalCaloriesBurnedRecord(Metadata metadata) { 591 return new TotalCaloriesBurnedRecord.Builder( 592 metadata, NOW, NOW.plusMillis(1000), Energy.fromCalories(10.0)) 593 .build(); 594 } 595 getTotalCaloriesBurnedRecordWithEmptyMetadata()596 public static TotalCaloriesBurnedRecord getTotalCaloriesBurnedRecordWithEmptyMetadata() { 597 return getTotalCaloriesBurnedRecord(getEmptyMetadata()); 598 } 599 getTestRecords()600 public static List<Record> getTestRecords() { 601 return Arrays.asList( 602 getStepsRecord(), 603 getHeartRateRecord(), 604 getBasalMetabolicRateRecord(), 605 buildExerciseSession()); 606 } 607 getChangeLogTokenRequestForTestRecordTypes()608 public static ChangeLogTokenRequest.Builder getChangeLogTokenRequestForTestRecordTypes() { 609 return new ChangeLogTokenRequest.Builder() 610 .addRecordType(StepsRecord.class) 611 .addRecordType(HeartRateRecord.class) 612 .addRecordType(BasalMetabolicRateRecord.class) 613 .addRecordType(ExerciseSessionRecord.class); 614 } 615 getBasalMetabolicRateRecord()616 public static BasalMetabolicRateRecord getBasalMetabolicRateRecord() { 617 return new BasalMetabolicRateRecord.Builder(generateMetadata(), NOW, Power.fromWatts(100.0)) 618 .build(); 619 } 620 } 621