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