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.quickstep; 18 19 import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assume.assumeTrue; 25 26 import android.content.Intent; 27 28 import androidx.test.filters.LargeTest; 29 import androidx.test.runner.AndroidJUnit4; 30 import androidx.test.uiautomator.By; 31 import androidx.test.uiautomator.Until; 32 33 import com.android.launcher3.Launcher; 34 import com.android.launcher3.LauncherState; 35 import com.android.launcher3.tapl.LaunchedAppState; 36 import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel; 37 import com.android.launcher3.tapl.Overview; 38 import com.android.launcher3.tapl.OverviewActions; 39 import com.android.launcher3.tapl.OverviewTask; 40 import com.android.launcher3.ui.TaplTestsLauncher3; 41 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; 42 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch; 43 import com.android.quickstep.views.RecentsView; 44 45 import org.junit.After; 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 TaplTestsQuickstep extends AbstractQuickStepTest { 54 55 private static final String APP_NAME = "LauncherTestApp"; 56 private static final String CALCULATOR_APP_PACKAGE = 57 resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR); 58 59 @Before setUp()60 public void setUp() throws Exception { 61 super.setUp(); 62 TaplTestsLauncher3.initialize(this); 63 executeOnLauncher(launcher -> { 64 RecentsView recentsView = launcher.getOverviewPanel(); 65 recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(true); 66 }); 67 } 68 69 @After tearDown()70 public void tearDown() { 71 executeOnLauncher(launcher -> { 72 RecentsView recentsView = launcher.getOverviewPanel(); 73 recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(false); 74 }); 75 } 76 startTestApps()77 public static void startTestApps() throws Exception { 78 startAppFast(getAppPackageName()); 79 startAppFast(CALCULATOR_APP_PACKAGE); 80 startTestActivity(2); 81 } 82 startTestAppsWithCheck()83 private void startTestAppsWithCheck() throws Exception { 84 startTestApps(); 85 executeOnLauncher(launcher -> assertTrue( 86 "Launcher activity is the top activity; expecting another activity to be the top " 87 + "one", 88 isInLaunchedApp(launcher))); 89 } 90 91 @Test 92 @NavigationModeSwitch 93 @PortraitLandscape testWorkspaceSwitchToAllApps()94 public void testWorkspaceSwitchToAllApps() { 95 assertNotNull("switchToAllApps() returned null", 96 mLauncher.getWorkspace().switchToAllApps()); 97 assertTrue("Launcher internal state is not All Apps", 98 isInState(() -> LauncherState.ALL_APPS)); 99 } 100 101 @Test 102 @PortraitLandscape testOverview()103 public void testOverview() throws Exception { 104 startTestAppsWithCheck(); 105 // mLauncher.pressHome() also tests an important case of pressing home while in background. 106 Overview overview = mLauncher.goHome().switchToOverview(); 107 assertTrue("Launcher internal state didn't switch to Overview", 108 isInState(() -> LauncherState.OVERVIEW)); 109 executeOnLauncher( 110 launcher -> assertTrue("Don't have at least 3 tasks", getTaskCount(launcher) >= 3)); 111 112 // Test flinging forward and backward. 113 executeOnLauncher(launcher -> assertEquals("Current task in Overview is not 0", 114 0, getCurrentOverviewPage(launcher))); 115 116 overview.flingForward(); 117 assertTrue("Launcher internal state is not Overview", 118 isInState(() -> LauncherState.OVERVIEW)); 119 final Integer currentTaskAfterFlingForward = getFromLauncher( 120 launcher -> getCurrentOverviewPage(launcher)); 121 executeOnLauncher(launcher -> assertTrue("Current task in Overview is still 0", 122 currentTaskAfterFlingForward > 0)); 123 124 overview.flingBackward(); 125 assertTrue("Launcher internal state is not Overview", 126 isInState(() -> LauncherState.OVERVIEW)); 127 executeOnLauncher(launcher -> assertTrue("Flinging back in Overview did nothing", 128 getCurrentOverviewPage(launcher) < currentTaskAfterFlingForward)); 129 130 // Test opening a task. 131 OverviewTask task = mLauncher.goHome().switchToOverview().getCurrentTask(); 132 assertNotNull("overview.getCurrentTask() returned null (1)", task); 133 assertNotNull("OverviewTask.open returned null", task.open()); 134 assertTrue("Test activity didn't open from Overview", mDevice.wait(Until.hasObject( 135 By.pkg(getAppPackageName()).text("TestActivity2")), 136 DEFAULT_UI_TIMEOUT)); 137 executeOnLauncher(launcher -> assertTrue( 138 "Launcher activity is the top activity; expecting another activity to be the top " 139 + "one", 140 isInLaunchedApp(launcher))); 141 142 // Test dismissing a task. 143 overview = mLauncher.goHome().switchToOverview(); 144 assertTrue("Launcher internal state didn't switch to Overview", 145 isInState(() -> LauncherState.OVERVIEW)); 146 final Integer numTasks = getFromLauncher(launcher -> getTaskCount(launcher)); 147 task = overview.getCurrentTask(); 148 assertNotNull("overview.getCurrentTask() returned null (2)", task); 149 task.dismiss(); 150 executeOnLauncher( 151 launcher -> assertEquals("Dismissing a task didn't remove 1 task from Overview", 152 numTasks - 1, getTaskCount(launcher))); 153 154 // Test dismissing all tasks. 155 mLauncher.goHome().switchToOverview().dismissAllTasks(); 156 assertTrue("Launcher internal state is not Home", 157 isInState(() -> LauncherState.NORMAL)); 158 executeOnLauncher( 159 launcher -> assertEquals("Still have tasks after dismissing all", 160 0, getTaskCount(launcher))); 161 } 162 163 /** 164 * Smoke test for action buttons: Presses all the buttons and makes sure no crashes occur. 165 */ 166 @Test 167 @NavigationModeSwitch 168 @PortraitLandscape 169 @ScreenRecord // b/195673272 testOverviewActions()170 public void testOverviewActions() throws Exception { 171 // Experimenting for b/165029151: 172 final Overview overview = mLauncher.goHome().switchToOverview(); 173 if (overview.hasTasks()) overview.dismissAllTasks(); 174 mLauncher.goHome(); 175 // 176 177 startTestAppsWithCheck(); 178 OverviewActions actionsView = 179 mLauncher.goHome().switchToOverview().getOverviewActions(); 180 actionsView.clickAndDismissScreenshot(); 181 } 182 183 @Test 184 @PortraitLandscape testSplitFromOverview()185 public void testSplitFromOverview() { 186 assumeTrue(!mLauncher.isTablet()); 187 188 startTestActivity(2); 189 startTestActivity(3); 190 191 mLauncher.goHome().switchToOverview().getCurrentTask() 192 .tapMenu() 193 .tapSplitMenuItem() 194 .getCurrentTask() 195 .open(); 196 } 197 198 @Test 199 @PortraitLandscape testSplitFromOverviewForTablet()200 public void testSplitFromOverviewForTablet() { 201 assumeTrue(mLauncher.isTablet()); 202 203 startTestActivity(2); 204 startTestActivity(3); 205 206 mLauncher.goHome().switchToOverview().getOverviewActions() 207 .clickSplit() 208 .getTestActivityTask(2) 209 .open(); 210 } 211 getCurrentOverviewPage(Launcher launcher)212 private int getCurrentOverviewPage(Launcher launcher) { 213 return launcher.<RecentsView>getOverviewPanel().getCurrentPage(); 214 } 215 getTaskCount(Launcher launcher)216 private int getTaskCount(Launcher launcher) { 217 return launcher.<RecentsView>getOverviewPanel().getTaskViewCount(); 218 } 219 getTopRowTaskCountForTablet(Launcher launcher)220 private int getTopRowTaskCountForTablet(Launcher launcher) { 221 return launcher.<RecentsView>getOverviewPanel().getTopRowTaskCountForTablet(); 222 } 223 getBottomRowTaskCountForTablet(Launcher launcher)224 private int getBottomRowTaskCountForTablet(Launcher launcher) { 225 return launcher.<RecentsView>getOverviewPanel().getBottomRowTaskCountForTablet(); 226 } 227 228 @Ignore 229 @Test 230 @NavigationModeSwitch 231 @PortraitLandscape 232 @ScreenRecord // b/238461765 testSwitchToOverview()233 public void testSwitchToOverview() throws Exception { 234 startTestAppsWithCheck(); 235 assertNotNull("Workspace.switchToOverview() returned null", 236 mLauncher.goHome().switchToOverview()); 237 assertTrue("Launcher internal state didn't switch to Overview", 238 isInState(() -> LauncherState.OVERVIEW)); 239 } 240 241 @Ignore 242 @Test 243 @NavigationModeSwitch 244 @PortraitLandscape testBackground()245 public void testBackground() throws Exception { 246 startAppFast(CALCULATOR_APP_PACKAGE); 247 final LaunchedAppState launchedAppState = getAndAssertLaunchedApp(); 248 249 assertNotNull("Background.switchToOverview() returned null", 250 launchedAppState.switchToOverview()); 251 assertTrue("Launcher internal state didn't switch to Overview", 252 isInState(() -> LauncherState.OVERVIEW)); 253 } 254 getAndAssertLaunchedApp()255 private LaunchedAppState getAndAssertLaunchedApp() { 256 final LaunchedAppState launchedAppState = mLauncher.getLaunchedAppState(); 257 assertNotNull("Launcher.getLaunchedApp() returned null", launchedAppState); 258 executeOnLauncher(launcher -> assertTrue( 259 "Launcher activity is the top activity; expecting another activity to be the top " 260 + "one", 261 isInLaunchedApp(launcher))); 262 return launchedAppState; 263 } 264 quickSwitchToPreviousAppAndAssert(boolean toRight)265 private void quickSwitchToPreviousAppAndAssert(boolean toRight) { 266 final LaunchedAppState launchedAppState = getAndAssertLaunchedApp(); 267 if (toRight) { 268 launchedAppState.quickSwitchToPreviousApp(); 269 } else { 270 launchedAppState.quickSwitchToPreviousAppSwipeLeft(); 271 } 272 273 // While enable shell transition, Launcher can be resumed due to transient launch. 274 waitForLauncherCondition("Launcher shouldn't stay in resume forever", 275 this::isInLaunchedApp, 3000 /* timeout */); 276 } 277 278 @Test 279 @PortraitLandscape testAllAppsFromHome()280 public void testAllAppsFromHome() throws Exception { 281 // Test opening all apps 282 assertNotNull("switchToAllApps() returned null", 283 mLauncher.getWorkspace().switchToAllApps()); 284 285 TaplTestsLauncher3.runAllAppsTest(this, mLauncher.getAllApps()); 286 287 // Testing pressHome. 288 assertTrue("Launcher internal state is not All Apps", 289 isInState(() -> LauncherState.ALL_APPS)); 290 assertNotNull("pressHome returned null", mLauncher.goHome()); 291 assertTrue("Launcher internal state is not Home", 292 isInState(() -> LauncherState.NORMAL)); 293 assertNotNull("getHome returned null", mLauncher.getWorkspace()); 294 } 295 296 @Test 297 @NavigationModeSwitch 298 @PortraitLandscape testQuickSwitchFromApp()299 public void testQuickSwitchFromApp() throws Exception { 300 startTestActivity(2); 301 startTestActivity(3); 302 startTestActivity(4); 303 304 quickSwitchToPreviousAppAndAssert(true /* toRight */); 305 assertTrue("The first app we should have quick switched to is not running", 306 isTestActivityRunning(3)); 307 308 quickSwitchToPreviousAppAndAssert(true /* toRight */); 309 if (mLauncher.getNavigationModel() == NavigationModel.THREE_BUTTON) { 310 // 3-button mode toggles between 2 apps, rather than going back further. 311 assertTrue("Second quick switch should have returned to the first app.", 312 isTestActivityRunning(4)); 313 } else { 314 assertTrue("The second app we should have quick switched to is not running", 315 isTestActivityRunning(2)); 316 } 317 318 quickSwitchToPreviousAppAndAssert(false /* toRight */); 319 assertTrue("The 2nd app we should have quick switched to is not running", 320 isTestActivityRunning(3)); 321 322 final LaunchedAppState launchedAppState = getAndAssertLaunchedApp(); 323 launchedAppState.switchToOverview(); 324 } 325 326 @Test 327 @ScreenRecord // b/242163205 testQuickSwitchToPreviousAppForTablet()328 public void testQuickSwitchToPreviousAppForTablet() throws Exception { 329 assumeTrue(mLauncher.isTablet()); 330 startTestActivity(2); 331 startImeTestActivity(); 332 333 // Set ignoreTaskbarVisibility to true to verify the task bar visibility explicitly. 334 mLauncher.setIgnoreTaskbarVisibility(true); 335 336 // Expect task bar invisible when the launched app was the IME activity. 337 LaunchedAppState launchedAppState = getAndAssertLaunchedApp(); 338 launchedAppState.assertTaskbarHidden(); 339 340 // Quick-switch to the test app with swiping to right. 341 quickSwitchToPreviousAppAndAssert(true /* toRight */); 342 343 assertTrue("The first app we should have quick switched to is not running", 344 isTestActivityRunning(2)); 345 // Expect task bar visible when the launched app was the test activity. 346 launchedAppState = getAndAssertLaunchedApp(); 347 launchedAppState.assertTaskbarVisible(); 348 } 349 isTestActivityRunning(int activityNumber)350 private boolean isTestActivityRunning(int activityNumber) { 351 return mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()) 352 .text("TestActivity" + activityNumber)), 353 DEFAULT_UI_TIMEOUT); 354 } 355 356 @Test 357 @NavigationModeSwitch 358 @PortraitLandscape testQuickSwitchFromHome()359 public void testQuickSwitchFromHome() throws Exception { 360 startTestActivity(2); 361 mLauncher.goHome().quickSwitchToPreviousApp(); 362 assertTrue("The most recent task is not running after quick switching from home", 363 isTestActivityRunning(2)); 364 getAndAssertLaunchedApp(); 365 } 366 367 @Test 368 @PortraitLandscape 369 @NavigationModeSwitch testPressBack()370 public void testPressBack() throws Exception { 371 mLauncher.getWorkspace().switchToAllApps(); 372 mLauncher.pressBack(); 373 mLauncher.getWorkspace(); 374 waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL); 375 376 startAppFast(CALCULATOR_APP_PACKAGE); 377 mLauncher.pressBack(); 378 mLauncher.getWorkspace(); 379 waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL); 380 } 381 382 @Ignore 383 @Test 384 @PortraitLandscape testOverviewForTablet()385 public void testOverviewForTablet() throws Exception { 386 assumeTrue(mLauncher.isTablet()); 387 388 for (int i = 2; i <= 14; i++) { 389 startTestActivity(i); 390 } 391 392 Overview overview = mLauncher.goHome().switchToOverview(); 393 executeOnLauncher( 394 launcher -> assertTrue("Don't have at least 13 tasks", 395 getTaskCount(launcher) >= 13)); 396 397 // Test scroll the first task off screen 398 overview.scrollCurrentTaskOffScreen(); 399 assertTrue("Launcher internal state is not Overview", 400 isInState(() -> LauncherState.OVERVIEW)); 401 executeOnLauncher(launcher -> assertTrue("Current task in Overview is still 0", 402 getCurrentOverviewPage(launcher) > 0)); 403 404 // Test opening the task. 405 overview.getCurrentTask().open(); 406 assertTrue("Test activity didn't open from Overview", 407 mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity10")), 408 DEFAULT_UI_TIMEOUT)); 409 410 // Scroll the task offscreen as it is now first 411 overview = mLauncher.goHome().switchToOverview(); 412 overview.scrollCurrentTaskOffScreen(); 413 assertTrue("Launcher internal state is not Overview", 414 isInState(() -> LauncherState.OVERVIEW)); 415 executeOnLauncher(launcher -> assertTrue("Current task in Overview is still 0", 416 getCurrentOverviewPage(launcher) > 0)); 417 418 // Test dismissing the later task. 419 final Integer numTasks = getFromLauncher(this::getTaskCount); 420 overview.getCurrentTask().dismiss(); 421 executeOnLauncher( 422 launcher -> assertEquals("Dismissing a task didn't remove 1 task from Overview", 423 numTasks - 1, getTaskCount(launcher))); 424 executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after dismissal", 425 (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet( 426 launcher)) <= 1))); 427 428 // Test dismissing more tasks. 429 assertTrue("Launcher internal state didn't remain in Overview", 430 isInState(() -> LauncherState.OVERVIEW)); 431 overview.getCurrentTask().dismiss(); 432 assertTrue("Launcher internal state didn't remain in Overview", 433 isInState(() -> LauncherState.OVERVIEW)); 434 overview.getCurrentTask().dismiss(); 435 executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals", 436 (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet( 437 launcher)) <= 1))); 438 439 // Test dismissing all tasks. 440 mLauncher.goHome().switchToOverview().dismissAllTasks(); 441 assertTrue("Launcher internal state is not Home", 442 isInState(() -> LauncherState.NORMAL)); 443 executeOnLauncher( 444 launcher -> assertEquals("Still have tasks after dismissing all", 445 0, getTaskCount(launcher))); 446 } 447 } 448