1 /* 2 * Copyright (C) 2018 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 com.android.launcher3.tapl; 18 19 import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS; 20 import static com.android.launcher3.tapl.LauncherInstrumentation.log; 21 22 import android.graphics.Rect; 23 24 import androidx.test.uiautomator.By; 25 import androidx.test.uiautomator.BySelector; 26 import androidx.test.uiautomator.Direction; 27 import androidx.test.uiautomator.UiObject2; 28 import androidx.test.uiautomator.Until; 29 30 import com.android.launcher3.testing.TestProtocol; 31 32 import java.util.Collection; 33 34 /** 35 * All widgets container. 36 */ 37 public final class Widgets extends LauncherInstrumentation.VisibleContainer { 38 private static final int FLING_STEPS = 10; 39 private static final int SCROLL_ATTEMPTS = 60; 40 Widgets(LauncherInstrumentation launcher)41 Widgets(LauncherInstrumentation launcher) { 42 super(launcher); 43 verifyActiveContainer(); 44 } 45 46 /** 47 * Flings forward (down) and waits the fling's end. 48 */ flingForward()49 public void flingForward() { 50 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 51 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 52 "want to fling forward in widgets")) { 53 log("Widgets.flingForward enter"); 54 final UiObject2 widgetsContainer = verifyActiveContainer(); 55 mLauncher.scroll( 56 widgetsContainer, 57 Direction.DOWN, 58 new Rect(0, 0, 0, 59 mLauncher.getBottomGestureMarginInContainer(widgetsContainer) + 1), 60 FLING_STEPS, false); 61 try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) { 62 verifyActiveContainer(); 63 } 64 log("Widgets.flingForward exit"); 65 } 66 } 67 68 /** 69 * Flings backward (up) and waits the fling's end. 70 */ flingBackward()71 public void flingBackward() { 72 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 73 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 74 "want to fling backwards in widgets")) { 75 log("Widgets.flingBackward enter"); 76 final UiObject2 widgetsContainer = verifyActiveContainer(); 77 mLauncher.scroll( 78 widgetsContainer, 79 Direction.UP, 80 new Rect(0, 0, mLauncher.getVisibleBounds(widgetsContainer).width(), 0), 81 FLING_STEPS, false); 82 try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) { 83 verifyActiveContainer(); 84 } 85 log("Widgets.flingBackward exit"); 86 } 87 } 88 89 @Override getContainerType()90 protected LauncherInstrumentation.ContainerType getContainerType() { 91 return LauncherInstrumentation.ContainerType.WIDGETS; 92 } 93 getWidgetsScroll()94 private int getWidgetsScroll() { 95 return mLauncher.getTestInfo( 96 TestProtocol.REQUEST_WIDGETS_SCROLL_Y) 97 .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); 98 } 99 getWidget(String labelText)100 public Widget getWidget(String labelText) { 101 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 102 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 103 "getting widget " + labelText + " in widgets list")) { 104 final UiObject2 searchBar = findSearchBar(); 105 final int searchBarHeight = searchBar.getVisibleBounds().height(); 106 final UiObject2 fullWidgetsPicker = verifyActiveContainer(); 107 mLauncher.assertTrue("Widgets container didn't become scrollable", 108 fullWidgetsPicker.wait(Until.scrollable(true), WAIT_TIME_MS)); 109 110 final UiObject2 widgetsContainer = findTestAppWidgetsTableContainer(); 111 mLauncher.assertTrue("Can't locate widgets list for the test app: " 112 + mLauncher.getLauncherPackageName(), 113 widgetsContainer != null); 114 final BySelector labelSelector = By.clazz("android.widget.TextView").text(labelText); 115 final BySelector previewSelector = By.res(mLauncher.getLauncherPackageName(), 116 "widget_preview"); 117 int i = 0; 118 for (; ; ) { 119 final Collection<UiObject2> tableRows = widgetsContainer.getChildren(); 120 for (UiObject2 row : tableRows) { 121 final Collection<UiObject2> widgetCells = row.getChildren(); 122 for (UiObject2 widget : widgetCells) { 123 final UiObject2 label = mLauncher.findObjectInContainer(widget, 124 labelSelector); 125 if (label == null) { 126 continue; 127 } 128 mLauncher.assertEquals( 129 "View is not WidgetCell", 130 "com.android.launcher3.widget.WidgetCell", 131 widget.getClassName()); 132 UiObject2 preview = mLauncher.waitForObjectInContainer(widget, 133 previewSelector); 134 return new Widget(mLauncher, preview); 135 } 136 } 137 138 mLauncher.assertTrue("Too many attempts", ++i <= SCROLL_ATTEMPTS); 139 final int scroll = getWidgetsScroll(); 140 mLauncher.scrollDownByDistance(fullWidgetsPicker, searchBarHeight); 141 final int newScroll = getWidgetsScroll(); 142 mLauncher.assertTrue( 143 "Scrolled in a wrong direction in Widgets: from " + scroll + " to " 144 + newScroll, newScroll >= scroll); 145 mLauncher.assertTrue("Unable to scroll to the widget", newScroll != scroll); 146 } 147 } 148 } 149 findSearchBar()150 private UiObject2 findSearchBar() { 151 final BySelector searchBarContainerSelector = By.res(mLauncher.getLauncherPackageName(), 152 "search_and_recommendations_container"); 153 final BySelector searchBarSelector = By.res(mLauncher.getLauncherPackageName(), 154 "widgets_search_bar"); 155 final UiObject2 searchBarContainer = mLauncher.waitForLauncherObject( 156 searchBarContainerSelector); 157 UiObject2 searchBar = mLauncher.waitForObjectInContainer(searchBarContainer, 158 searchBarSelector); 159 return searchBar; 160 } 161 162 /** Finds the widgets list of this test app from the collapsed full widgets picker. */ findTestAppWidgetsTableContainer()163 private UiObject2 findTestAppWidgetsTableContainer() { 164 final BySelector headerSelector = By.res(mLauncher.getLauncherPackageName(), 165 "widgets_list_header"); 166 final BySelector targetAppSelector = By.clazz("android.widget.TextView").text( 167 mLauncher.getContext().getPackageName()); 168 final BySelector widgetsContainerSelector = By.res(mLauncher.getLauncherPackageName(), 169 "widgets_table"); 170 171 boolean hasHeaderExpanded = false; 172 int scrollDistance = 0; 173 for (int i = 0; i < SCROLL_ATTEMPTS; i++) { 174 UiObject2 fullWidgetsPicker = verifyActiveContainer(); 175 176 UiObject2 header = mLauncher.waitForObjectInContainer(fullWidgetsPicker, 177 headerSelector); 178 // If a header is barely visible in the bottom edge of the screen, its height could be 179 // too small for a scroll gesture. Since all header should have roughly the same height, 180 // let's pick the max height we have seen so far. 181 scrollDistance = Math.max(scrollDistance, header.getVisibleBounds().height()); 182 183 // Look for a header that has the test app name. 184 UiObject2 headerTitle = mLauncher.findObjectInContainer(fullWidgetsPicker, 185 targetAppSelector); 186 if (headerTitle != null) { 187 // If we find the header and it has not been expanded, let's click it to see the 188 // widgets list. Note that we wait until the header is out of the gesture region at 189 // the bottom of the screen, because tapping there in Launcher3 causes NexusLauncher 190 // to briefly appear to handle the gesture, which can break our test. 191 boolean isHeaderOutOfGestureRegion = headerTitle.getVisibleCenter().y 192 < mLauncher.getBottomGestureStartOnScreen(); 193 if (!hasHeaderExpanded && isHeaderOutOfGestureRegion) { 194 log("Header has not been expanded. Click to expand."); 195 hasHeaderExpanded = true; 196 mLauncher.clickLauncherObject(headerTitle); 197 } 198 199 // Look for a widgets list. 200 UiObject2 widgetsContainer = mLauncher.findObjectInContainer(fullWidgetsPicker, 201 widgetsContainerSelector); 202 if (widgetsContainer != null) { 203 log("Widgets container found."); 204 return widgetsContainer; 205 } 206 } 207 log("Finding test widget package - scroll with distance: " + scrollDistance); 208 mLauncher.scrollDownByDistance(fullWidgetsPicker, scrollDistance); 209 } 210 211 return null; 212 } 213 } 214