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.photopicker.cts.util; 18 19 import static com.google.common.truth.Truth.assertWithMessage; 20 21 import android.text.format.DateUtils; 22 23 import androidx.annotation.NonNull; 24 import androidx.test.uiautomator.UiDevice; 25 import androidx.test.uiautomator.UiObject; 26 import androidx.test.uiautomator.UiObjectNotFoundException; 27 import androidx.test.uiautomator.UiScrollable; 28 import androidx.test.uiautomator.UiSelector; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 33 /** 34 * Photo Picker Utility methods for finding UI elements. 35 */ 36 public class PhotoPickerUiUtils { 37 public static final long SHORT_TIMEOUT = 5 * DateUtils.SECOND_IN_MILLIS; 38 39 private static final long TIMEOUT = 30 * DateUtils.SECOND_IN_MILLIS; 40 41 public static final String REGEX_PACKAGE_NAME = 42 "com(.google)?.android.providers.media(.module)?"; 43 44 /** 45 * Get the list of items from the photo grid list. 46 * @param itemCount if the itemCount is -1, return all matching items. Otherwise, return the 47 * item list that its size is not greater than the itemCount. 48 * @throws Exception 49 */ findItemList(int itemCount)50 public static List<UiObject> findItemList(int itemCount) throws Exception { 51 final List<UiObject> itemList = new ArrayList<>(); 52 final UiSelector gridList = new UiSelector().resourceIdMatches( 53 REGEX_PACKAGE_NAME + ":id/picker_tab_recyclerview"); 54 55 // Wait for the first item to appear 56 assertWithMessage("Timed out while waiting for first item to appear") 57 .that(new UiObject(gridList.childSelector(new UiSelector())).waitForExists(TIMEOUT)) 58 .isTrue(); 59 60 final UiSelector itemSelector = new UiSelector().resourceIdMatches( 61 REGEX_PACKAGE_NAME + ":id/icon_thumbnail"); 62 final UiScrollable grid = new UiScrollable(gridList); 63 final int childCount = grid.getChildCount(); 64 final int count = itemCount == -1 ? childCount : itemCount; 65 66 for (int i = 0; i < childCount; i++) { 67 final UiObject item = grid.getChildByInstance(itemSelector, i); 68 if (item.exists()) { 69 itemList.add(item); 70 } 71 if (itemList.size() == count) { 72 break; 73 } 74 } 75 return itemList; 76 } 77 findPreviewAddButton()78 public static UiObject findPreviewAddButton() { 79 return new UiObject(new UiSelector().resourceIdMatches( 80 REGEX_PACKAGE_NAME + ":id/preview_add_button")); 81 } 82 findPreviewAddOrSelectButton()83 public static UiObject findPreviewAddOrSelectButton() { 84 return new UiObject(new UiSelector().resourceIdMatches( 85 REGEX_PACKAGE_NAME + ":id/preview_add_or_select_button")); 86 } 87 findAddButton()88 public static UiObject findAddButton() { 89 return new UiObject(new UiSelector().resourceIdMatches( 90 REGEX_PACKAGE_NAME + ":id/button_add")); 91 } 92 findProfileButton()93 public static UiObject findProfileButton() { 94 return new UiObject(new UiSelector().resourceIdMatches( 95 REGEX_PACKAGE_NAME + ":id/profile_button")); 96 } 97 findAndClickBrowse(UiDevice uiDevice)98 public static void findAndClickBrowse(UiDevice uiDevice) throws Exception { 99 final UiObject overflowMenu = getOverflowMenuObject(uiDevice); 100 clickAndWait(uiDevice, overflowMenu); 101 102 final UiObject browseButton = new UiObject(new UiSelector().textContains("Browse")); 103 clickAndWait(uiDevice, browseButton); 104 } 105 findSettingsOverflowMenuItem(UiDevice uiDevice)106 public static UiObject findSettingsOverflowMenuItem(UiDevice uiDevice) throws Exception { 107 final UiObject overflowMenu = getOverflowMenuObject(uiDevice); 108 clickAndWait(uiDevice, overflowMenu); 109 return new UiObject(new UiSelector().textContains("Cloud media app")); 110 } 111 getOverflowMenuObject(UiDevice uiDevice)112 public static UiObject getOverflowMenuObject(UiDevice uiDevice) { 113 // Wait for overflow menu to appear. 114 verifyOverflowMenuExists(uiDevice); 115 return new UiObject(new UiSelector().description("More options")); 116 } 117 isPhotoPickerVisible()118 public static boolean isPhotoPickerVisible() { 119 return new UiObject(new UiSelector().resourceIdMatches( 120 PhotoPickerUiUtils.REGEX_PACKAGE_NAME + ":id/bottom_sheet")).waitForExists(TIMEOUT); 121 } 122 verifySettingsActionBarIsVisible()123 public static void verifySettingsActionBarIsVisible() { 124 assertWithMessage("Timed out waiting for action bar to appear") 125 .that(new UiObject(new UiSelector() 126 .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/picker_settings_toolbar")) 127 .waitForExists(TIMEOUT)) 128 .isTrue(); 129 } 130 verifySettingsTitleIsVisible()131 public static void verifySettingsTitleIsVisible() { 132 assertWithMessage("Timed out waiting for settings page title to appear") 133 .that(new UiObject(new UiSelector() 134 .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/picker_settings_title")) 135 .waitForExists(TIMEOUT)) 136 .isTrue(); 137 } 138 verifySettingsDescriptionIsVisible()139 public static void verifySettingsDescriptionIsVisible() { 140 assertWithMessage("Timed out waiting for settings page description to appear") 141 .that(new UiObject(new UiSelector() 142 .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/picker_settings_description")) 143 .waitForExists(TIMEOUT)) 144 .isTrue(); 145 } 146 147 /** 148 * Verify if the app label of the {@code sTargetPackageName} is visible on the UI. 149 */ verifySettingsCloudProviderOptionIsVisible(@onNull String cmpLabel)150 public static void verifySettingsCloudProviderOptionIsVisible(@NonNull String cmpLabel) { 151 assertWithMessage("Timed out waiting for cloud provider option on settings activity") 152 .that(new UiObject(new UiSelector().textContains(cmpLabel)) 153 .waitForExists(TIMEOUT)) 154 .isTrue(); 155 } 156 verifySettingsFragmentContainerExists()157 public static void verifySettingsFragmentContainerExists() { 158 assertWithMessage("Timed out waiting for settings fragment container to appear") 159 .that(new UiObject(new UiSelector() 160 .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/settings_fragment_container")) 161 .waitForExists(TIMEOUT)) 162 .isTrue(); 163 } 164 verifyOverflowMenuExists(UiDevice uiDevice)165 private static void verifyOverflowMenuExists(UiDevice uiDevice) { 166 assertWithMessage("Timed out waiting for overflow menu to appear") 167 .that(new UiObject(new UiSelector().description("More options")) 168 .waitForExists(TIMEOUT)) 169 .isTrue(); 170 } 171 verifySettingsActivityIsVisible()172 public static void verifySettingsActivityIsVisible() { 173 // id/settings_activity_root is the root layout in activity_photo_picker_settings.xml 174 assertWithMessage("Timed out waiting for settings activity to appear") 175 .that(new UiObject(new UiSelector() 176 .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/settings_activity_root")) 177 .waitForExists(TIMEOUT)) 178 .isTrue(); 179 } 180 clickAndWait(UiDevice uiDevice, UiObject uiObject)181 public static void clickAndWait(UiDevice uiDevice, UiObject uiObject) throws Exception { 182 uiObject.click(); 183 uiDevice.waitForIdle(); 184 } 185 186 /** 187 * Verifies whether the selected tab is the one with the provided title 188 */ isSelectedTabTitle( @onNull String tabTitle, @NonNull String tabResourceId, UiDevice device)189 public static boolean isSelectedTabTitle( 190 @NonNull String tabTitle, @NonNull String tabResourceId, UiDevice device) 191 throws UiObjectNotFoundException { 192 final UiObject tabLayout = findObject(tabResourceId, device); 193 final UiObject tab = tabLayout.getChild(new UiSelector().textContains(tabTitle)); 194 return tab.isSelected(); 195 } 196 197 /** 198 * Returns the UI object corresponding to the specified resourceId 199 */ findObject(@onNull String resourceId, UiDevice device)200 public static UiObject findObject(@NonNull String resourceId, UiDevice device) { 201 return device.findObject(new UiSelector().resourceIdMatches(resourceId)); 202 } 203 } 204