• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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