• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.google.common.truth.Truth.assertThat;
22 
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assume.assumeTrue;
29 
30 import android.content.Intent;
31 import android.graphics.Point;
32 import android.os.SystemClock;
33 import android.platform.test.annotations.IwTest;
34 import android.util.Log;
35 
36 import androidx.test.filters.LargeTest;
37 import androidx.test.runner.AndroidJUnit4;
38 
39 import com.android.launcher3.Launcher;
40 import com.android.launcher3.LauncherState;
41 import com.android.launcher3.popup.ArrowPopup;
42 import com.android.launcher3.tapl.AllApps;
43 import com.android.launcher3.tapl.AppIcon;
44 import com.android.launcher3.tapl.AppIconMenu;
45 import com.android.launcher3.tapl.AppIconMenuItem;
46 import com.android.launcher3.tapl.Folder;
47 import com.android.launcher3.tapl.FolderIcon;
48 import com.android.launcher3.tapl.HomeAllApps;
49 import com.android.launcher3.tapl.HomeAppIcon;
50 import com.android.launcher3.tapl.HomeAppIconMenu;
51 import com.android.launcher3.tapl.HomeAppIconMenuItem;
52 import com.android.launcher3.tapl.Widgets;
53 import com.android.launcher3.tapl.Workspace;
54 import com.android.launcher3.util.TestUtil;
55 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
56 import com.android.launcher3.util.rule.TISBindRule;
57 import com.android.launcher3.widget.picker.WidgetsFullSheet;
58 import com.android.launcher3.widget.picker.WidgetsRecyclerView;
59 
60 import org.junit.Before;
61 import org.junit.Ignore;
62 import org.junit.Rule;
63 import org.junit.Test;
64 import org.junit.runner.RunWith;
65 
66 import java.io.IOException;
67 import java.util.Map;
68 
69 @LargeTest
70 @RunWith(AndroidJUnit4.class)
71 public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
72     private static final String APP_NAME = "LauncherTestApp";
73     private static final String DUMMY_APP_NAME = "Aardwolf";
74     private static final String MAPS_APP_NAME = "Maps";
75     private static final String STORE_APP_NAME = "Play Store";
76     private static final String GMAIL_APP_NAME = "Gmail";
77 
78     @Rule
79     public TISBindRule mTISBindRule = new TISBindRule();
80 
81     @Before
setUp()82     public void setUp() throws Exception {
83         super.setUp();
84         initialize(this);
85     }
86 
initialize(AbstractLauncherUiTest test)87     public static void initialize(AbstractLauncherUiTest test) throws Exception {
88         test.clearLauncherData();
89         test.mDevice.pressHome();
90         test.waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null);
91         test.waitForState("Launcher internal state didn't switch to Home",
92                 () -> LauncherState.NORMAL);
93         test.waitForResumed("Launcher internal state is still Background");
94         // Check that we switched to home.
95         test.mLauncher.getWorkspace();
96         AbstractLauncherUiTest.checkDetectedLeaks(test.mLauncher);
97     }
98 
99     // Please don't add negative test cases for methods that fail only after a long wait.
expectFail(String message, Runnable action)100     public static void expectFail(String message, Runnable action) {
101         boolean failed = false;
102         try {
103             action.run();
104         } catch (AssertionError e) {
105             failed = true;
106         }
107         assertTrue(message, failed);
108     }
109 
isWorkspaceScrollable(Launcher launcher)110     public static boolean isWorkspaceScrollable(Launcher launcher) {
111         return launcher.getWorkspace().getPageCount() > launcher.getWorkspace().getPanelCount();
112     }
113 
getCurrentWorkspacePage(Launcher launcher)114     private int getCurrentWorkspacePage(Launcher launcher) {
115         return launcher.getWorkspace().getCurrentPage();
116     }
117 
getWidgetsView(Launcher launcher)118     private WidgetsRecyclerView getWidgetsView(Launcher launcher) {
119         return WidgetsFullSheet.getWidgetsView(launcher);
120     }
121 
122     @Test
testDevicePressMenu()123     public void testDevicePressMenu() throws Exception {
124         mDevice.pressMenu();
125         mDevice.waitForIdle();
126         executeOnLauncher(
127                 launcher -> assertNotNull("Launcher internal state didn't switch to Showing Menu",
128                         launcher.getOptionsPopup()));
129         // Check that pressHome works when the menu is shown.
130         mLauncher.goHome();
131     }
132 
133     @Test
134     @ScreenRecord
testPressHomeOnAllAppsContextMenu()135     public void testPressHomeOnAllAppsContextMenu() throws Exception {
136         final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
137         allApps.freeze();
138         try {
139             allApps.getAppIcon("TestActivity7").openMenu();
140         } finally {
141             allApps.unfreeze();
142         }
143         mLauncher.goHome();
144     }
145 
runAllAppsTest(AbstractLauncherUiTest test, AllApps allApps)146     public static void runAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) {
147         allApps.freeze();
148         try {
149             assertNotNull("allApps parameter is null", allApps);
150 
151             assertTrue(
152                     "Launcher internal state is not All Apps",
153                     test.isInState(() -> LauncherState.ALL_APPS));
154 
155             // Test flinging forward and backward.
156             test.executeOnLauncher(launcher -> assertEquals(
157                     "All Apps started in already scrolled state", 0,
158                     test.getAllAppsScroll(launcher)));
159 
160             allApps.flingForward();
161             assertTrue("Launcher internal state is not All Apps",
162                     test.isInState(() -> LauncherState.ALL_APPS));
163             final Integer flingForwardY = test.getFromLauncher(
164                     launcher -> test.getAllAppsScroll(launcher));
165             test.executeOnLauncher(
166                     launcher -> assertTrue("flingForward() didn't scroll App Apps",
167                             flingForwardY > 0));
168 
169             allApps.flingBackward();
170             assertTrue(
171                     "Launcher internal state is not All Apps",
172                     test.isInState(() -> LauncherState.ALL_APPS));
173             final Integer flingBackwardY = test.getFromLauncher(
174                     launcher -> test.getAllAppsScroll(launcher));
175             test.executeOnLauncher(launcher -> assertTrue("flingBackward() didn't scroll App Apps",
176                     flingBackwardY < flingForwardY));
177 
178             // Test scrolling down to YouTube.
179             assertNotNull("All apps: can't find YouTube", allApps.getAppIcon("YouTube"));
180             // Test scrolling up to Camera.
181             assertNotNull("All apps: can't find Camera", allApps.getAppIcon("Camera"));
182             // Test failing to find a non-existing app.
183             final AllApps allAppsFinal = allApps;
184             expectFail("All apps: could find a non-existing app",
185                     () -> allAppsFinal.getAppIcon("NO APP"));
186 
187             assertTrue(
188                     "Launcher internal state is not All Apps",
189                     test.isInState(() -> LauncherState.ALL_APPS));
190         } finally {
191             allApps.unfreeze();
192         }
193     }
194 
195     @Test
196     @PortraitLandscape
testWorkspaceSwitchToAllApps()197     public void testWorkspaceSwitchToAllApps() {
198         assertNotNull("switchToAllApps() returned null",
199                 mLauncher.getWorkspace().switchToAllApps());
200         assertTrue("Launcher internal state is not All Apps",
201                 isInState(() -> LauncherState.ALL_APPS));
202     }
203 
204     @Test
205     @PortraitLandscape
testAllAppsSwitchToWorkspace()206     public void testAllAppsSwitchToWorkspace() {
207         assertNotNull("switchToWorkspace() returned null",
208                 mLauncher.getWorkspace().switchToAllApps().switchToWorkspace());
209         assertTrue("Launcher internal state is not Workspace",
210                 isInState(() -> LauncherState.NORMAL));
211     }
212 
213     @Test
214     @PortraitLandscape
testAllAppsDeadzoneForTablet()215     public void testAllAppsDeadzoneForTablet() throws Exception {
216         assumeTrue(mLauncher.isTablet());
217 
218         mLauncher.getWorkspace().switchToAllApps().dismissByTappingOutsideForTablet(
219                 true /* tapRight */);
220         mLauncher.getWorkspace().switchToAllApps().dismissByTappingOutsideForTablet(
221                 false /* tapRight */);
222     }
223 
224     @IwTest(focusArea = "launcher")
225     @Test
226     @ScreenRecord // b/202433017
testWorkspace()227     public void testWorkspace() throws Exception {
228         // Make sure there is an instance of chrome on the hotseat
229         mLauncher.useTaplWorkspaceLayoutOnReload();
230         clearLauncherData();
231 
232         final Workspace workspace = mLauncher.getWorkspace();
233 
234         // Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there.
235         executeOnLauncher(launcher -> assertFalse("Initial workspace state is scrollable",
236                 isWorkspaceScrollable(launcher)));
237         assertEquals("Initial workspace doesn't have the correct page", workspace.pagesPerScreen(),
238                 workspace.getPageCount());
239         workspace.verifyWorkspaceAppIconIsGone("Chrome app was found on empty workspace", "Chrome");
240         workspace.ensureWorkspaceIsScrollable();
241 
242         executeOnLauncher(
243                 launcher -> assertEquals(
244                         "Ensuring workspace scrollable didn't switch to next screen",
245                         workspace.pagesPerScreen(), getCurrentWorkspacePage(launcher)));
246         executeOnLauncher(
247                 launcher -> assertTrue("ensureScrollable didn't make workspace scrollable",
248                         isWorkspaceScrollable(launcher)));
249         assertNotNull("ensureScrollable didn't add Chrome app",
250                 workspace.getWorkspaceAppIcon("Chrome"));
251 
252         // Test flinging workspace.
253         workspace.flingBackward();
254         assertTrue("Launcher internal state is not Home", isInState(() -> LauncherState.NORMAL));
255         executeOnLauncher(
256                 launcher -> assertEquals("Flinging back didn't switch workspace to page #0",
257                         0, getCurrentWorkspacePage(launcher)));
258 
259         workspace.flingForward();
260         executeOnLauncher(
261                 launcher -> assertEquals("Flinging forward didn't switch workspace to next screen",
262                         workspace.pagesPerScreen(), getCurrentWorkspacePage(launcher)));
263         assertTrue("Launcher internal state is not Home", isInState(() -> LauncherState.NORMAL));
264 
265         // Test starting a workspace app.
266         final HomeAppIcon app = workspace.getWorkspaceAppIcon("Chrome");
267         assertNotNull("No Chrome app in workspace", app);
268     }
269 
runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps)270     public static void runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) {
271         allApps.freeze();
272         try {
273             final AppIcon app = allApps.getAppIcon("TestActivity7");
274             assertNotNull("AppIcon.launch returned null", app.launch(getAppPackageName()));
275             test.executeOnLauncher(launcher -> assertTrue(
276                     "Launcher activity is the top activity; expecting another activity to be the "
277                             + "top one",
278                     test.isInLaunchedApp(launcher)));
279         } finally {
280             allApps.unfreeze();
281         }
282     }
283 
284     @Test
285     @PortraitLandscape
testAppIconLaunchFromAllAppsFromHome()286     public void testAppIconLaunchFromAllAppsFromHome() throws Exception {
287         final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
288         assertTrue("Launcher internal state is not All Apps",
289                 isInState(() -> LauncherState.ALL_APPS));
290 
291         runIconLaunchFromAllAppsTest(this, allApps);
292     }
293 
294     @Test
295     @PortraitLandscape
testWidgets()296     public void testWidgets() throws Exception {
297         // Test opening widgets.
298         executeOnLauncher(launcher ->
299                 assertTrue("Widgets is initially opened", getWidgetsView(launcher) == null));
300         Widgets widgets = mLauncher.getWorkspace().openAllWidgets();
301         assertNotNull("openAllWidgets() returned null", widgets);
302         widgets = mLauncher.getAllWidgets();
303         assertNotNull("getAllWidgets() returned null", widgets);
304         executeOnLauncher(launcher ->
305                 assertTrue("Widgets is not shown", getWidgetsView(launcher).isShown()));
306         executeOnLauncher(launcher -> assertEquals("Widgets is scrolled upon opening",
307                 0, getWidgetsScroll(launcher)));
308 
309         // Test flinging widgets.
310         widgets.flingForward();
311         Integer flingForwardY = getFromLauncher(launcher -> getWidgetsScroll(launcher));
312         executeOnLauncher(launcher -> assertTrue("Flinging forward didn't scroll widgets",
313                 flingForwardY > 0));
314 
315         widgets.flingBackward();
316         executeOnLauncher(launcher -> assertTrue("Flinging backward didn't scroll widgets",
317                 getWidgetsScroll(launcher) < flingForwardY));
318 
319         mLauncher.goHome();
320         waitForLauncherCondition("Widgets were not closed",
321                 launcher -> getWidgetsView(launcher) == null);
322     }
323 
getWidgetsScroll(Launcher launcher)324     private int getWidgetsScroll(Launcher launcher) {
325         return getWidgetsView(launcher).computeVerticalScrollOffset();
326     }
327 
isOptionsPopupVisible(Launcher launcher)328     private boolean isOptionsPopupVisible(Launcher launcher) {
329         final ArrowPopup<?> popup = launcher.getOptionsPopup();
330         return popup != null && popup.isShown();
331     }
332 
333     @Test
334     @PortraitLandscape
testLaunchMenuItem()335     public void testLaunchMenuItem() throws Exception {
336         final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
337         allApps.freeze();
338         try {
339             final AppIconMenu menu = allApps.
340                     getAppIcon(APP_NAME).
341                     openDeepShortcutMenu();
342 
343             executeOnLauncher(
344                     launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
345                             isOptionsPopupVisible(launcher)));
346 
347             final AppIconMenuItem menuItem = menu.getMenuItem(1);
348             assertEquals("Wrong menu item", "Shortcut 2", menuItem.getText());
349             menuItem.launch(getAppPackageName());
350         } finally {
351             allApps.unfreeze();
352         }
353     }
354 
355     @IwTest(focusArea = "launcher")
356     @Test
357     @PortraitLandscape
358     @ScreenRecord // b/256898879
testDragAppIcon()359     public void testDragAppIcon() throws Throwable {
360         // 1. Open all apps and wait for load complete.
361         // 2. Drag icon to homescreen.
362         // 3. Verify that the icon works on homescreen.
363         final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
364         allApps.freeze();
365         try {
366             allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false);
367             mLauncher.getWorkspace().getWorkspaceAppIcon(APP_NAME).launch(getAppPackageName());
368         } finally {
369             allApps.unfreeze();
370         }
371         executeOnLauncher(launcher -> assertTrue(
372                 "Launcher activity is the top activity; expecting another activity to be the top "
373                         + "one",
374                 isInLaunchedApp(launcher)));
375     }
376 
377     @Test
378     @PortraitLandscape
testDragShortcut()379     public void testDragShortcut() throws Throwable {
380         // 1. Open all apps and wait for load complete.
381         // 2. Find the app and long press it to show shortcuts.
382         // 3. Press icon center until shortcuts appear
383         final HomeAllApps allApps = mLauncher
384                 .getWorkspace()
385                 .switchToAllApps();
386         allApps.freeze();
387         try {
388             final HomeAppIconMenu menu = allApps
389                     .getAppIcon(APP_NAME)
390                     .openDeepShortcutMenu();
391             final HomeAppIconMenuItem menuItem0 = menu.getMenuItem(0);
392             final HomeAppIconMenuItem menuItem2 = menu.getMenuItem(2);
393 
394             final HomeAppIconMenuItem menuItem;
395 
396             final String expectedShortcutName = "Shortcut 3";
397             if (menuItem0.getText().equals(expectedShortcutName)) {
398                 menuItem = menuItem0;
399             } else {
400                 final String shortcutName2 = menuItem2.getText();
401                 assertEquals("Wrong menu item", expectedShortcutName, shortcutName2);
402                 menuItem = menuItem2;
403             }
404 
405             menuItem.dragToWorkspace(false, false);
406             mLauncher.getWorkspace().getWorkspaceAppIcon(expectedShortcutName)
407                     .launch(getAppPackageName());
408         } finally {
409             allApps.unfreeze();
410         }
411     }
412 
413     @Test
414     @PortraitLandscape
415     @ScreenRecord
416     @Ignore // b/233075289
testDragToFolder()417     public void testDragToFolder() {
418         // TODO: add the use case to drag an icon to an existing folder. Currently it either fails
419         // on tablets or phones due to difference in resolution.
420         final HomeAppIcon playStoreIcon = createShortcutIfNotExist(STORE_APP_NAME, 0, 1);
421         final HomeAppIcon gmailIcon = createShortcutInCenterIfNotExist(GMAIL_APP_NAME);
422 
423         FolderIcon folderIcon = gmailIcon.dragToIcon(playStoreIcon);
424         Folder folder = folderIcon.open();
425         folder.getAppIcon(STORE_APP_NAME);
426         folder.getAppIcon(GMAIL_APP_NAME);
427         Workspace workspace = folder.close();
428 
429         workspace.verifyWorkspaceAppIconIsGone(STORE_APP_NAME + " should be moved to a folder.",
430                 STORE_APP_NAME);
431         workspace.verifyWorkspaceAppIconIsGone(GMAIL_APP_NAME + " should be moved to a folder.",
432                 GMAIL_APP_NAME);
433 
434         final HomeAppIcon mapIcon = createShortcutInCenterIfNotExist(MAPS_APP_NAME);
435         folderIcon = mapIcon.dragToIcon(folderIcon);
436         folder = folderIcon.open();
437         folder.getAppIcon(MAPS_APP_NAME);
438         workspace = folder.close();
439 
440         workspace.verifyWorkspaceAppIconIsGone(MAPS_APP_NAME + " should be moved to a folder.",
441                 MAPS_APP_NAME);
442     }
443 
444     @Test
445     @PortraitLandscape
testPressBack()446     public void testPressBack() throws Exception {
447         mLauncher.getWorkspace().switchToAllApps();
448         mLauncher.pressBack();
449         mLauncher.getWorkspace();
450         waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
451 
452         startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
453         mLauncher.pressBack();
454         mLauncher.getWorkspace();
455         waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
456     }
457 
458     @Test
459     @PortraitLandscape
testDragAndCancelAppIcon()460     public void testDragAndCancelAppIcon() {
461         final HomeAppIcon homeAppIcon = createShortcutInCenterIfNotExist(GMAIL_APP_NAME);
462         Point positionBeforeDrag =
463                 mLauncher.getWorkspace().getWorkspaceIconsPositions().get(GMAIL_APP_NAME);
464         assertNotNull("App not found in Workspace before dragging.", positionBeforeDrag);
465 
466         mLauncher.getWorkspace().dragAndCancelAppIcon(homeAppIcon);
467 
468         Point positionAfterDrag =
469                 mLauncher.getWorkspace().getWorkspaceIconsPositions().get(GMAIL_APP_NAME);
470         assertNotNull("App not found in Workspace after dragging.", positionAfterDrag);
471         assertEquals("App not returned to same position in Workspace after drag & cancel",
472                 positionBeforeDrag, positionAfterDrag);
473     }
474 
475     @Test
476     @PortraitLandscape
testDeleteFromWorkspace()477     public void testDeleteFromWorkspace() throws Exception {
478         // test delete both built-in apps and user-installed app from workspace
479         for (String appName : new String[]{"Gmail", "Play Store", APP_NAME}) {
480             final HomeAppIcon homeAppIcon = createShortcutInCenterIfNotExist(appName);
481             Workspace workspace = mLauncher.getWorkspace().deleteAppIcon(homeAppIcon);
482             workspace.verifyWorkspaceAppIconIsGone(
483                     appName + " app was found after being deleted from workspace",
484                     appName);
485         }
486     }
487 
verifyAppUninstalledFromAllApps(Workspace workspace, String appName)488     private void verifyAppUninstalledFromAllApps(Workspace workspace, String appName) {
489         final HomeAllApps allApps = workspace.switchToAllApps();
490         allApps.freeze();
491         try {
492             assertNull(appName + " app was found on all apps after being uninstalled",
493                     allApps.tryGetAppIcon(appName));
494         } finally {
495             allApps.unfreeze();
496         }
497     }
498 
499     @Test
500     @PortraitLandscape
testUninstallFromWorkspace()501     public void testUninstallFromWorkspace() throws Exception {
502         installDummyAppAndWaitForUIUpdate();
503         try {
504             verifyAppUninstalledFromAllApps(
505                     createShortcutInCenterIfNotExist(DUMMY_APP_NAME).uninstall(), DUMMY_APP_NAME);
506         } finally {
507             TestUtil.uninstallDummyApp();
508         }
509     }
510 
511     @Test
512     @PortraitLandscape
testUninstallFromAllApps()513     public void testUninstallFromAllApps() throws Exception {
514         installDummyAppAndWaitForUIUpdate();
515         try {
516             Workspace workspace = mLauncher.getWorkspace();
517             final HomeAllApps allApps = workspace.switchToAllApps();
518             allApps.freeze();
519             try {
520                 workspace = allApps.getAppIcon(DUMMY_APP_NAME).uninstall();
521                 // After the toast clears, then the model tries to commit the uninstall transaction
522                 mLauncher.waitForModelQueueCleared();
523             } finally {
524                 allApps.unfreeze();
525             }
526             verifyAppUninstalledFromAllApps(workspace, DUMMY_APP_NAME);
527         } finally {
528             TestUtil.uninstallDummyApp();
529         }
530     }
531 
532     @Test
533     @PortraitLandscape
testDragAppIconToWorkspaceCell()534     public void testDragAppIconToWorkspaceCell() throws Exception {
535         long startTime, endTime, elapsedTime;
536         Point[] targets = getCornersAndCenterPositions();
537 
538         for (Point target : targets) {
539             startTime = SystemClock.uptimeMillis();
540             final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
541             allApps.freeze();
542             try {
543                 allApps.getAppIcon(APP_NAME).dragToWorkspace(target.x, target.y);
544             } finally {
545                 allApps.unfreeze();
546             }
547             // Reset the workspace for the next shortcut creation.
548             initialize(this);
549             endTime = SystemClock.uptimeMillis();
550             elapsedTime = endTime - startTime;
551             Log.d("testDragAppIconToWorkspaceCellTime",
552                     "Milliseconds taken to drag app icon to workspace cell: " + elapsedTime);
553         }
554 
555         // test to move a shortcut to other cell.
556         final HomeAppIcon launcherTestAppIcon = createShortcutInCenterIfNotExist(APP_NAME);
557         for (Point target : targets) {
558             startTime = SystemClock.uptimeMillis();
559             launcherTestAppIcon.dragToWorkspace(target.x, target.y);
560             endTime = SystemClock.uptimeMillis();
561             elapsedTime = endTime - startTime;
562             Log.d("testDragAppIconToWorkspaceCellTime",
563                     "Milliseconds taken to move shortcut to other cell: " + elapsedTime);
564         }
565     }
566 
567     @Test
getIconsPosition_afterIconRemoved_notContained()568     public void getIconsPosition_afterIconRemoved_notContained() throws IOException {
569         Point[] gridPositions = getCornersAndCenterPositions();
570         createShortcutIfNotExist(STORE_APP_NAME, gridPositions[0]);
571         createShortcutIfNotExist(MAPS_APP_NAME, gridPositions[1]);
572         installDummyAppAndWaitForUIUpdate();
573         try {
574             createShortcutIfNotExist(DUMMY_APP_NAME, gridPositions[2]);
575             Map<String, Point> initialPositions =
576                     mLauncher.getWorkspace().getWorkspaceIconsPositions();
577             assertThat(initialPositions.keySet())
578                     .containsAtLeast(DUMMY_APP_NAME, MAPS_APP_NAME, STORE_APP_NAME);
579 
580             mLauncher.getWorkspace().getWorkspaceAppIcon(DUMMY_APP_NAME).uninstall();
581             mLauncher.getWorkspace().verifyWorkspaceAppIconIsGone(
582                     DUMMY_APP_NAME + " was expected to disappear after uninstall.", DUMMY_APP_NAME);
583 
584             Map<String, Point> finalPositions =
585                     mLauncher.getWorkspace().getWorkspaceIconsPositions();
586             assertThat(finalPositions).doesNotContainKey(DUMMY_APP_NAME);
587         } finally {
588             TestUtil.uninstallDummyApp();
589         }
590     }
591 
592     @Test
593     @PortraitLandscape
testDragShortcutToWorkspaceCell()594     public void testDragShortcutToWorkspaceCell() throws Exception {
595         Point[] targets = getCornersAndCenterPositions();
596 
597         for (Point target : targets) {
598             final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
599             allApps.freeze();
600             try {
601                 allApps.getAppIcon(APP_NAME)
602                         .openDeepShortcutMenu()
603                         .getMenuItem(0)
604                         .dragToWorkspace(target.x, target.y);
605             } finally {
606                 allApps.unfreeze();
607             }
608         }
609     }
610 
611     @Test
612     @PortraitLandscape
testAddDeleteShortcutOnHotseat()613     public void testAddDeleteShortcutOnHotseat() {
614         mLauncher.getWorkspace()
615                 .deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
616                 .switchToAllApps()
617                 .getAppIcon(APP_NAME)
618                 .dragToHotseat(0);
619         mLauncher.getWorkspace().deleteAppIcon(
620                 mLauncher.getWorkspace().getHotseatAppIcon(APP_NAME));
621     }
622 
installDummyAppAndWaitForUIUpdate()623     private void installDummyAppAndWaitForUIUpdate() throws IOException {
624         TestUtil.installDummyApp();
625         // Wait for model thread completion as it may be processing
626         // the install event from the SystemService
627         mLauncher.waitForModelQueueCleared();
628         // Wait for Launcher UI thread completion, as it may be processing updating the UI in
629         // response to the model update. Not that `waitForLauncherInitialized` is just a proxy
630         // method, we can use any method which touches Launcher UI thread,
631         mLauncher.waitForLauncherInitialized();
632     }
633 
634     /**
635      * @return List of workspace grid coordinates. Those are not pixels. See {@link
636      * Workspace#getIconGridDimensions()}
637      */
getCornersAndCenterPositions()638     private Point[] getCornersAndCenterPositions() {
639         final Point dimensions = mLauncher.getWorkspace().getIconGridDimensions();
640         return new Point[]{
641                 new Point(0, 1),
642                 new Point(0, dimensions.y - 2),
643                 new Point(dimensions.x - 1, 1),
644                 new Point(dimensions.x - 1, dimensions.y - 2),
645                 new Point(dimensions.x / 2, dimensions.y / 2)
646         };
647     }
648 
getAppPackageName()649     public static String getAppPackageName() {
650         return getInstrumentation().getContext().getPackageName();
651     }
652 
653     @Test
testGetAppIconName()654     public void testGetAppIconName() {
655         HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
656         allApps.freeze();
657         try {
658             HomeAppIcon icon = allApps.getAppIcon(APP_NAME);
659             assertEquals("Wrong app icon name.", icon.getIconName(), APP_NAME);
660         } finally {
661             allApps.unfreeze();
662         }
663     }
664 }
665