• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.shared.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, 0,
81                             mLauncher.getBottomGestureMarginInContainer(widgetsContainer) + 1),
82                     FLING_STEPS, false);
83             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
84                 verifyActiveContainer();
85             }
86             log("Widgets.flingBackward exit");
87         }
88     }
89 
90     @Override
getContainerType()91     protected LauncherInstrumentation.ContainerType getContainerType() {
92         return LauncherInstrumentation.ContainerType.WIDGETS;
93     }
94 
getWidgetsScroll()95     private int getWidgetsScroll() {
96         return mLauncher.getTestInfo(
97                 TestProtocol.REQUEST_WIDGETS_SCROLL_Y)
98                 .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
99     }
100 
getWidget(String labelText)101     public Widget getWidget(String labelText) {
102         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
103              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
104                      "getting widget " + labelText + " in widgets list")) {
105             final UiObject2 searchBar = findSearchBar();
106             final int searchBarHeight = searchBar.getVisibleBounds().height();
107             final UiObject2 fullWidgetsPicker = verifyActiveContainer();
108             mLauncher.assertTrue("Widgets container didn't become scrollable",
109                     fullWidgetsPicker.wait(Until.scrollable(true), WAIT_TIME_MS));
110 
111             final UiObject2 widgetsContainer = findTestAppWidgetsTableContainer();
112             mLauncher.assertTrue("Can't locate widgets list for the test app: "
113                             + mLauncher.getLauncherPackageName(),
114                     widgetsContainer != null);
115             final BySelector labelSelector = By.clazz("android.widget.TextView").text(labelText);
116             final BySelector previewSelector = By.res(mLauncher.getLauncherPackageName(),
117                     "widget_preview");
118             final int bottomGestureStartOnScreen = mLauncher.getBottomGestureStartOnScreen();
119             int i = 0;
120             for (; ; ) {
121                 final Collection<UiObject2> tableRows = mLauncher.getChildren(widgetsContainer);
122                 for (UiObject2 row : tableRows) {
123                     final Collection<UiObject2> widgetCells = mLauncher.getChildren(row);
124                     for (UiObject2 widget : widgetCells) {
125                         final UiObject2 label = mLauncher.findObjectInContainer(widget,
126                                 labelSelector);
127                         if (label == null) {
128                             continue;
129                         }
130                         if (widget.getVisibleCenter().y >= bottomGestureStartOnScreen) {
131                             continue;
132                         }
133                         mLauncher.assertEquals(
134                                 "View is not WidgetCell",
135                                 "com.android.launcher3.widget.WidgetCell",
136                                 widget.getClassName());
137                         UiObject2 preview = mLauncher.waitForObjectInContainer(widget,
138                                 previewSelector);
139                         return new Widget(mLauncher, preview);
140                     }
141                 }
142 
143                 mLauncher.assertTrue("Too many attempts", ++i <= SCROLL_ATTEMPTS);
144                 final int scroll = getWidgetsScroll();
145                 mLauncher.scrollDownByDistance(fullWidgetsPicker, searchBarHeight);
146                 final int newScroll = getWidgetsScroll();
147                 mLauncher.assertTrue(
148                         "Scrolled in a wrong direction in Widgets: from " + scroll + " to "
149                                 + newScroll, newScroll >= scroll);
150                 mLauncher.assertTrue("Unable to scroll to the widget", newScroll != scroll);
151             }
152         }
153     }
154 
findSearchBar()155     private UiObject2 findSearchBar() {
156         final BySelector searchBarContainerSelector = By.res(mLauncher.getLauncherPackageName(),
157                 "search_and_recommendations_container");
158         final BySelector searchBarSelector = By.res(mLauncher.getLauncherPackageName(),
159                 "widgets_search_bar");
160         final UiObject2 searchBarContainer = mLauncher.waitForLauncherObject(
161                 searchBarContainerSelector);
162         UiObject2 searchBar = mLauncher.waitForObjectInContainer(searchBarContainer,
163                 searchBarSelector);
164         return searchBar;
165     }
166 
167     /** Finds the widgets list of this test app from the collapsed full widgets picker. */
findTestAppWidgetsTableContainer()168     private UiObject2 findTestAppWidgetsTableContainer() {
169         final BySelector headerSelector = By.res(mLauncher.getLauncherPackageName(),
170                 "widgets_list_header");
171         final BySelector widgetPickerSelector = By.res(mLauncher.getLauncherPackageName(),
172                 "container");
173         final BySelector targetAppSelector = By.clazz("android.widget.TextView").text(
174                 mLauncher.getContext().getPackageName());
175         final BySelector widgetsContainerSelector = By.res(mLauncher.getLauncherPackageName(),
176                 "widgets_table");
177 
178         boolean hasHeaderExpanded = false;
179         int scrollDistance = 0;
180         for (int i = 0; i < SCROLL_ATTEMPTS; i++) {
181             UiObject2 widgetPicker = mLauncher.waitForLauncherObject(widgetPickerSelector);
182             UiObject2 widgetListView = verifyActiveContainer();
183             UiObject2 header = mLauncher.waitForObjectInContainer(widgetListView,
184                     headerSelector);
185             // If a header is barely visible in the bottom edge of the screen, its height could be
186             // too small for a scroll gesture. Since all header should have roughly the same height,
187             // let's pick the max height we have seen so far.
188             scrollDistance = Math.max(scrollDistance, header.getVisibleBounds().height());
189 
190             // Look for a header that has the test app name.
191             UiObject2 headerTitle = mLauncher.findObjectInContainer(widgetListView,
192                     targetAppSelector);
193             if (headerTitle != null) {
194                 // If we find the header and it has not been expanded, let's click it to see the
195                 // widgets list. Note that we wait until the header is out of the gesture region at
196                 // the bottom of the screen, because tapping there in Launcher3 causes NexusLauncher
197                 // to briefly appear to handle the gesture, which can break our test.
198                 boolean isHeaderOutOfGestureRegion = headerTitle.getVisibleCenter().y
199                         < mLauncher.getBottomGestureStartOnScreen();
200                 if (!hasHeaderExpanded && isHeaderOutOfGestureRegion) {
201                     log("Header has not been expanded. Click to expand.");
202                     hasHeaderExpanded = true;
203                     mLauncher.clickLauncherObject(headerTitle);
204                 }
205 
206                 // If we are in a tablet in landscape mode then we will have a two pane view and we
207                 // use the right pane to display the widgets table.
208                 UiObject2 rightPane = mLauncher.findObjectInContainer(
209                         widgetPicker,
210                         widgetsContainerSelector);
211 
212                 // Look for a widgets list.
213                 UiObject2 widgetsContainer = mLauncher.findObjectInContainer(
214                         rightPane != null ? rightPane : widgetListView,
215                         widgetsContainerSelector);
216                 if (widgetsContainer != null) {
217                     log("Widgets container found.");
218                     return widgetsContainer;
219                 }
220             }
221             log("Finding test widget package - scroll with distance: " + scrollDistance);
222 
223             // If we are in a tablet in landscape mode then we will have a two pane view and we use
224             // the right pane to display the widgets table.
225             UiObject2 rightPane = mLauncher.findObjectInContainer(
226                     widgetPicker,
227                     widgetsContainerSelector);
228 
229             mLauncher.scrollDownByDistance(hasHeaderExpanded && rightPane != null
230                     ? rightPane
231                     : widgetListView, scrollDistance);
232         }
233 
234         return null;
235     }
236 }
237