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