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 25 import android.content.Intent; 26 27 import androidx.test.filters.LargeTest; 28 import androidx.test.runner.AndroidJUnit4; 29 import androidx.test.uiautomator.By; 30 import androidx.test.uiautomator.Until; 31 32 import com.android.launcher3.Launcher; 33 import com.android.launcher3.LauncherState; 34 import com.android.launcher3.tapl.AllApps; 35 import com.android.launcher3.tapl.Background; 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.tapl.TestHelpers; 41 import com.android.launcher3.ui.TaplTestsLauncher3; 42 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; 43 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch; 44 import com.android.quickstep.views.RecentsView; 45 46 import org.junit.After; 47 import org.junit.Before; 48 import org.junit.Ignore; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 52 @LargeTest 53 @RunWith(AndroidJUnit4.class) 54 public class TaplTestsQuickstep extends AbstractQuickStepTest { 55 56 private static final String APP_NAME = "LauncherTestApp"; 57 58 @Before setUp()59 public void setUp() throws Exception { 60 super.setUp(); 61 TaplTestsLauncher3.initialize(this); 62 executeOnLauncher(launcher -> { 63 RecentsView recentsView = launcher.getOverviewPanel(); 64 recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(true); 65 }); 66 } 67 68 @After tearDown()69 public void tearDown() { 70 executeOnLauncher(launcher -> { 71 RecentsView recentsView = launcher.getOverviewPanel(); 72 recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(false); 73 }); 74 } 75 startTestApps()76 public static void startTestApps() throws Exception { 77 startAppFast(getAppPackageName()); 78 startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); 79 startTestActivity(2); 80 } 81 startTestAppsWithCheck()82 private void startTestAppsWithCheck() throws Exception { 83 startTestApps(); 84 executeOnLauncher(launcher -> assertTrue( 85 "Launcher activity is the top activity; expecting another activity to be the top " 86 + "one", 87 isInBackground(launcher))); 88 } 89 90 @Test 91 @NavigationModeSwitch 92 @PortraitLandscape testWorkspaceSwitchToAllApps()93 public void testWorkspaceSwitchToAllApps() { 94 assertNotNull("switchToAllApps() returned null", 95 mLauncher.getWorkspace().switchToAllApps()); 96 assertTrue("Launcher internal state is not All Apps", 97 isInState(() -> LauncherState.ALL_APPS)); 98 } 99 100 @Test 101 @PortraitLandscape testOverview()102 public void testOverview() throws Exception { 103 startTestAppsWithCheck(); 104 // mLauncher.pressHome() also tests an important case of pressing home while in background. 105 Overview overview = mLauncher.pressHome().switchToOverview(); 106 assertTrue("Launcher internal state didn't switch to Overview", 107 isInState(() -> LauncherState.OVERVIEW)); 108 executeOnLauncher( 109 launcher -> assertTrue("Don't have at least 3 tasks", getTaskCount(launcher) >= 3)); 110 111 // Test flinging forward and backward. 112 executeOnLauncher(launcher -> assertEquals("Current task in Overview is not 0", 113 0, getCurrentOverviewPage(launcher))); 114 115 overview.flingForward(); 116 assertTrue("Launcher internal state is not Overview", 117 isInState(() -> LauncherState.OVERVIEW)); 118 final Integer currentTaskAfterFlingForward = getFromLauncher( 119 launcher -> getCurrentOverviewPage(launcher)); 120 executeOnLauncher(launcher -> assertTrue("Current task in Overview is still 0", 121 currentTaskAfterFlingForward > 0)); 122 123 overview.flingBackward(); 124 assertTrue("Launcher internal state is not Overview", 125 isInState(() -> LauncherState.OVERVIEW)); 126 executeOnLauncher(launcher -> assertTrue("Flinging back in Overview did nothing", 127 getCurrentOverviewPage(launcher) < currentTaskAfterFlingForward)); 128 129 // Test opening a task. 130 OverviewTask task = mLauncher.pressHome().switchToOverview().getCurrentTask(); 131 assertNotNull("overview.getCurrentTask() returned null (1)", task); 132 assertNotNull("OverviewTask.open returned null", task.open()); 133 assertTrue("Test activity didn't open from Overview", mDevice.wait(Until.hasObject( 134 By.pkg(getAppPackageName()).text("TestActivity2")), 135 DEFAULT_UI_TIMEOUT)); 136 executeOnLauncher(launcher -> assertTrue( 137 "Launcher activity is the top activity; expecting another activity to be the top " 138 + "one", 139 isInBackground(launcher))); 140 141 // Test dismissing a task. 142 overview = mLauncher.pressHome().switchToOverview(); 143 assertTrue("Launcher internal state didn't switch to Overview", 144 isInState(() -> LauncherState.OVERVIEW)); 145 final Integer numTasks = getFromLauncher(launcher -> getTaskCount(launcher)); 146 task = overview.getCurrentTask(); 147 assertNotNull("overview.getCurrentTask() returned null (2)", task); 148 task.dismiss(); 149 executeOnLauncher( 150 launcher -> assertEquals("Dismissing a task didn't remove 1 task from Overview", 151 numTasks - 1, getTaskCount(launcher))); 152 153 // Test dismissing all tasks. 154 mLauncher.pressHome().switchToOverview().dismissAllTasks(); 155 assertTrue("Launcher internal state is not Home", 156 isInState(() -> LauncherState.NORMAL)); 157 executeOnLauncher( 158 launcher -> assertEquals("Still have tasks after dismissing all", 159 0, getTaskCount(launcher))); 160 } 161 162 /** 163 * Smoke test for action buttons: Presses all the buttons and makes sure no crashes occur. 164 */ 165 @Test 166 @NavigationModeSwitch 167 @PortraitLandscape 168 @ScreenRecord // b/195673272 testOverviewActions()169 public void testOverviewActions() throws Exception { 170 // Experimenting for b/165029151: 171 final Overview overview = mLauncher.pressHome().switchToOverview(); 172 if (overview.hasTasks()) overview.dismissAllTasks(); 173 mLauncher.pressHome(); 174 // 175 176 startTestAppsWithCheck(); 177 OverviewActions actionsView = 178 mLauncher.pressHome().switchToOverview().getOverviewActions(); 179 actionsView.clickAndDismissScreenshot(); 180 } 181 getCurrentOverviewPage(Launcher launcher)182 private int getCurrentOverviewPage(Launcher launcher) { 183 return launcher.<RecentsView>getOverviewPanel().getCurrentPage(); 184 } 185 getTaskCount(Launcher launcher)186 private int getTaskCount(Launcher launcher) { 187 return launcher.<RecentsView>getOverviewPanel().getTaskViewCount(); 188 } 189 getTopRowTaskCountForTablet(Launcher launcher)190 private int getTopRowTaskCountForTablet(Launcher launcher) { 191 return launcher.<RecentsView>getOverviewPanel().getTopRowTaskCountForTablet(); 192 } 193 getBottomRowTaskCountForTablet(Launcher launcher)194 private int getBottomRowTaskCountForTablet(Launcher launcher) { 195 return launcher.<RecentsView>getOverviewPanel().getBottomRowTaskCountForTablet(); 196 } 197 198 @Test 199 @NavigationModeSwitch 200 @PortraitLandscape testSwitchToOverview()201 public void testSwitchToOverview() throws Exception { 202 assertNotNull("Workspace.switchToOverview() returned null", 203 mLauncher.pressHome().switchToOverview()); 204 assertTrue("Launcher internal state didn't switch to Overview", 205 isInState(() -> LauncherState.OVERVIEW)); 206 } 207 208 @Test 209 @NavigationModeSwitch 210 @PortraitLandscape testBackground()211 public void testBackground() throws Exception { 212 startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); 213 final Background background = getAndAssertBackground(); 214 215 assertNotNull("Background.switchToOverview() returned null", background.switchToOverview()); 216 assertTrue("Launcher internal state didn't switch to Overview", 217 isInState(() -> LauncherState.OVERVIEW)); 218 } 219 getAndAssertBackground()220 private Background getAndAssertBackground() { 221 final Background background = mLauncher.getBackground(); 222 assertNotNull("Launcher.getBackground() returned null", background); 223 executeOnLauncher(launcher -> assertTrue( 224 "Launcher activity is the top activity; expecting another activity to be the top " 225 + "one", 226 isInBackground(launcher))); 227 return background; 228 } 229 230 @Test 231 @PortraitLandscape testAllAppsFromHome()232 public void testAllAppsFromHome() throws Exception { 233 // Test opening all apps 234 assertNotNull("switchToAllApps() returned null", 235 mLauncher.getWorkspace().switchToAllApps()); 236 237 TaplTestsLauncher3.runAllAppsTest(this, mLauncher.getAllApps()); 238 239 // Testing pressHome. 240 assertTrue("Launcher internal state is not All Apps", 241 isInState(() -> LauncherState.ALL_APPS)); 242 assertNotNull("pressHome returned null", mLauncher.pressHome()); 243 assertTrue("Launcher internal state is not Home", 244 isInState(() -> LauncherState.NORMAL)); 245 assertNotNull("getHome returned null", mLauncher.getWorkspace()); 246 } 247 248 @Test 249 @NavigationModeSwitch 250 @PortraitLandscape testQuickSwitchFromApp()251 public void testQuickSwitchFromApp() throws Exception { 252 startTestActivity(2); 253 startTestActivity(3); 254 startTestActivity(4); 255 256 Background background = getAndAssertBackground(); 257 background.quickSwitchToPreviousApp(); 258 assertTrue("The first app we should have quick switched to is not running", 259 isTestActivityRunning(3)); 260 261 background = getAndAssertBackground(); 262 background.quickSwitchToPreviousApp(); 263 if (mLauncher.getNavigationModel() == NavigationModel.THREE_BUTTON) { 264 // 3-button mode toggles between 2 apps, rather than going back further. 265 assertTrue("Second quick switch should have returned to the first app.", 266 isTestActivityRunning(4)); 267 } else { 268 assertTrue("The second app we should have quick switched to is not running", 269 isTestActivityRunning(2)); 270 } 271 background = getAndAssertBackground(); 272 background.quickSwitchToPreviousAppSwipeLeft(); 273 assertTrue("The 2nd app we should have quick switched to is not running", 274 isTestActivityRunning(3)); 275 276 background = getAndAssertBackground(); 277 background.switchToOverview(); 278 } 279 isTestActivityRunning(int activityNumber)280 private boolean isTestActivityRunning(int activityNumber) { 281 return mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()) 282 .text("TestActivity" + activityNumber)), 283 DEFAULT_UI_TIMEOUT); 284 } 285 286 @Test 287 @NavigationModeSwitch 288 @PortraitLandscape testQuickSwitchFromHome()289 public void testQuickSwitchFromHome() throws Exception { 290 startTestActivity(2); 291 mLauncher.pressHome().quickSwitchToPreviousApp(); 292 assertTrue("The most recent task is not running after quick switching from home", 293 isTestActivityRunning(2)); 294 getAndAssertBackground(); 295 } 296 297 // TODO(b/204830798): test with all navigation modes(add @NavigationModeSwitch annotation) 298 // after the bug resolved. 299 @Ignore("b/205027405") 300 @Test 301 @PortraitLandscape 302 @ScreenRecord testPressBack()303 public void testPressBack() throws Exception { 304 mLauncher.getWorkspace().switchToAllApps(); 305 mLauncher.pressBack(); 306 mLauncher.getWorkspace(); 307 waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL); 308 309 AllApps allApps = mLauncher.getWorkspace().switchToAllApps(); 310 allApps.freeze(); 311 try { 312 allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false); 313 } finally { 314 allApps.unfreeze(); 315 } 316 mLauncher.getWorkspace().getWorkspaceAppIcon(APP_NAME).launch(getAppPackageName()); 317 mLauncher.pressBack(); 318 mLauncher.getWorkspace(); 319 waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL); 320 } 321 322 @Test 323 @PortraitLandscape testOverviewForTablet()324 public void testOverviewForTablet() throws Exception { 325 // TODO(b/210158657): Re-enable for OOP 326 if (!mLauncher.isTablet() || !TestHelpers.isInLauncherProcess()) { 327 return; 328 } 329 for (int i = 2; i <= 14; i++) { 330 startTestActivity(i); 331 } 332 333 Overview overview = mLauncher.pressHome().switchToOverview(); 334 executeOnLauncher( 335 launcher -> assertTrue("Don't have at least 13 tasks", 336 getTaskCount(launcher) >= 13)); 337 338 // Test scroll the first task off screen 339 overview.scrollCurrentTaskOffScreen(); 340 assertTrue("Launcher internal state is not Overview", 341 isInState(() -> LauncherState.OVERVIEW)); 342 executeOnLauncher(launcher -> assertTrue("Current task in Overview is still 0", 343 getCurrentOverviewPage(launcher) > 0)); 344 345 // Test opening the task. 346 overview.getCurrentTask().open(); 347 assertTrue("Test activity didn't open from Overview", 348 mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity8")), 349 DEFAULT_UI_TIMEOUT)); 350 351 // Scroll the task offscreen as it is now first 352 overview = mLauncher.pressHome().switchToOverview(); 353 overview.scrollCurrentTaskOffScreen(); 354 assertTrue("Launcher internal state is not Overview", 355 isInState(() -> LauncherState.OVERVIEW)); 356 executeOnLauncher(launcher -> assertTrue("Current task in Overview is still 0", 357 getCurrentOverviewPage(launcher) > 0)); 358 359 // Test dismissing the later task. 360 final Integer numTasks = getFromLauncher(this::getTaskCount); 361 overview.getCurrentTask().dismiss(); 362 executeOnLauncher( 363 launcher -> assertEquals("Dismissing a task didn't remove 1 task from Overview", 364 numTasks - 1, getTaskCount(launcher))); 365 executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after dismissal", 366 (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet( 367 launcher)) <= 1))); 368 369 // Test dismissing more tasks. 370 assertTrue("Launcher internal state didn't remain in Overview", 371 isInState(() -> LauncherState.OVERVIEW)); 372 overview.getCurrentTask().dismiss(); 373 assertTrue("Launcher internal state didn't remain in Overview", 374 isInState(() -> LauncherState.OVERVIEW)); 375 overview.getCurrentTask().dismiss(); 376 executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals", 377 (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet( 378 launcher)) <= 1))); 379 380 // Test dismissing all tasks. 381 mLauncher.pressHome().switchToOverview().dismissAllTasks(); 382 assertTrue("Launcher internal state is not Home", 383 isInState(() -> LauncherState.NORMAL)); 384 executeOnLauncher( 385 launcher -> assertEquals("Still have tasks after dismissing all", 386 0, getTaskCount(launcher))); 387 } 388 } 389