• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.route;
18 
19 import static android.health.connect.HealthPermissions.READ_EXERCISE;
20 import static android.health.connect.HealthPermissions.READ_EXERCISE_ROUTES;
21 import static android.health.connect.HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND;
22 import static android.health.connect.HealthPermissions.WRITE_EXERCISE;
23 import static android.health.connect.HealthPermissions.WRITE_EXERCISE_ROUTE;
24 import static android.healthconnect.cts.utils.PermissionHelper.READ_EXERCISE_ROUTE_PERMISSION;
25 import static android.healthconnect.cts.utils.PermissionHelper.getGrantedHealthPermissions;
26 import static android.healthconnect.cts.utils.TestUtils.readRecords;
27 import static android.healthconnect.cts.utils.TestUtils.yesterdayAt;
28 
29 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
30 
31 import static com.google.common.truth.Truth.assertThat;
32 
33 import static java.time.Duration.ofMinutes;
34 
35 import android.content.Context;
36 import android.health.connect.ReadRecordsRequestUsingFilters;
37 import android.health.connect.datatypes.ExerciseRoute;
38 import android.health.connect.datatypes.ExerciseSessionRecord;
39 import android.health.connect.datatypes.ExerciseSessionType;
40 import android.health.connect.datatypes.Metadata;
41 import android.health.connect.datatypes.units.Length;
42 import android.healthconnect.cts.lib.TestAppProxy;
43 
44 import androidx.test.core.app.ApplicationProvider;
45 
46 import java.time.Instant;
47 import java.time.temporal.ChronoUnit;
48 import java.util.List;
49 
50 final class ExerciseRouteTestHelper {
51 
52     static final TestAppProxy ROUTE_WRITER_APP =
53             TestAppProxy.forPackageName("android.healthconnect.cts.route.testapp.writer");
54 
55     static final TestAppProxy ROUTES_READER_WRITER_APP =
56             TestAppProxy.forPackageName("android.healthconnect.cts.route.testapp.readerWriter");
57 
58     static final Instant START_TIME = yesterdayAt("11:00").truncatedTo(ChronoUnit.MILLIS);
59 
60     /**
61      * Make sure test app permissions didn't change between the runs.
62      *
63      * <p>Fail quickly and explicitly if the permissions were not cleaned up by a previous test
64      * case. Also because permissions in CTS tests are auto granted it's easy to misconfigure
65      * permissions without noticing it, so this works as a double check.
66      */
assertCorrectHealthPermissions()67     static void assertCorrectHealthPermissions() {
68         Context context = ApplicationProvider.getApplicationContext();
69         assertThat(getGrantedHealthPermissions(context.getPackageName()))
70                 .containsExactly(READ_EXERCISE, WRITE_EXERCISE, WRITE_EXERCISE_ROUTE);
71         assertThat(getGrantedHealthPermissions(ROUTE_WRITER_APP.getPackageName()))
72                 .containsExactly(WRITE_EXERCISE, WRITE_EXERCISE_ROUTE);
73         assertThat(getGrantedHealthPermissions(ROUTES_READER_WRITER_APP.getPackageName()))
74                 .containsExactly(
75                         READ_EXERCISE,
76                         READ_EXERCISE_ROUTES,
77                         READ_HEALTH_DATA_IN_BACKGROUND,
78                         WRITE_EXERCISE,
79                         WRITE_EXERCISE_ROUTE);
80     }
81 
getExerciseSessionWithRoute(Metadata metadata)82     static ExerciseSessionRecord getExerciseSessionWithRoute(Metadata metadata) {
83         return getExerciseSessionWithRoute(metadata, START_TIME);
84     }
85 
getExerciseSessionWithRoute(Metadata metadata, Instant startTime)86     static ExerciseSessionRecord getExerciseSessionWithRoute(Metadata metadata, Instant startTime) {
87         return getExerciseSession(metadata, startTime, getRoute(startTime));
88     }
89 
getExerciseSessionWithAnotherRoute(Metadata metadata)90     static ExerciseSessionRecord getExerciseSessionWithAnotherRoute(Metadata metadata) {
91         return getExerciseSession(metadata, START_TIME, getAnotherRoute(START_TIME));
92     }
93 
getExerciseSessionWithoutRoute(Metadata metadata)94     static ExerciseSessionRecord getExerciseSessionWithoutRoute(Metadata metadata) {
95         return getExerciseSession(metadata, START_TIME, null);
96     }
97 
getExerciseSessionWithoutRoute( Metadata metadata, Instant startTime)98     static ExerciseSessionRecord getExerciseSessionWithoutRoute(
99             Metadata metadata, Instant startTime) {
100         return getExerciseSession(metadata, startTime, null);
101     }
102 
getExerciseSession( Metadata metadata, Instant startTime, ExerciseRoute route)103     static ExerciseSessionRecord getExerciseSession(
104             Metadata metadata, Instant startTime, ExerciseRoute route) {
105         return new ExerciseSessionRecord.Builder(
106                         metadata,
107                         startTime,
108                         startTime.plus(ofMinutes(30)),
109                         ExerciseSessionType.EXERCISE_SESSION_TYPE_RUNNING)
110                 .setRoute(route)
111                 .build();
112     }
113 
getRoute(Instant startTime)114     static ExerciseRoute getRoute(Instant startTime) {
115         return new ExerciseRoute(
116                 List.of(
117                         new ExerciseRoute.Location.Builder(startTime, 52., 48.).build(),
118                         new ExerciseRoute.Location.Builder(startTime.plusSeconds(5), -51., -49.)
119                                 .setAltitude(Length.fromMeters(14))
120                                 .setHorizontalAccuracy(Length.fromMeters(3))
121                                 .setVerticalAccuracy(Length.fromMeters(5))
122                                 .build()));
123     }
124 
getAnotherRoute(Instant startTime)125     static ExerciseRoute getAnotherRoute(Instant startTime) {
126         return new ExerciseRoute(
127                 List.of(
128                         new ExerciseRoute.Location.Builder(startTime.plusSeconds(10), -53., -47.)
129                                 .setAltitude(Length.fromMeters(123))
130                                 .setHorizontalAccuracy(Length.fromMeters(7))
131                                 .setVerticalAccuracy(Length.fromMeters(11))
132                                 .build()));
133     }
134 
readAllExerciseSessionRecordsPrivileged()135     static List<ExerciseSessionRecord> readAllExerciseSessionRecordsPrivileged() {
136         return runWithShellPermissionIdentity(
137                 () ->
138                         readRecords(
139                                 new ReadRecordsRequestUsingFilters.Builder<>(
140                                                 ExerciseSessionRecord.class)
141                                         .build()),
142                 READ_EXERCISE_ROUTE_PERMISSION);
143     }
144 
ExerciseRouteTestHelper()145     private ExerciseRouteTestHelper() {}
146 }
147