1 /*
2  * Copyright (C) 2019 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.ui;
18 
19 import static androidx.test.InstrumentationRegistry.getInstrumentation;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertNull;
25 import static org.junit.Assert.assertTrue;
26 
27 import android.util.Log;
28 
29 import androidx.test.filters.LargeTest;
30 import androidx.test.runner.AndroidJUnit4;
31 
32 import com.android.launcher3.Launcher;
33 import com.android.launcher3.LauncherState;
34 import com.android.launcher3.popup.ArrowPopup;
35 import com.android.launcher3.tapl.AllApps;
36 import com.android.launcher3.tapl.AppIcon;
37 import com.android.launcher3.tapl.AppIconMenu;
38 import com.android.launcher3.tapl.AppIconMenuItem;
39 import com.android.launcher3.tapl.Widgets;
40 import com.android.launcher3.tapl.Workspace;
41 import com.android.launcher3.util.rule.TestStabilityRule.Stability;
42 import com.android.launcher3.views.OptionsPopupView;
43 import com.android.launcher3.widget.WidgetsFullSheet;
44 import com.android.launcher3.widget.WidgetsRecyclerView;
45 
46 import org.junit.Before;
47 import org.junit.Ignore;
48 import org.junit.Test;
49 import org.junit.runner.RunWith;
50 
51 @LargeTest
52 @RunWith(AndroidJUnit4.class)
53 public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
54     private static final String APP_NAME = "LauncherTestApp";
55 
56     @Before
setUp()57     public void setUp() throws Exception {
58         super.setUp();
59         initialize(this);
60     }
61 
initialize(AbstractLauncherUiTest test)62     public static void initialize(AbstractLauncherUiTest test) throws Exception {
63         test.clearLauncherData();
64         test.mDevice.pressHome();
65         test.waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null);
66         test.waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL);
67         test.waitForResumed("Launcher internal state is still Background");
68         // Check that we switched to home.
69         test.mLauncher.getWorkspace();
70     }
71 
72     // Please don't add negative test cases for methods that fail only after a long wait.
expectFail(String message, Runnable action)73     public static void expectFail(String message, Runnable action) {
74         boolean failed = false;
75         try {
76             action.run();
77         } catch (AssertionError e) {
78             failed = true;
79         }
80         assertTrue(message, failed);
81     }
82 
isWorkspaceScrollable(Launcher launcher)83     private boolean isWorkspaceScrollable(Launcher launcher) {
84         return launcher.getWorkspace().getPageCount() > 1;
85     }
86 
getCurrentWorkspacePage(Launcher launcher)87     private int getCurrentWorkspacePage(Launcher launcher) {
88         return launcher.getWorkspace().getCurrentPage();
89     }
90 
getWidgetsView(Launcher launcher)91     private WidgetsRecyclerView getWidgetsView(Launcher launcher) {
92         return WidgetsFullSheet.getWidgetsView(launcher);
93     }
94 
95     @Test
testDevicePressMenu()96     public void testDevicePressMenu() throws Exception {
97         mDevice.pressMenu();
98         mDevice.waitForIdle();
99         executeOnLauncher(
100                 launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
101                         OptionsPopupView.getOptionsPopup(launcher) != null));
102         // Check that pressHome works when the menu is shown.
103         mLauncher.pressHome();
104     }
105 
106     @Test
107     @Ignore
testPressHomeOnAllAppsContextMenu()108     public void testPressHomeOnAllAppsContextMenu() throws Exception {
109         final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
110         allApps.freeze();
111         try {
112             allApps.getAppIcon("TestActivity7").openMenu();
113         } finally {
114             allApps.unfreeze();
115         }
116         mLauncher.pressHome();
117     }
118 
runAllAppsTest(AbstractLauncherUiTest test, AllApps allApps)119     public static void runAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) {
120         allApps.freeze();
121         try {
122             assertNotNull("allApps parameter is null", allApps);
123 
124             assertTrue(
125                     "Launcher internal state is not All Apps",
126                     test.isInState(LauncherState.ALL_APPS));
127 
128             // Test flinging forward and backward.
129             test.executeOnLauncher(launcher -> assertEquals(
130                     "All Apps started in already scrolled state", 0,
131                     test.getAllAppsScroll(launcher)));
132 
133             allApps.flingForward();
134             assertTrue("Launcher internal state is not All Apps",
135                     test.isInState(LauncherState.ALL_APPS));
136             final Integer flingForwardY = test.getFromLauncher(
137                     launcher -> test.getAllAppsScroll(launcher));
138             test.executeOnLauncher(
139                     launcher -> assertTrue("flingForward() didn't scroll App Apps",
140                             flingForwardY > 0));
141 
142             allApps.flingBackward();
143             assertTrue(
144                     "Launcher internal state is not All Apps",
145                     test.isInState(LauncherState.ALL_APPS));
146             final Integer flingBackwardY = test.getFromLauncher(
147                     launcher -> test.getAllAppsScroll(launcher));
148             test.executeOnLauncher(launcher -> assertTrue("flingBackward() didn't scroll App Apps",
149                     flingBackwardY < flingForwardY));
150 
151             // Test scrolling down to YouTube.
152             assertNotNull("All apps: can't fine YouTube", allApps.getAppIcon("YouTube"));
153             // Test scrolling up to Camera.
154             assertNotNull("All apps: can't fine Camera", allApps.getAppIcon("Camera"));
155             // Test failing to find a non-existing app.
156             final AllApps allAppsFinal = allApps;
157             expectFail("All apps: could find a non-existing app",
158                     () -> allAppsFinal.getAppIcon("NO APP"));
159 
160             assertTrue(
161                     "Launcher internal state is not All Apps",
162                     test.isInState(LauncherState.ALL_APPS));
163         } finally {
164             allApps.unfreeze();
165         }
166     }
167 
168     @Test
169     @PortraitLandscape
testWorkspaceSwitchToAllApps()170     public void testWorkspaceSwitchToAllApps() {
171         assertNotNull("switchToAllApps() returned null",
172                 mLauncher.getWorkspace().switchToAllApps());
173         assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
174     }
175 
176     @Test
testWorkspace()177     public void testWorkspace() throws Exception {
178         final Workspace workspace = mLauncher.getWorkspace();
179 
180         // Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there.
181         executeOnLauncher(launcher -> assertFalse("Initial workspace state is scrollable",
182                 isWorkspaceScrollable(launcher)));
183         assertNull("Chrome app was found on empty workspace",
184                 workspace.tryGetWorkspaceAppIcon("Chrome"));
185 
186         workspace.ensureWorkspaceIsScrollable();
187 
188         executeOnLauncher(
189                 launcher -> assertEquals("Ensuring workspace scrollable didn't switch to page #1",
190                         1, getCurrentWorkspacePage(launcher)));
191         executeOnLauncher(
192                 launcher -> assertTrue("ensureScrollable didn't make workspace scrollable",
193                         isWorkspaceScrollable(launcher)));
194         assertNotNull("ensureScrollable didn't add Chrome app",
195                 workspace.getWorkspaceAppIcon("Chrome"));
196 
197         // Test flinging workspace.
198         workspace.flingBackward();
199         assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL));
200         executeOnLauncher(
201                 launcher -> assertEquals("Flinging back didn't switch workspace to page #0",
202                         0, getCurrentWorkspacePage(launcher)));
203 
204         workspace.flingForward();
205         executeOnLauncher(
206                 launcher -> assertEquals("Flinging forward didn't switch workspace to page #1",
207                         1, getCurrentWorkspacePage(launcher)));
208         assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL));
209 
210         // Test starting a workspace app.
211         final AppIcon app = workspace.getWorkspaceAppIcon("Chrome");
212         assertNotNull("No Chrome app in workspace", app);
213     }
214 
runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps)215     public static void runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) {
216         allApps.freeze();
217         try {
218             final AppIcon app = allApps.getAppIcon("TestActivity7");
219             assertNotNull("AppIcon.launch returned null", app.launch(getAppPackageName()));
220             test.executeOnLauncher(launcher -> assertTrue(
221                     "Launcher activity is the top activity; expecting another activity to be the "
222                             + "top "
223                             + "one",
224                     test.isInBackground(launcher)));
225         } finally {
226             allApps.unfreeze();
227         }
228     }
229 
230     @Test
231     @PortraitLandscape
testAppIconLaunchFromAllAppsFromHome()232     public void testAppIconLaunchFromAllAppsFromHome() throws Exception {
233         final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
234         assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
235 
236         runIconLaunchFromAllAppsTest(this, allApps);
237     }
238 
239     @Test
240     @PortraitLandscape
testWidgets()241     public void testWidgets() throws Exception {
242         // Test opening widgets.
243         executeOnLauncher(launcher ->
244                 assertTrue("Widgets is initially opened", getWidgetsView(launcher) == null));
245         Widgets widgets = mLauncher.getWorkspace().openAllWidgets();
246         assertNotNull("openAllWidgets() returned null", widgets);
247         widgets = mLauncher.getAllWidgets();
248         assertNotNull("getAllWidgets() returned null", widgets);
249         executeOnLauncher(launcher ->
250                 assertTrue("Widgets is not shown", getWidgetsView(launcher).isShown()));
251         executeOnLauncher(launcher -> assertEquals("Widgets is scrolled upon opening",
252                 0, getWidgetsScroll(launcher)));
253 
254         // Test flinging widgets.
255         widgets.flingForward();
256         Integer flingForwardY = getFromLauncher(launcher -> getWidgetsScroll(launcher));
257         executeOnLauncher(launcher -> assertTrue("Flinging forward didn't scroll widgets",
258                 flingForwardY > 0));
259 
260         widgets.flingBackward();
261         executeOnLauncher(launcher -> assertTrue("Flinging backward didn't scroll widgets",
262                 getWidgetsScroll(launcher) < flingForwardY));
263 
264         mLauncher.pressHome();
265         waitForLauncherCondition("Widgets were not closed",
266                 launcher -> getWidgetsView(launcher) == null);
267     }
268 
getWidgetsScroll(Launcher launcher)269     private int getWidgetsScroll(Launcher launcher) {
270         return getWidgetsView(launcher).getCurrentScrollY();
271     }
272 
isOptionsPopupVisible(Launcher launcher)273     private boolean isOptionsPopupVisible(Launcher launcher) {
274         final ArrowPopup popup = OptionsPopupView.getOptionsPopup(launcher);
275         return popup != null && popup.isShown();
276     }
277 
278     @Test
279     @PortraitLandscape
testLaunchMenuItem()280     public void testLaunchMenuItem() throws Exception {
281         final AllApps allApps = mLauncher.
282                 getWorkspace().
283                 switchToAllApps();
284         allApps.freeze();
285         try {
286             final AppIconMenu menu = allApps.
287                     getAppIcon(APP_NAME).
288                     openMenu();
289 
290             executeOnLauncher(
291                     launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
292                             isOptionsPopupVisible(launcher)));
293 
294             menu.getMenuItem(1).launch(getAppPackageName());
295         } finally {
296             allApps.unfreeze();
297         }
298     }
299 
300     @Test
301     @PortraitLandscape
testDragAppIcon()302     public void testDragAppIcon() throws Throwable {
303         // 1. Open all apps and wait for load complete.
304         // 2. Drag icon to homescreen.
305         // 3. Verify that the icon works on homescreen.
306         final AllApps allApps = mLauncher.getWorkspace().
307                 switchToAllApps();
308         allApps.freeze();
309         try {
310             allApps.getAppIcon(APP_NAME).dragToWorkspace();
311             mLauncher.getWorkspace().getWorkspaceAppIcon(APP_NAME).launch(getAppPackageName());
312         } finally {
313             allApps.unfreeze();
314         }
315         executeOnLauncher(launcher -> assertTrue(
316                 "Launcher activity is the top activity; expecting another activity to be the top "
317                         + "one",
318                 isInBackground(launcher)));
319     }
320 
321     @Test
322     @PortraitLandscape
testDragShortcut()323     public void testDragShortcut() throws Throwable {
324         // 1. Open all apps and wait for load complete.
325         // 2. Find the app and long press it to show shortcuts.
326         // 3. Press icon center until shortcuts appear
327         final AllApps allApps = mLauncher.
328                 getWorkspace().
329                 switchToAllApps();
330         allApps.freeze();
331         try {
332             final AppIconMenuItem menuItem = allApps.
333                     getAppIcon(APP_NAME).
334                     openMenu().
335                     getMenuItem(0);
336             final String shortcutName = menuItem.getText();
337 
338             menuItem.dragToWorkspace();
339             mLauncher.getWorkspace().getWorkspaceAppIcon(shortcutName).launch(getAppPackageName());
340         } finally {
341             allApps.unfreeze();
342         }
343     }
344 
getAppPackageName()345     public static String getAppPackageName() {
346         return getInstrumentation().getContext().getPackageName();
347     }
348 
349     @Test
350     @Stability
testTestStabilityAttribute()351     public void testTestStabilityAttribute() {
352         Log.d("TestStabilityRule", "Hello world!");
353     }
354 }
355