1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.android.launcher3.ui; 17 18 import static androidx.test.InstrumentationRegistry.getInstrumentation; 19 20 import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING; 21 import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName; 22 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; 23 24 import static org.junit.Assert.assertEquals; 25 import static org.junit.Assert.assertTrue; 26 27 import android.content.BroadcastReceiver; 28 import android.content.ComponentName; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.content.pm.ActivityInfo; 33 import android.content.pm.LauncherActivityInfo; 34 import android.content.pm.LauncherApps; 35 import android.content.pm.PackageInfo; 36 import android.content.pm.PackageManager; 37 import android.graphics.Point; 38 import android.os.Debug; 39 import android.os.Process; 40 import android.os.RemoteException; 41 import android.os.UserHandle; 42 import android.os.UserManager; 43 import android.system.OsConstants; 44 import android.util.Log; 45 46 import androidx.test.InstrumentationRegistry; 47 import androidx.test.uiautomator.By; 48 import androidx.test.uiautomator.BySelector; 49 import androidx.test.uiautomator.UiDevice; 50 import androidx.test.uiautomator.Until; 51 52 import com.android.launcher3.Launcher; 53 import com.android.launcher3.LauncherState; 54 import com.android.launcher3.Utilities; 55 import com.android.launcher3.statemanager.StateManager; 56 import com.android.launcher3.tapl.HomeAllApps; 57 import com.android.launcher3.tapl.HomeAppIcon; 58 import com.android.launcher3.tapl.LauncherInstrumentation; 59 import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType; 60 import com.android.launcher3.tapl.TestHelpers; 61 import com.android.launcher3.testcomponent.TestCommandReceiver; 62 import com.android.launcher3.testing.shared.TestProtocol; 63 import com.android.launcher3.util.LooperExecutor; 64 import com.android.launcher3.util.SimpleBroadcastReceiver; 65 import com.android.launcher3.util.TestUtil; 66 import com.android.launcher3.util.Wait; 67 import com.android.launcher3.util.rule.FailureWatcher; 68 import com.android.launcher3.util.rule.SamplerRule; 69 import com.android.launcher3.util.rule.ScreenRecordRule; 70 import com.android.launcher3.util.rule.ShellCommandRule; 71 import com.android.launcher3.util.rule.TestStabilityRule; 72 import com.android.launcher3.util.rule.ViewCaptureRule; 73 74 import org.junit.After; 75 import org.junit.Assert; 76 import org.junit.Before; 77 import org.junit.Rule; 78 import org.junit.rules.RuleChain; 79 import org.junit.rules.TestRule; 80 81 import java.io.IOException; 82 import java.util.concurrent.Callable; 83 import java.util.concurrent.CountDownLatch; 84 import java.util.concurrent.TimeUnit; 85 import java.util.concurrent.TimeoutException; 86 import java.util.function.Consumer; 87 import java.util.function.Function; 88 import java.util.function.Supplier; 89 90 /** 91 * Base class for all instrumentation tests providing various utility methods. 92 */ 93 public abstract class AbstractLauncherUiTest { 94 95 public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10); 96 public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5; 97 98 public static final long DEFAULT_UI_TIMEOUT = TestUtil.DEFAULT_UI_TIMEOUT; 99 private static final String TAG = "AbstractLauncherUiTest"; 100 101 private static boolean sDumpWasGenerated = false; 102 private static boolean sActivityLeakReported = false; 103 private static boolean sSeenKeyguard = false; 104 105 private static final String SYSTEMUI_PACKAGE = "com.android.systemui"; 106 107 protected LooperExecutor mMainThreadExecutor = MAIN_EXECUTOR; 108 protected final UiDevice mDevice = UiDevice.getInstance(getInstrumentation()); 109 protected final LauncherInstrumentation mLauncher = new LauncherInstrumentation(); 110 protected Context mTargetContext; 111 protected String mTargetPackage; 112 private int mLauncherPid; 113 checkDetectedLeaks(LauncherInstrumentation launcher)114 public static void checkDetectedLeaks(LauncherInstrumentation launcher) { 115 if (sActivityLeakReported) return; 116 117 // Check whether activity leak detector has found leaked activities. 118 Wait.atMost(() -> getActivityLeakErrorMessage(launcher), 119 () -> { 120 launcher.forceGc(); 121 return MAIN_EXECUTOR.submit( 122 () -> launcher.noLeakedActivities()).get(); 123 }, DEFAULT_UI_TIMEOUT, launcher); 124 } 125 getActivityLeakErrorMessage(LauncherInstrumentation launcher)126 private static String getActivityLeakErrorMessage(LauncherInstrumentation launcher) { 127 sActivityLeakReported = true; 128 return "Activity leak detector has found leaked activities, " 129 + dumpHprofData(launcher, false) + "."; 130 } 131 dumpHprofData(LauncherInstrumentation launcher, boolean intentionalLeak)132 public static String dumpHprofData(LauncherInstrumentation launcher, boolean intentionalLeak) { 133 if (intentionalLeak) return "intentional leak; not generating dump"; 134 135 String result; 136 if (sDumpWasGenerated) { 137 result = "dump has already been generated by another test"; 138 } else { 139 try { 140 final String fileName = 141 getInstrumentation().getTargetContext().getFilesDir().getPath() 142 + "/ActivityLeakHeapDump.hprof"; 143 if (TestHelpers.isInLauncherProcess()) { 144 Debug.dumpHprofData(fileName); 145 } else { 146 final UiDevice device = UiDevice.getInstance(getInstrumentation()); 147 device.executeShellCommand( 148 "am dumpheap " + device.getLauncherPackageName() + " " + fileName); 149 } 150 Log.d(TAG, "Saved leak dump, the leak is still present: " 151 + !launcher.noLeakedActivities()); 152 sDumpWasGenerated = true; 153 result = "saved memory dump as an artifact"; 154 } catch (Throwable e) { 155 Log.e(TAG, "dumpHprofData failed", e); 156 result = "failed to save memory dump"; 157 } 158 } 159 return result + ". Full list of activities: " + launcher.getRootedActivitiesList(); 160 } 161 AbstractLauncherUiTest()162 protected AbstractLauncherUiTest() { 163 mLauncher.enableCheckEventsForSuccessfulGestures(); 164 try { 165 mDevice.setOrientationNatural(); 166 } catch (RemoteException e) { 167 throw new RuntimeException(e); 168 } 169 if (TestHelpers.isInLauncherProcess()) { 170 Utilities.enableRunningInTestHarnessForTests(); 171 mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand( 172 TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()). 173 getString("result")); 174 mLauncher.setOnSettledStateAction( 175 containerType -> executeOnLauncher( 176 launcher -> 177 checkLauncherIntegrity(launcher, containerType))); 178 } 179 mLauncher.enableDebugTracing(); 180 // Avoid double-reporting of Launcher crashes. 181 mLauncher.setOnLauncherCrashed(() -> mLauncherPid = 0); 182 } 183 184 @Rule 185 public ShellCommandRule mDisableHeadsUpNotification = 186 ShellCommandRule.disableHeadsUpNotification(); 187 188 @Rule 189 public ScreenRecordRule mScreenRecordRule = new ScreenRecordRule(); 190 clearPackageData(String pkg)191 protected void clearPackageData(String pkg) throws IOException, InterruptedException { 192 final CountDownLatch count = new CountDownLatch(2); 193 final SimpleBroadcastReceiver broadcastReceiver = 194 new SimpleBroadcastReceiver(i -> count.countDown()); 195 broadcastReceiver.registerPkgActions(mTargetContext, pkg, 196 Intent.ACTION_PACKAGE_RESTARTED, Intent.ACTION_PACKAGE_DATA_CLEARED); 197 198 mDevice.executeShellCommand("pm clear " + pkg); 199 assertTrue(pkg + " didn't restart", count.await(10, TimeUnit.SECONDS)); 200 mTargetContext.unregisterReceiver(broadcastReceiver); 201 } 202 getRulesInsideActivityMonitor()203 protected TestRule getRulesInsideActivityMonitor() { 204 final ViewCaptureRule viewCaptureRule = new ViewCaptureRule( 205 Launcher.ACTIVITY_TRACKER::getCreatedActivity); 206 final RuleChain inner = RuleChain 207 .outerRule(new PortraitLandscapeRunner(this)) 208 .around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData)) 209 .around(viewCaptureRule); 210 211 return TestHelpers.isInLauncherProcess() 212 ? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher()).around(inner) 213 : inner; 214 } 215 216 @Rule 217 public TestRule mOrderSensitiveRules = RuleChain 218 .outerRule(new SamplerRule()) 219 .around(new TestStabilityRule()) 220 .around(getRulesInsideActivityMonitor()); 221 getDevice()222 public UiDevice getDevice() { 223 return mDevice; 224 } 225 226 @Before setUp()227 public void setUp() throws Exception { 228 mLauncher.onTestStart(); 229 230 verifyKeyguardInvisible(); 231 232 final String launcherPackageName = mDevice.getLauncherPackageName(); 233 try { 234 final Context context = InstrumentationRegistry.getContext(); 235 final PackageManager pm = context.getPackageManager(); 236 final PackageInfo launcherPackage = pm.getPackageInfo(launcherPackageName, 0); 237 238 if (!launcherPackage.versionName.equals("BuildFromAndroidStudio")) { 239 Assert.assertEquals("Launcher version doesn't match tests version", 240 pm.getPackageInfo(context.getPackageName(), 0).getLongVersionCode(), 241 launcherPackage.getLongVersionCode()); 242 } 243 } catch (PackageManager.NameNotFoundException e) { 244 throw new RuntimeException(e); 245 } 246 247 mLauncherPid = 0; 248 249 mTargetContext = InstrumentationRegistry.getTargetContext(); 250 mTargetPackage = mTargetContext.getPackageName(); 251 mLauncherPid = mLauncher.getPid(); 252 253 UserManager userManager = mTargetContext.getSystemService(UserManager.class); 254 if (userManager != null) { 255 for (UserHandle userHandle : userManager.getUserProfiles()) { 256 if (!userHandle.isSystem()) { 257 mDevice.executeShellCommand("pm remove-user " + userHandle.getIdentifier()); 258 } 259 } 260 } 261 } 262 verifyKeyguardInvisible()263 private static void verifyKeyguardInvisible() { 264 final boolean keyguardAlreadyVisible = sSeenKeyguard; 265 266 sSeenKeyguard = sSeenKeyguard 267 || !TestHelpers.wait( 268 Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000); 269 270 Assert.assertFalse( 271 "Keyguard is visible, which is likely caused by a crash in SysUI, seeing keyguard" 272 + " for the first time = " 273 + !keyguardAlreadyVisible, 274 sSeenKeyguard); 275 } 276 277 @After verifyLauncherState()278 public void verifyLauncherState() { 279 try { 280 // Limits UI tests affecting tests running after them. 281 mLauncher.waitForLauncherInitialized(); 282 if (mLauncherPid != 0) { 283 assertEquals("Launcher crashed, pid mismatch:", 284 mLauncherPid, mLauncher.getPid().intValue()); 285 } 286 } finally { 287 mLauncher.onTestFinish(); 288 } 289 } 290 reinitializeLauncherData()291 protected void reinitializeLauncherData() { 292 reinitializeLauncherData(false); 293 } 294 reinitializeLauncherData(boolean clearWorkspace)295 protected void reinitializeLauncherData(boolean clearWorkspace) { 296 if (clearWorkspace) { 297 mLauncher.clearLauncherData(); 298 } else { 299 mLauncher.reinitializeLauncherData(); 300 } 301 mLauncher.waitForLauncherInitialized(); 302 } 303 304 /** 305 * Runs the callback on the UI thread and returns the result. 306 */ getOnUiThread(final Callable<T> callback)307 protected <T> T getOnUiThread(final Callable<T> callback) { 308 try { 309 return mMainThreadExecutor.submit(callback).get(DEFAULT_UI_TIMEOUT, 310 TimeUnit.MILLISECONDS); 311 } catch (TimeoutException e) { 312 Log.e(TAG, "Timeout in getOnUiThread, sending SIGABRT", e); 313 Process.sendSignal(Process.myPid(), OsConstants.SIGABRT); 314 throw new RuntimeException(e); 315 } catch (Throwable e) { 316 throw new RuntimeException(e); 317 } 318 } 319 getFromLauncher(Function<Launcher, T> f)320 protected <T> T getFromLauncher(Function<Launcher, T> f) { 321 if (!TestHelpers.isInLauncherProcess()) return null; 322 return getOnUiThread(() -> f.apply(Launcher.ACTIVITY_TRACKER.getCreatedActivity())); 323 } 324 executeOnLauncher(Consumer<Launcher> f)325 protected void executeOnLauncher(Consumer<Launcher> f) { 326 getFromLauncher(launcher -> { 327 f.accept(launcher); 328 return null; 329 }); 330 } 331 332 // Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call 333 // expecting the results of that gesture because the wait can hide flakeness. waitForState(String message, Supplier<LauncherState> state)334 protected void waitForState(String message, Supplier<LauncherState> state) { 335 waitForLauncherCondition(message, 336 launcher -> launcher.getStateManager().getCurrentStableState() == state.get()); 337 } 338 339 // Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call 340 // expecting the results of that gesture because the wait can hide flakeness. waitForStateTransitionToEnd(String message, Supplier<LauncherState> state)341 protected void waitForStateTransitionToEnd(String message, Supplier<LauncherState> state) { 342 waitForLauncherCondition(message, 343 launcher -> launcher.getStateManager().isInStableState(state.get()) 344 && !launcher.getStateManager().isInTransition()); 345 } 346 waitForResumed(String message)347 protected void waitForResumed(String message) { 348 waitForLauncherCondition(message, launcher -> launcher.hasBeenResumed()); 349 } 350 351 // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide 352 // flakiness. waitForLauncherCondition(String message, Function<Launcher, Boolean> condition)353 protected void waitForLauncherCondition(String 354 message, Function<Launcher, Boolean> condition) { 355 waitForLauncherCondition(message, condition, DEFAULT_ACTIVITY_TIMEOUT); 356 } 357 358 // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide 359 // flakiness. getOnceNotNull(String message, Function<Launcher, T> f)360 protected <T> T getOnceNotNull(String message, Function<Launcher, T> f) { 361 return getOnceNotNull(message, f, DEFAULT_ACTIVITY_TIMEOUT); 362 } 363 364 // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide 365 // flakiness. waitForLauncherCondition( String message, Function<Launcher, Boolean> condition, long timeout)366 protected void waitForLauncherCondition( 367 String message, Function<Launcher, Boolean> condition, long timeout) { 368 verifyKeyguardInvisible(); 369 if (!TestHelpers.isInLauncherProcess()) return; 370 Wait.atMost(message, () -> getFromLauncher(condition), timeout, mLauncher); 371 } 372 373 // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide 374 // flakiness. getOnceNotNull(String message, Function<Launcher, T> f, long timeout)375 protected <T> T getOnceNotNull(String message, Function<Launcher, T> f, long timeout) { 376 if (!TestHelpers.isInLauncherProcess()) return null; 377 378 final Object[] output = new Object[1]; 379 Wait.atMost(message, () -> { 380 final Object fromLauncher = getFromLauncher(f); 381 output[0] = fromLauncher; 382 return fromLauncher != null; 383 }, timeout, mLauncher); 384 return (T) output[0]; 385 } 386 387 // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide 388 // flakiness. waitForLauncherCondition( String message, Runnable testThreadAction, Function<Launcher, Boolean> condition, long timeout)389 protected void waitForLauncherCondition( 390 String message, 391 Runnable testThreadAction, Function<Launcher, Boolean> condition, 392 long timeout) { 393 if (!TestHelpers.isInLauncherProcess()) return; 394 Wait.atMost(message, () -> { 395 testThreadAction.run(); 396 return getFromLauncher(condition); 397 }, timeout, mLauncher); 398 } 399 getSettingsApp()400 protected LauncherActivityInfo getSettingsApp() { 401 return mTargetContext.getSystemService(LauncherApps.class) 402 .getActivityList("com.android.settings", Process.myUserHandle()).get(0); 403 } 404 405 /** 406 * Broadcast receiver which blocks until the result is received. 407 */ 408 public class BlockingBroadcastReceiver extends BroadcastReceiver { 409 410 private final CountDownLatch latch = new CountDownLatch(1); 411 private Intent mIntent; 412 BlockingBroadcastReceiver(String action)413 public BlockingBroadcastReceiver(String action) { 414 mTargetContext.registerReceiver(this, new IntentFilter(action), 415 Context.RECEIVER_EXPORTED/*UNAUDITED*/); 416 } 417 418 @Override onReceive(Context context, Intent intent)419 public void onReceive(Context context, Intent intent) { 420 mIntent = intent; 421 latch.countDown(); 422 } 423 blockingGetIntent()424 public Intent blockingGetIntent() throws InterruptedException { 425 latch.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS); 426 mTargetContext.unregisterReceiver(this); 427 return mIntent; 428 } 429 blockingGetExtraIntent()430 public Intent blockingGetExtraIntent() throws InterruptedException { 431 Intent intent = blockingGetIntent(); 432 return intent == null ? null : (Intent) intent.getParcelableExtra( 433 Intent.EXTRA_INTENT); 434 } 435 } 436 startAppFast(String packageName)437 public static void startAppFast(String packageName) { 438 startIntent( 439 getInstrumentation().getContext().getPackageManager().getLaunchIntentForPackage( 440 packageName), 441 By.pkg(packageName).depth(0), 442 true /* newTask */); 443 } 444 startTestActivity(int activityNumber)445 public static void startTestActivity(int activityNumber) { 446 final String packageName = getAppPackageName(); 447 final Intent intent = getInstrumentation().getContext().getPackageManager(). 448 getLaunchIntentForPackage(packageName); 449 intent.setComponent(new ComponentName(packageName, 450 "com.android.launcher3.tests.Activity" + activityNumber)); 451 startIntent(intent, By.pkg(packageName).text("TestActivity" + activityNumber), 452 false /* newTask */); 453 } 454 startImeTestActivity()455 public static void startImeTestActivity() { 456 final String packageName = getAppPackageName(); 457 final Intent intent = getInstrumentation().getContext().getPackageManager(). 458 getLaunchIntentForPackage(packageName); 459 intent.setComponent(new ComponentName(packageName, 460 "com.android.launcher3.testcomponent.ImeTestActivity")); 461 startIntent(intent, By.pkg(packageName).text("ImeTestActivity"), 462 false /* newTask */); 463 } 464 startIntent(Intent intent, BySelector selector, boolean newTask)465 private static void startIntent(Intent intent, BySelector selector, boolean newTask) { 466 intent.addCategory(Intent.CATEGORY_LAUNCHER); 467 if (newTask) { 468 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 469 } else { 470 intent.addFlags( 471 Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT); 472 } 473 getInstrumentation().getTargetContext().startActivity(intent); 474 assertTrue("App didn't start: " + selector, 475 TestHelpers.wait(Until.hasObject(selector), DEFAULT_UI_TIMEOUT)); 476 } 477 resolveSystemAppInfo(String category)478 public static ActivityInfo resolveSystemAppInfo(String category) { 479 return getInstrumentation().getContext().getPackageManager().resolveActivity( 480 new Intent(Intent.ACTION_MAIN).addCategory(category), 481 PackageManager.MATCH_SYSTEM_ONLY). 482 activityInfo; 483 } 484 485 resolveSystemApp(String category)486 public static String resolveSystemApp(String category) { 487 return resolveSystemAppInfo(category).packageName; 488 } 489 closeLauncherActivity()490 protected void closeLauncherActivity() { 491 // Destroy Launcher activity. 492 executeOnLauncher(launcher -> { 493 if (launcher != null) { 494 onLauncherActivityClose(launcher); 495 launcher.finish(); 496 } 497 }); 498 waitForLauncherCondition( 499 "Launcher still active", launcher -> launcher == null, DEFAULT_UI_TIMEOUT); 500 } 501 isInLaunchedApp(Launcher launcher)502 protected boolean isInLaunchedApp(Launcher launcher) { 503 return launcher == null || !launcher.hasBeenResumed(); 504 } 505 isInState(Supplier<LauncherState> state)506 protected boolean isInState(Supplier<LauncherState> state) { 507 if (!TestHelpers.isInLauncherProcess()) return true; 508 return getFromLauncher( 509 launcher -> launcher.getStateManager().getState() == state.get()); 510 } 511 getAllAppsScroll(Launcher launcher)512 protected int getAllAppsScroll(Launcher launcher) { 513 return launcher.getAppsView().getActiveRecyclerView().computeVerticalScrollOffset(); 514 } 515 checkLauncherIntegrity( Launcher launcher, ContainerType expectedContainerType)516 private void checkLauncherIntegrity( 517 Launcher launcher, ContainerType expectedContainerType) { 518 if (launcher != null) { 519 final StateManager<LauncherState> stateManager = launcher.getStateManager(); 520 final LauncherState stableState = stateManager.getCurrentStableState(); 521 522 assertTrue("Stable state != state: " + stableState.getClass().getSimpleName() + ", " 523 + stateManager.getState().getClass().getSimpleName(), 524 stableState == stateManager.getState()); 525 526 final boolean isResumed = launcher.hasBeenResumed(); 527 final boolean isStarted = launcher.isStarted(); 528 checkLauncherState(launcher, expectedContainerType, isResumed, isStarted); 529 530 final int ordinal = stableState.ordinal; 531 532 switch (expectedContainerType) { 533 case WORKSPACE: 534 case WIDGETS: { 535 assertTrue( 536 "Launcher is not resumed in state: " + expectedContainerType, 537 isResumed); 538 assertTrue(TestProtocol.stateOrdinalToString(ordinal), 539 ordinal == TestProtocol.NORMAL_STATE_ORDINAL); 540 break; 541 } 542 case HOME_ALL_APPS: { 543 assertTrue( 544 "Launcher is not resumed in state: " + expectedContainerType, 545 isResumed); 546 assertTrue(TestProtocol.stateOrdinalToString(ordinal), 547 ordinal == TestProtocol.ALL_APPS_STATE_ORDINAL); 548 break; 549 } 550 case OVERVIEW: { 551 verifyOverviewState(launcher, expectedContainerType, isStarted, isResumed, 552 ordinal, TestProtocol.OVERVIEW_STATE_ORDINAL); 553 break; 554 } 555 case SPLIT_SCREEN_SELECT: { 556 verifyOverviewState(launcher, expectedContainerType, isStarted, isResumed, 557 ordinal, TestProtocol.OVERVIEW_SPLIT_SELECT_ORDINAL); 558 break; 559 } 560 case TASKBAR_ALL_APPS: 561 case LAUNCHED_APP: { 562 assertTrue("Launcher is resumed in state: " + expectedContainerType, 563 !isResumed); 564 assertTrue(TestProtocol.stateOrdinalToString(ordinal), 565 ordinal == TestProtocol.NORMAL_STATE_ORDINAL); 566 break; 567 } 568 default: 569 throw new IllegalArgumentException( 570 "Illegal container: " + expectedContainerType); 571 } 572 } else { 573 assertTrue( 574 "Container type is not LAUNCHED_APP, TASKBAR_ALL_APPS " 575 + "or FALLBACK_OVERVIEW: " + expectedContainerType, 576 expectedContainerType == ContainerType.LAUNCHED_APP 577 || expectedContainerType == ContainerType.TASKBAR_ALL_APPS 578 || expectedContainerType == ContainerType.FALLBACK_OVERVIEW); 579 } 580 } 581 checkLauncherState(Launcher launcher, ContainerType expectedContainerType, boolean isResumed, boolean isStarted)582 protected void checkLauncherState(Launcher launcher, ContainerType expectedContainerType, 583 boolean isResumed, boolean isStarted) { 584 assertTrue("hasBeenResumed() != isStarted(), hasBeenResumed(): " + isResumed, 585 isResumed == isStarted); 586 assertTrue("hasBeenResumed() != isUserActive(), hasBeenResumed(): " + isResumed, 587 isResumed == launcher.isUserActive()); 588 } 589 checkLauncherStateInOverview(Launcher launcher, ContainerType expectedContainerType, boolean isStarted, boolean isResumed)590 protected void checkLauncherStateInOverview(Launcher launcher, 591 ContainerType expectedContainerType, boolean isStarted, boolean isResumed) { 592 assertTrue("Launcher is not resumed in state: " + expectedContainerType, 593 isResumed); 594 } 595 onLauncherActivityClose(Launcher launcher)596 protected void onLauncherActivityClose(Launcher launcher) { 597 } 598 createShortcutInCenterIfNotExist(String name)599 protected HomeAppIcon createShortcutInCenterIfNotExist(String name) { 600 Point dimension = mLauncher.getWorkspace().getIconGridDimensions(); 601 return createShortcutIfNotExist(name, dimension.x / 2, dimension.y / 2); 602 } 603 createShortcutIfNotExist(String name, Point cellPosition)604 protected HomeAppIcon createShortcutIfNotExist(String name, Point cellPosition) { 605 return createShortcutIfNotExist(name, cellPosition.x, cellPosition.y); 606 } 607 createShortcutIfNotExist(String name, int cellX, int cellY)608 protected HomeAppIcon createShortcutIfNotExist(String name, int cellX, int cellY) { 609 HomeAppIcon homeAppIcon = mLauncher.getWorkspace().tryGetWorkspaceAppIcon(name); 610 Log.d(ICON_MISSING, "homeAppIcon: " + homeAppIcon + " name: " + name + 611 " cell: " + cellX + ", " + cellY); 612 if (homeAppIcon == null) { 613 HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps(); 614 allApps.freeze(); 615 try { 616 allApps.getAppIcon(name).dragToWorkspace(cellX, cellY); 617 } finally { 618 allApps.unfreeze(); 619 } 620 homeAppIcon = mLauncher.getWorkspace().getWorkspaceAppIcon(name); 621 } 622 return homeAppIcon; 623 } 624 verifyOverviewState(Launcher launcher, ContainerType expectedContainerType, boolean isStarted, boolean isResumed, int ordinal, int expectedOrdinal)625 private void verifyOverviewState(Launcher launcher, ContainerType expectedContainerType, 626 boolean isStarted, boolean isResumed, int ordinal, int expectedOrdinal) { 627 checkLauncherStateInOverview(launcher, expectedContainerType, isStarted, isResumed); 628 assertEquals(TestProtocol.stateOrdinalToString(ordinal), ordinal, expectedOrdinal); 629 } 630 } 631