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