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