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.ui 18 19 import android.health.connect.datatypes.Record 20 import android.healthconnect.cts.lib.ActivityLauncher.launchMainActivity 21 import android.healthconnect.cts.lib.ActivityLauncher.launchRequestPermissionActivity 22 import android.healthconnect.cts.lib.UiTestUtils.findDesc 23 import android.healthconnect.cts.lib.UiTestUtils.findDescAndClick 24 import android.healthconnect.cts.lib.UiTestUtils.findObject 25 import android.healthconnect.cts.lib.UiTestUtils.findText 26 import android.healthconnect.cts.lib.UiTestUtils.findTextAndClick 27 import android.healthconnect.cts.lib.UiTestUtils.grantPermissionViaPackageManager 28 import android.healthconnect.cts.lib.UiTestUtils.navigateToNewPage 29 import android.healthconnect.cts.lib.UiTestUtils.revokePermissionViaPackageManager 30 import android.healthconnect.cts.lib.UiTestUtils.scrollDownTo 31 import android.healthconnect.cts.lib.UiTestUtils.scrollDownToAndClick 32 import android.healthconnect.cts.lib.UiTestUtils.scrollDownToAndFindText 33 import android.healthconnect.cts.lib.UiTestUtils.scrollToEnd 34 import android.healthconnect.cts.lib.UiTestUtils.verifyTextNotFound 35 import android.healthconnect.cts.lib.UiTestUtils.waitForObjectNotFound 36 import android.healthconnect.cts.utils.PermissionHelper.getGrantedHealthPermissions 37 import android.healthconnect.cts.utils.TestUtils 38 import android.healthconnect.cts.utils.TestUtils.readAllRecords 39 import android.platform.test.annotations.RequiresFlagsDisabled 40 import android.platform.test.annotations.RequiresFlagsEnabled 41 import android.platform.test.flag.junit.CheckFlagsRule 42 import android.platform.test.flag.junit.DeviceFlagsValueProvider 43 import androidx.test.uiautomator.By 44 import com.android.healthfitness.flags.AconfigFlagHelper 45 import com.android.settingslib.widget.theme.flags.Flags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED 46 import com.google.common.truth.Truth.assertThat 47 import java.time.Duration.ofSeconds 48 import org.junit.After 49 import org.junit.Before 50 import org.junit.Rule 51 import org.junit.Test 52 53 abstract class BaseDataTypeTest<T : Record> : HealthConnectBaseTest() { 54 abstract val dataTypeString: String 55 abstract val dataCategoryString: String 56 abstract val permissionString: String 57 abstract val permissions: List<String> 58 abstract val sameCategoryDataTypeString: String? 59 abstract val anotherCategoryString: String 60 createRecordnull61 abstract fun createRecord(): T 62 63 abstract val expectedRecordHeader: String 64 abstract val expectedRecordTitle: String 65 abstract val expectedRecordSubtitle: String? 66 67 abstract fun createRecordToBeDeleted(): Record 68 69 abstract val expectedRecordToBeDeletedHeader: String 70 abstract val expectedRecordToBeDeletedTitle: String 71 72 abstract fun createSameCategoryRecord(): Record? 73 74 abstract fun createAnotherCategoryRecord(): Record 75 76 @get:Rule val mCheckFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() 77 78 companion object { 79 const val APP_WITH_READ_WRITE_PERMISSIONS = 80 "android.healthconnect.cts.testapp.readWritePerms.A" 81 const val APP_WITH_READ_WRITE_PERMISSIONS_LABEL = 82 "CtsHealthConnectTestAppAWithNormalReadWritePermission" 83 } 84 85 private lateinit var record: Record 86 87 @Before setupnull88 fun setup() { 89 assertThat(getGrantedHealthPermissions(context.packageName)) 90 .containsAtLeastElementsIn(permissions) 91 assertThat(getGrantedHealthPermissions(APP_WITH_READ_WRITE_PERMISSIONS)) 92 .containsAtLeastElementsIn(permissions) 93 94 TestUtils.deleteAllStagedRemoteData() 95 96 val record = createRecord() 97 98 val recordToBeDeleted = createRecordToBeDeleted() 99 100 val insertedRecords = TestUtils.insertRecords(record, recordToBeDeleted) 101 this.record = insertedRecords[0] 102 } 103 104 @After tearDownnull105 fun tearDown() { 106 TestUtils.deleteAllStagedRemoteData() 107 permissions.forEach { 108 grantPermissionViaPackageManager(context, APP_WITH_READ_WRITE_PERMISSIONS, it) 109 assertPermissionGranted(it, APP_WITH_READ_WRITE_PERMISSIONS) 110 } 111 } 112 113 @Test dataAndAccess_showsEntries_deletesEntrynull114 fun dataAndAccess_showsEntries_deletesEntry() { 115 context.launchMainActivity { 116 navigateToNewPage("Data and access") 117 118 scrollDownToAndFindText(dataCategoryString) 119 navigateToNewPage(dataTypeString) 120 121 findText("No data") 122 findDescAndClick("Previous day") 123 waitForObjectNotFound(By.text("No data"), timeout = ofSeconds(1)) 124 scrollToEnd() 125 126 findText(expectedRecordHeader) 127 findText(expectedRecordTitle) 128 expectedRecordSubtitle?.let { findText(it) } 129 130 findText(expectedRecordToBeDeletedHeader) 131 // Check that clicking on the entry does not open the details screen. 132 findTextAndClick(expectedRecordToBeDeletedTitle) 133 findText(expectedRecordTitle) 134 findDesc("Previous day") 135 136 findDescAndClick("Enter deletion") 137 findTextAndClick(expectedRecordToBeDeletedTitle) 138 findDescAndClick("Delete data") 139 findTextAndClick("Delete") 140 findObject(By.text("Done"), timeout = ofSeconds(3)) 141 findTextAndClick("Done") 142 verifyTextNotFound(expectedRecordToBeDeletedTitle) 143 findText(expectedRecordTitle) 144 145 assertThat(readAllRecords(record::class.java)).containsExactly(record) 146 } 147 } 148 149 @Test dataAndAccess_deleteData_deletesDataType_doesNotDeleteOtherDataTypesnull150 fun dataAndAccess_deleteData_deletesDataType_doesNotDeleteOtherDataTypes() { 151 val sameCategoryRecord = createSameCategoryRecord() 152 val anotherCategoryRecord = createAnotherCategoryRecord() 153 TestUtils.insertRecords(listOfNotNull(sameCategoryRecord, anotherCategoryRecord)) 154 155 context.launchMainActivity { 156 navigateToNewPage("Data and access") 157 158 findDescAndClick("Enter deletion") 159 scrollDownToAndClick(By.text(dataTypeString)) 160 findDescAndClick("Delete data") 161 findTextAndClick("Delete") 162 findObject(By.text("Done"), timeout = ofSeconds(3)) 163 findTextAndClick("Done") 164 165 assertThat(readAllRecords(record::class.java)).isEmpty() 166 assertThat(readAllRecords(anotherCategoryRecord::class.java)).hasSize(1) 167 168 verifyTextNotFound(dataTypeString) 169 findText(anotherCategoryString) 170 171 sameCategoryRecord?.let { 172 assertThat(readAllRecords(it::class.java)).hasSize(1) 173 findText(dataCategoryString) 174 findText(sameCategoryDataTypeString!!) 175 } 176 177 if (sameCategoryRecord == null) { 178 verifyTextNotFound(dataCategoryString) 179 } 180 } 181 } 182 183 @Test 184 @RequiresFlagsDisabled(FLAG_IS_EXPRESSIVE_DESIGN_ENABLED) legacySeeAllRecentAccess_showsDataCategorynull185 fun legacySeeAllRecentAccess_showsDataCategory() { 186 context.launchMainActivity { 187 navigateToNewPage("See all recent access") 188 scrollDownToAndFindText("Write: ${dataCategoryString}") 189 } 190 } 191 192 @Test 193 @RequiresFlagsEnabled(FLAG_IS_EXPRESSIVE_DESIGN_ENABLED) expressiveSeeAllRecentAccess_showsDataCategorynull194 fun expressiveSeeAllRecentAccess_showsDataCategory() { 195 context.launchMainActivity { 196 navigateToNewPage("View all") 197 scrollDownToAndFindText("Write: ${dataCategoryString}") 198 } 199 } 200 201 @Test appPermissions_allowAll_grantsPermissionsnull202 fun appPermissions_allowAll_grantsPermissions() { 203 permissions.forEach { 204 revokePermissionViaPackageManager(context, APP_WITH_READ_WRITE_PERMISSIONS, it) 205 assertPermissionDenied(it, APP_WITH_READ_WRITE_PERMISSIONS) 206 } 207 208 context.launchMainActivity { 209 navigateToNewPage("App permissions") 210 navigateToNewPage(APP_WITH_READ_WRITE_PERMISSIONS_LABEL) 211 if (AconfigFlagHelper.isPersonalHealthRecordEnabled()) { 212 navigateToNewPage("Fitness and wellness") 213 } 214 findTextAndClick("Allow all") 215 } 216 217 permissions.forEach { assertPermissionGranted(it, APP_WITH_READ_WRITE_PERMISSIONS) } 218 } 219 220 @Test requestPermission_showsPermissionnull221 fun requestPermission_showsPermission() { 222 permissions.forEach { 223 revokePermissionViaPackageManager(context, APP_WITH_READ_WRITE_PERMISSIONS, it) 224 assertPermissionDenied(it, APP_WITH_READ_WRITE_PERMISSIONS) 225 } 226 227 context.launchRequestPermissionActivity( 228 packageName = APP_WITH_READ_WRITE_PERMISSIONS, 229 permissions = permissions, 230 ) { 231 scrollDownTo(By.text(permissionString)) 232 findTextAndClick("Allow all") 233 findTextAndClick("Allow") 234 } 235 236 permissions.forEach { assertPermissionGranted(it, APP_WITH_READ_WRITE_PERMISSIONS) } 237 } 238 } 239