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.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
20 
21 import static junit.framework.TestCase.assertTrue;
22 
23 import android.graphics.Point;
24 import android.graphics.Rect;
25 import android.os.SystemClock;
26 import android.view.KeyEvent;
27 import android.view.MotionEvent;
28 
29 import androidx.annotation.NonNull;
30 import androidx.annotation.Nullable;
31 import androidx.test.uiautomator.By;
32 import androidx.test.uiautomator.Direction;
33 import androidx.test.uiautomator.UiObject2;
34 
35 import com.android.launcher3.testing.TestProtocol;
36 
37 /**
38  * Operations on the workspace screen.
39  */
40 public final class Workspace extends Home {
41     private static final int DRAG_DURACTION = 2000;
42     private static final int FLING_STEPS = 10;
43     private final UiObject2 mHotseat;
44 
Workspace(LauncherInstrumentation launcher)45     Workspace(LauncherInstrumentation launcher) {
46         super(launcher);
47         mHotseat = launcher.waitForLauncherObject("hotseat");
48     }
49 
50     /**
51      * Swipes up to All Apps.
52      *
53      * @return the App Apps object.
54      */
55     @NonNull
switchToAllApps()56     public AllApps switchToAllApps() {
57         try (LauncherInstrumentation.Closable c =
58                      mLauncher.addContextLayer("want to switch from workspace to all apps")) {
59             verifyActiveContainer();
60             final UiObject2 hotseat = mHotseat;
61             final Point start = hotseat.getVisibleCenter();
62             start.y = hotseat.getVisibleBounds().bottom - 1;
63             final int swipeHeight = mLauncher.getTestInfo(
64                     TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT).
65                     getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
66             LauncherInstrumentation.log(
67                     "switchToAllApps: swipeHeight = " + swipeHeight + ", slop = "
68                             + mLauncher.getTouchSlop());
69 
70             mLauncher.swipeToState(
71                     start.x,
72                     start.y,
73                     start.x,
74                     start.y - swipeHeight - mLauncher.getTouchSlop(),
75                     60,
76                     ALL_APPS_STATE_ORDINAL);
77 
78             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
79                     "swiped to all apps")) {
80                 return new AllApps(mLauncher);
81             }
82         }
83     }
84 
85     /**
86      * Returns an icon for the app, if currently visible.
87      *
88      * @param appName name of the app
89      * @return app icon, if found, null otherwise.
90      */
91     @Nullable
tryGetWorkspaceAppIcon(String appName)92     public AppIcon tryGetWorkspaceAppIcon(String appName) {
93         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
94                 "want to get a workspace icon")) {
95             final UiObject2 workspace = verifyActiveContainer();
96             final UiObject2 icon = workspace.findObject(
97                     AppIcon.getAppIconSelector(appName, mLauncher));
98             return icon != null ? new AppIcon(mLauncher, icon) : null;
99         }
100     }
101 
102 
103     /**
104      * Returns an icon for the app; fails if the icon doesn't exist.
105      *
106      * @param appName name of the app
107      * @return app icon.
108      */
109     @NonNull
getWorkspaceAppIcon(String appName)110     public AppIcon getWorkspaceAppIcon(String appName) {
111         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
112                 "want to get a workspace icon")) {
113             return new AppIcon(mLauncher,
114                     mLauncher.waitForObjectInContainer(
115                             verifyActiveContainer(),
116                             AppIcon.getAppIconSelector(appName, mLauncher)));
117         }
118     }
119 
120     /**
121      * Ensures that workspace is scrollable. If it's not, drags an icon icons from hotseat to the
122      * second screen.
123      */
ensureWorkspaceIsScrollable()124     public void ensureWorkspaceIsScrollable() {
125         final UiObject2 workspace = verifyActiveContainer();
126         if (!isWorkspaceScrollable(workspace)) {
127             try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
128                     "dragging icon to a second page of workspace to make it scrollable")) {
129                 dragIconToWorkspace(
130                         mLauncher,
131                         getHotseatAppIcon("Chrome"),
132                         new Point(mLauncher.getDevice().getDisplayWidth(),
133                                 workspace.getVisibleBounds().centerY()),
134                         "deep_shortcuts_container");
135                 verifyActiveContainer();
136             }
137         }
138         assertTrue("Home screen workspace didn't become scrollable",
139                 isWorkspaceScrollable(workspace));
140     }
141 
isWorkspaceScrollable(UiObject2 workspace)142     private boolean isWorkspaceScrollable(UiObject2 workspace) {
143         return workspace.getChildCount() > 1;
144     }
145 
146     @NonNull
getHotseatAppIcon(String appName)147     public AppIcon getHotseatAppIcon(String appName) {
148         return new AppIcon(mLauncher, mLauncher.waitForObjectInContainer(
149                 mHotseat, AppIcon.getAppIconSelector(appName, mLauncher)));
150     }
151 
152     @NonNull
getHotseatFolder(String appName)153     public Folder getHotseatFolder(String appName) {
154         return new Folder(mLauncher, mLauncher.waitForObjectInContainer(
155                 mHotseat, Folder.getSelector(appName, mLauncher)));
156     }
157 
dragIconToWorkspace( LauncherInstrumentation launcher, Launchable launchable, Point dest, String longPressIndicator)158     static void dragIconToWorkspace(
159             LauncherInstrumentation launcher, Launchable launchable, Point dest,
160             String longPressIndicator) {
161         LauncherInstrumentation.log("dragIconToWorkspace: begin");
162         final Point launchableCenter = launchable.getObject().getVisibleCenter();
163         final long downTime = SystemClock.uptimeMillis();
164         launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, launchableCenter);
165         LauncherInstrumentation.log("dragIconToWorkspace: sent down");
166         launcher.waitForLauncherObject(longPressIndicator);
167         LauncherInstrumentation.log("dragIconToWorkspace: indicator");
168         launcher.movePointer(
169                 downTime, SystemClock.uptimeMillis(), DRAG_DURACTION, launchableCenter, dest);
170         LauncherInstrumentation.log("dragIconToWorkspace: moved pointer");
171         launcher.sendPointer(
172                 downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest);
173         LauncherInstrumentation.log("dragIconToWorkspace: end");
174         launcher.waitUntilGone("drop_target_bar");
175     }
176 
177     /**
178      * Flings to get to screens on the right. Waits for scrolling and a possible overscroll
179      * recoil to complete.
180      */
flingForward()181     public void flingForward() {
182         final UiObject2 workspace = verifyActiveContainer();
183         mLauncher.scroll(workspace, Direction.RIGHT,
184                 new Rect(0, 0, mLauncher.getEdgeSensitivityWidth(), 0),
185                 FLING_STEPS);
186         verifyActiveContainer();
187     }
188 
189     /**
190      * Flings to get to screens on the left.  Waits for scrolling and a possible overscroll
191      * recoil to complete.
192      */
flingBackward()193     public void flingBackward() {
194         final UiObject2 workspace = verifyActiveContainer();
195         mLauncher.scroll(workspace, Direction.LEFT,
196                 new Rect(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0),
197                 FLING_STEPS);
198         verifyActiveContainer();
199     }
200 
201     /**
202      * Opens widgets container by pressing Ctrl+W.
203      *
204      * @return the widgets container.
205      */
206     @NonNull
openAllWidgets()207     public Widgets openAllWidgets() {
208         verifyActiveContainer();
209         mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
210         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer("pressed Ctrl+W")) {
211             return new Widgets(mLauncher);
212         }
213     }
214 
215     @Override
getSwipeHeightRequestName()216     protected String getSwipeHeightRequestName() {
217         return TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT;
218     }
219 
220     @Override
getSwipeStartY()221     protected int getSwipeStartY() {
222         return mLauncher.getRealDisplaySize().y - 1;
223     }
224 
225     @Nullable
tryGetWidget(String label, long timeout)226     public Widget tryGetWidget(String label, long timeout) {
227         final UiObject2 widget = mLauncher.tryWaitForLauncherObject(
228                 By.clazz("com.android.launcher3.widget.LauncherAppWidgetHostView").desc(label),
229                 timeout);
230         return widget != null ? new Widget(mLauncher, widget) : null;
231     }
232 
233     @Nullable
tryGetPendingWidget(long timeout)234     public Widget tryGetPendingWidget(long timeout) {
235         final UiObject2 widget = mLauncher.tryWaitForLauncherObject(
236                 By.clazz("com.android.launcher3.widget.PendingAppWidgetHostView"), timeout);
237         return widget != null ? new Widget(mLauncher, widget) : null;
238     }
239 }