1 /* 2 * Copyright (C) 2022 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.health.connect; 18 19 import static android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP; 20 import static android.health.connect.HealthPermissions.READ_EXERCISE_ROUTE; 21 import static android.health.connect.HealthPermissions.READ_MEDICAL_DATA_IMMUNIZATION; 22 import static android.health.connect.HealthPermissions.WRITE_MEDICAL_DATA; 23 24 import static com.android.healthfitness.flags.Flags.FLAG_PERSONAL_HEALTH_RECORD; 25 26 import static com.google.common.truth.Truth.assertThat; 27 import static com.google.common.truth.Truth.assertWithMessage; 28 29 import static org.mockito.Mockito.reset; 30 31 import android.content.Context; 32 import android.content.pm.PackageInfo; 33 import android.content.pm.PackageManager; 34 import android.content.pm.PermissionInfo; 35 import android.platform.test.annotations.EnableFlags; 36 import android.platform.test.flag.junit.SetFlagsRule; 37 38 import androidx.test.InstrumentationRegistry; 39 import androidx.test.runner.AndroidJUnit4; 40 41 import org.junit.After; 42 import org.junit.Before; 43 import org.junit.Rule; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 import org.mockito.Mock; 47 import org.mockito.MockitoAnnotations; 48 49 import java.util.Set; 50 51 @RunWith(AndroidJUnit4.class) 52 public class HealthPermissionsTest { 53 private static final String FAIL_MESSAGE = 54 "Add new health permission to ALL_EXPECTED_HEALTH_PERMISSIONS and " 55 + " android.healthconnect.cts.HealthPermissionsPresenceTest.HEALTH_PERMISSIONS " 56 + "sets."; 57 58 // Add new health permission to ALL_EXPECTED_HEALTH_PERMISSIONS and 59 // {@link android.healthconnect.cts.HealthPermissionsPresenceTest.HEALTH_PERMISSIONS} 60 // sets. 61 private static final Set<String> ALL_EXPECTED_HEALTH_PERMISSIONS = 62 Set.of( 63 HealthPermissions.READ_HEALTH_DATA_HISTORY, 64 HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND, 65 HealthPermissions.READ_ACTIVE_CALORIES_BURNED, 66 HealthPermissions.READ_DISTANCE, 67 HealthPermissions.READ_ELEVATION_GAINED, 68 HealthPermissions.READ_EXERCISE, 69 HealthPermissions.READ_EXERCISE_ROUTES, 70 HealthPermissions.READ_PLANNED_EXERCISE, 71 HealthPermissions.READ_FLOORS_CLIMBED, 72 HealthPermissions.READ_STEPS, 73 HealthPermissions.READ_TOTAL_CALORIES_BURNED, 74 HealthPermissions.READ_VO2_MAX, 75 HealthPermissions.READ_WHEELCHAIR_PUSHES, 76 HealthPermissions.READ_POWER, 77 HealthPermissions.READ_SPEED, 78 HealthPermissions.READ_BASAL_METABOLIC_RATE, 79 HealthPermissions.READ_BODY_FAT, 80 HealthPermissions.READ_BODY_WATER_MASS, 81 HealthPermissions.READ_BONE_MASS, 82 HealthPermissions.READ_HEIGHT, 83 HealthPermissions.READ_LEAN_BODY_MASS, 84 HealthPermissions.READ_WEIGHT, 85 HealthPermissions.READ_CERVICAL_MUCUS, 86 HealthPermissions.READ_INTERMENSTRUAL_BLEEDING, 87 HealthPermissions.READ_MENSTRUATION, 88 HealthPermissions.READ_OVULATION_TEST, 89 HealthPermissions.READ_SEXUAL_ACTIVITY, 90 HealthPermissions.READ_HYDRATION, 91 HealthPermissions.READ_NUTRITION, 92 HealthPermissions.READ_SLEEP, 93 HealthPermissions.READ_BASAL_BODY_TEMPERATURE, 94 HealthPermissions.READ_BLOOD_GLUCOSE, 95 HealthPermissions.READ_BLOOD_PRESSURE, 96 HealthPermissions.READ_BODY_TEMPERATURE, 97 HealthPermissions.READ_HEART_RATE, 98 HealthPermissions.READ_HEART_RATE_VARIABILITY, 99 HealthPermissions.READ_OXYGEN_SATURATION, 100 HealthPermissions.READ_RESPIRATORY_RATE, 101 HealthPermissions.READ_RESTING_HEART_RATE, 102 HealthPermissions.READ_SKIN_TEMPERATURE, 103 HealthPermissions.READ_MINDFULNESS, 104 HealthPermissions.READ_MEDICAL_DATA_IMMUNIZATION, 105 HealthPermissions.WRITE_ACTIVE_CALORIES_BURNED, 106 HealthPermissions.WRITE_DISTANCE, 107 HealthPermissions.WRITE_ELEVATION_GAINED, 108 HealthPermissions.WRITE_EXERCISE, 109 HealthPermissions.WRITE_EXERCISE_ROUTE, 110 HealthPermissions.WRITE_PLANNED_EXERCISE, 111 HealthPermissions.WRITE_FLOORS_CLIMBED, 112 HealthPermissions.WRITE_STEPS, 113 HealthPermissions.WRITE_TOTAL_CALORIES_BURNED, 114 HealthPermissions.WRITE_VO2_MAX, 115 HealthPermissions.WRITE_WHEELCHAIR_PUSHES, 116 HealthPermissions.WRITE_POWER, 117 HealthPermissions.WRITE_SPEED, 118 HealthPermissions.WRITE_BASAL_METABOLIC_RATE, 119 HealthPermissions.WRITE_BODY_FAT, 120 HealthPermissions.WRITE_BODY_WATER_MASS, 121 HealthPermissions.WRITE_BONE_MASS, 122 HealthPermissions.WRITE_HEIGHT, 123 HealthPermissions.WRITE_LEAN_BODY_MASS, 124 HealthPermissions.WRITE_WEIGHT, 125 HealthPermissions.WRITE_CERVICAL_MUCUS, 126 HealthPermissions.WRITE_INTERMENSTRUAL_BLEEDING, 127 HealthPermissions.WRITE_MENSTRUATION, 128 HealthPermissions.WRITE_OVULATION_TEST, 129 HealthPermissions.WRITE_SEXUAL_ACTIVITY, 130 HealthPermissions.WRITE_HYDRATION, 131 HealthPermissions.WRITE_NUTRITION, 132 HealthPermissions.WRITE_SLEEP, 133 HealthPermissions.WRITE_BASAL_BODY_TEMPERATURE, 134 HealthPermissions.WRITE_BLOOD_GLUCOSE, 135 HealthPermissions.WRITE_BLOOD_PRESSURE, 136 HealthPermissions.WRITE_BODY_TEMPERATURE, 137 HealthPermissions.WRITE_HEART_RATE, 138 HealthPermissions.WRITE_HEART_RATE_VARIABILITY, 139 HealthPermissions.WRITE_OXYGEN_SATURATION, 140 HealthPermissions.WRITE_RESPIRATORY_RATE, 141 HealthPermissions.WRITE_RESTING_HEART_RATE, 142 HealthPermissions.WRITE_SKIN_TEMPERATURE, 143 HealthPermissions.WRITE_MINDFULNESS, 144 HealthPermissions.WRITE_MEDICAL_DATA); 145 private PackageManager mPackageManager; 146 private Context mContext; 147 @Mock private PackageInfo mPackageInfo1; 148 149 @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 150 151 @Before setUp()152 public void setUp() { 153 MockitoAnnotations.initMocks(this); 154 mContext = InstrumentationRegistry.getTargetContext(); 155 mPackageManager = mContext.getPackageManager(); 156 } 157 158 @After tearDown()159 public void tearDown() { 160 reset(mPackageInfo1); 161 } 162 163 @Test testHealthGroupPermissions_noUnexpectedPermissionsDefined()164 public void testHealthGroupPermissions_noUnexpectedPermissionsDefined() throws Exception { 165 PermissionInfo[] permissionInfos = getHealthPermissionInfos(); 166 for (PermissionInfo permissionInfo : permissionInfos) { 167 if (permissionInfo.group != null 168 && permissionInfo.group.equals(HEALTH_PERMISSION_GROUP)) { 169 assertWithMessage(FAIL_MESSAGE) 170 .that(ALL_EXPECTED_HEALTH_PERMISSIONS) 171 .contains(permissionInfo.name); 172 } 173 } 174 } 175 176 @Test testHealthConnectManager_noUnexpectedPermissionsReturned()177 public void testHealthConnectManager_noUnexpectedPermissionsReturned() throws Exception { 178 assertWithMessage(FAIL_MESSAGE) 179 .that(HealthConnectManager.getHealthPermissions(mContext)) 180 .isEqualTo(ALL_EXPECTED_HEALTH_PERMISSIONS); 181 } 182 183 @Test testReadExerciseRoutePerm_hasSignatureProtection()184 public void testReadExerciseRoutePerm_hasSignatureProtection() throws Exception { 185 assertThat( 186 mPackageManager 187 .getPermissionInfo(READ_EXERCISE_ROUTE, /* flags= */ 0) 188 .getProtection()) 189 .isEqualTo(PermissionInfo.PROTECTION_SIGNATURE); 190 } 191 192 @Test testReadExerciseRoutePerm_controllerUiHoldsIt()193 public void testReadExerciseRoutePerm_controllerUiHoldsIt() throws Exception { 194 String healthControllerPackageName = getControllerUiPackageName(); 195 assertThat( 196 mContext.getPackageManager() 197 .checkPermission(READ_EXERCISE_ROUTE, healthControllerPackageName)) 198 .isEqualTo(PackageManager.PERMISSION_GRANTED); 199 } 200 201 @Test testGetDataCategoriesWithWritePermissionsForPackage_returnsCorrectSet()202 public void testGetDataCategoriesWithWritePermissionsForPackage_returnsCorrectSet() { 203 mPackageInfo1.requestedPermissions = 204 new String[] { 205 HealthPermissions.WRITE_STEPS, 206 HealthPermissions.WRITE_SLEEP, 207 HealthPermissions.READ_HEART_RATE, 208 HealthPermissions.WRITE_OVULATION_TEST 209 }; 210 mPackageInfo1.requestedPermissionsFlags = 211 new int[] { 212 PackageInfo.REQUESTED_PERMISSION_GRANTED, 213 0, 214 PackageInfo.REQUESTED_PERMISSION_GRANTED, 215 PackageInfo.REQUESTED_PERMISSION_GRANTED 216 }; 217 218 Set<Integer> expectedResult = 219 Set.of(HealthDataCategory.ACTIVITY, HealthDataCategory.CYCLE_TRACKING); 220 Set<Integer> actualResult = 221 HealthPermissions.getDataCategoriesWithWritePermissionsForPackage( 222 mPackageInfo1, mContext); 223 assertThat(actualResult).isEqualTo(expectedResult); 224 } 225 226 @Test 227 public void testPackageHasWriteHealthPermissionsForCategory_ifNoWritePermissions_returnsFalse()228 testPackageHasWriteHealthPermissionsForCategory_ifNoWritePermissions_returnsFalse() { 229 mPackageInfo1.requestedPermissions = 230 new String[] { 231 HealthPermissions.WRITE_EXERCISE, 232 HealthPermissions.WRITE_SLEEP, 233 HealthPermissions.READ_HEART_RATE, 234 HealthPermissions.WRITE_OVULATION_TEST 235 }; 236 mPackageInfo1.requestedPermissionsFlags = 237 new int[] { 238 PackageInfo.REQUESTED_PERMISSION_GRANTED, 239 0, 240 PackageInfo.REQUESTED_PERMISSION_GRANTED, 241 PackageInfo.REQUESTED_PERMISSION_GRANTED 242 }; 243 244 assertThat( 245 HealthPermissions.getPackageHasWriteHealthPermissionsForCategory( 246 mPackageInfo1, HealthDataCategory.SLEEP, mContext)) 247 .isFalse(); 248 } 249 250 @Test testPackageHasWriteHealthPermissionsForCategory_ifWritePermissions_returnsTrue()251 public void testPackageHasWriteHealthPermissionsForCategory_ifWritePermissions_returnsTrue() { 252 mPackageInfo1.requestedPermissions = 253 new String[] { 254 HealthPermissions.WRITE_STEPS, 255 HealthPermissions.WRITE_SLEEP, 256 HealthPermissions.READ_HEART_RATE, 257 HealthPermissions.WRITE_OVULATION_TEST 258 }; 259 mPackageInfo1.requestedPermissionsFlags = 260 new int[] { 261 PackageInfo.REQUESTED_PERMISSION_GRANTED, 262 0, 263 PackageInfo.REQUESTED_PERMISSION_GRANTED, 264 PackageInfo.REQUESTED_PERMISSION_GRANTED 265 }; 266 267 assertThat( 268 HealthPermissions.getPackageHasWriteHealthPermissionsForCategory( 269 mPackageInfo1, HealthDataCategory.ACTIVITY, mContext)) 270 .isTrue(); 271 } 272 273 @Test 274 @EnableFlags(FLAG_PERSONAL_HEALTH_RECORD) testGetMedicalReadPermission_givenCategory_returnsPermission()275 public void testGetMedicalReadPermission_givenCategory_returnsPermission() { 276 String readPermission = 277 HealthPermissions.getMedicalReadPermission(MedicalPermissionCategory.IMMUNIZATION); 278 assertThat(readPermission).isEqualTo(READ_MEDICAL_DATA_IMMUNIZATION); 279 } 280 281 @Test(expected = NullPointerException.class) 282 @EnableFlags(FLAG_PERSONAL_HEALTH_RECORD) testGetMedicalReadPermission_unknownCategory_throwsException()283 public void testGetMedicalReadPermission_unknownCategory_throwsException() { 284 HealthPermissions.getMedicalReadPermission(MedicalPermissionCategory.UNKNOWN); 285 } 286 287 @Test 288 @EnableFlags(FLAG_PERSONAL_HEALTH_RECORD) testGetMedicalPermissions_returnsValidPermissions()289 public void testGetMedicalPermissions_returnsValidPermissions() { 290 Set<String> permissions = HealthPermissions.getAllMedicalPermissions(); 291 assertThat(permissions).containsAtLeast(WRITE_MEDICAL_DATA, READ_MEDICAL_DATA_IMMUNIZATION); 292 } 293 getHealthPermissionInfos()294 private PermissionInfo[] getHealthPermissionInfos() throws Exception { 295 String healthControllerPackageName = getControllerUiPackageName(); 296 297 PackageInfo packageInfo = 298 mPackageManager.getPackageInfo( 299 healthControllerPackageName, 300 PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS)); 301 return packageInfo.permissions; 302 } 303 getControllerUiPackageName()304 private String getControllerUiPackageName() throws Exception { 305 return mPackageManager.getPermissionInfo(HealthPermissions.READ_STEPS, /* flags= */ 0) 306 .packageName; 307 } 308 } 309