1 /* 2 * Copyright (C) 2021 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.companion.cts.uiautomation 18 19 import androidx.test.uiautomator.By 20 import androidx.test.uiautomator.BySelector 21 import androidx.test.uiautomator.SearchCondition 22 import androidx.test.uiautomator.UiDevice 23 import androidx.test.uiautomator.UiObject2 24 import androidx.test.uiautomator.Until 25 import kotlin.time.Duration 26 import kotlin.time.Duration.Companion.seconds 27 28 class CompanionDeviceManagerUi(private val ui: UiDevice) { 29 val isVisible: Boolean 30 get() = ui.hasObject(CONFIRMATION_UI) 31 dismissnull32 fun dismiss() { 33 if (!isVisible) return 34 // Pressing back button should close (cancel) confirmation UI. 35 ui.pressBack() 36 waitUntilGone() 37 } 38 waitUntilVisiblenull39 fun waitUntilVisible() = ui.wait(Until.hasObject(CONFIRMATION_UI), "CDM UI has not appeared.") 40 41 fun waitUntilGone() = ui.waitShort(Until.gone(CONFIRMATION_UI), "CDM UI has not disappeared") 42 43 fun waitAndClickOnFirstFoundDevice() = ui.waitLongAndFind( 44 Until.findObject(DEVICE_LIST_WITH_ITEMS), "Device List not found or empty") 45 .children[0].click() 46 47 fun waitUntilPositiveButtonIsEnabledAndClick() = ui.waitLongAndFind( 48 Until.findObject(POSITIVE_BUTTON), "Positive button not found or not clickable") 49 .click() 50 51 fun clickPositiveButton() = click(POSITIVE_BUTTON, "Positive button") 52 53 fun clickNegativeButton() = click(NEGATIVE_BUTTON, "Negative button") 54 55 fun clickNegativeButtonMultipleDevices() = click( 56 NEGATIVE_BUTTON_MULTIPLE_DEVICES, "Negative button for multiple devices") 57 58 private fun click(selector: BySelector, description: String) = ui.waitShortAndFind( 59 Until.findObject(selector), "$description is not found") 60 .click() 61 62 companion object { 63 private const val PACKAGE_NAME = "com.android.companiondevicemanager" 64 65 private val CONFIRMATION_UI = By.pkg(PACKAGE_NAME) 66 .res(PACKAGE_NAME, "activity_confirmation") 67 68 private val CLICKABLE_BUTTON = 69 By.pkg(PACKAGE_NAME).clazz(".Button").clickable(true) 70 private val POSITIVE_BUTTON = By.copy(CLICKABLE_BUTTON).res(PACKAGE_NAME, "btn_positive") 71 private val NEGATIVE_BUTTON = By.copy(CLICKABLE_BUTTON).res(PACKAGE_NAME, "btn_negative") 72 private val NEGATIVE_BUTTON_MULTIPLE_DEVICES = By.copy(CLICKABLE_BUTTON) 73 .res(PACKAGE_NAME, "btn_negative_multiple_devices") 74 75 private val DEVICE_LIST = By.pkg(PACKAGE_NAME) 76 .clazz("androidx.recyclerview.widget.RecyclerView") 77 .res(PACKAGE_NAME, "device_list") 78 private val DEVICE_LIST_ITEM = By.pkg(PACKAGE_NAME) 79 .res(PACKAGE_NAME, "list_item_device") 80 private val DEVICE_LIST_WITH_ITEMS = By.copy(DEVICE_LIST) 81 .hasChild(DEVICE_LIST_ITEM) 82 } 83 waitnull84 private fun UiDevice.wait( 85 condition: SearchCondition<Boolean>, 86 message: String, 87 timeout: Duration = 3.seconds 88 ) { 89 if (!wait(condition, timeout.inWholeMilliseconds)) error(message) 90 } 91 waitShortnull92 private fun UiDevice.waitShort(condition: SearchCondition<Boolean>, message: String) = 93 wait(condition, message, 1.seconds) 94 95 private fun UiDevice.waitAndFind( 96 condition: SearchCondition<UiObject2>, 97 message: String, 98 timeout: Duration = 3.seconds 99 ): UiObject2 = 100 wait(condition, timeout.inWholeMilliseconds) ?: error(message) 101 102 private fun UiDevice.waitShortAndFind( 103 condition: SearchCondition<UiObject2>, 104 message: String 105 ): UiObject2 = waitAndFind(condition, message, 1.seconds) 106 107 private fun UiDevice.waitLongAndFind( 108 condition: SearchCondition<UiObject2>, 109 message: String 110 ): UiObject2 = waitAndFind(condition, message, 10.seconds) 111 }