Merge "Make sure TAPL waits for Launcher activity to stop each time it stops" into main
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 496cb4e..798b238 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -411,6 +411,8 @@
     private final SettingsCache.OnChangeListener mNaturalScrollingChangedListener =
             enabled -> mIsNaturalScrollingEnabled = enabled;
 
+    private int mActivityStopCount; // Used only by tests
+
     public static Launcher getLauncher(Context context) {
         return fromContext(context);
     }
@@ -1052,10 +1054,18 @@
         mAppWidgetHolder.setActivityStarted(false);
         NotificationListener.removeNotificationsChangedListener(getPopupDataProvider());
         FloatingIconView.resetIconLoadResult();
+        ++mActivityStopCount;
         AccessibilityManagerCompat.sendTestProtocolEventToTest(
                 this, LAUNCHER_ACTIVITY_STOPPED_MESSAGE);
     }
 
+    /** Return activity stop count and reset it. Used only by tests. */
+    public int getAndResetActivityStopCount() {
+        final int activityStopCount = mActivityStopCount;
+        mActivityStopCount = 0;
+        return activityStopCount;
+    }
+
     @Override
     protected void onStart() {
         TraceHelper.INSTANCE.beginSection(ON_START_EVT);
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 5636405..27a153b 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -214,6 +214,16 @@
                                 .forceAllowRotationForTesting(Boolean.parseBoolean(arg)));
                 return response;
 
+            case TestProtocol.REQUEST_GET_AND_RESET_ACTIVITY_STOP_COUNT: {
+                final Bundle bundle = getLauncherUIProperty(Bundle::putInt,
+                        launcher -> launcher.getAndResetActivityStopCount());
+                if (bundle != null) return bundle;
+
+                // If Launcher activity wasn't created, 'it' was stopped 0 times.
+                response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, 0);
+                return response;
+            }
+
             case TestProtocol.REQUEST_WORKSPACE_CELL_LAYOUT_SIZE:
                 return getLauncherUIProperty(Bundle::putIntArray, launcher -> {
                     final Workspace<?> workspace = launcher.getWorkspace();
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 2f9945d..187daca 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -178,6 +178,9 @@
     public static final String REQUEST_UNSTASH_BUBBLE_BAR_IF_STASHED =
             "unstash-bubble-bar-if-stashed";
 
+    public static final String REQUEST_GET_AND_RESET_ACTIVITY_STOP_COUNT =
+            "get-and-reset-activity-stops";
+
     /** Logs {@link Log#d(String, String)} if {@link #sDebugTracing} is true. */
     public static void testLogD(String tag, String message) {
         if (!sDebugTracing) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index f0d2e20..dcf56f8 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -599,6 +599,9 @@
         Wait.atMost("Launcher activity didn't stop",
                 () -> !launcherInstrumentation.isLauncherActivityStarted(),
                 DEFAULT_ACTIVITY_TIMEOUT, launcherInstrumentation);
+
+        // Reset activity stop count.
+        launcherInstrumentation.getAndResetActivityStopCount();
     }
 
     public static ActivityInfo resolveSystemAppInfo(String category) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/rule/TestIsolationRule.java b/tests/multivalentTests/src/com/android/launcher3/util/rule/TestIsolationRule.java
index 2b45902..e98dcf4 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/rule/TestIsolationRule.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/rule/TestIsolationRule.java
@@ -44,11 +44,15 @@
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
-                base.evaluate();
-                // Make sure that Launcher workspace looks correct.
+                // Reset activity stop count.
+                mLauncher.getAndResetActivityStopCount();
 
+                base.evaluate();
+
+                // Make sure that Launcher workspace looks correct.
                 UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).pressHome();
                 AbstractLauncherUiTest.checkDetectedLeaks(mLauncher, mRequireOneActiveActivity);
+                mLauncher.assertNoUnexpectedStops();
             }
         };
     }
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 6c9f5ed..90ca990 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -207,6 +207,7 @@
 
     private TrackpadGestureType mTrackpadGestureType = TrackpadGestureType.NONE;
     private int mPointerCount = 0;
+    private final boolean mIsLauncherTest;
 
     private static Pattern getKeyEventPattern(String action, String keyCode) {
         return Pattern.compile("Key event: KeyEvent.*action=" + action + ".*keyCode=" + keyCode);
@@ -243,6 +244,7 @@
      */
     @Deprecated
     public LauncherInstrumentation(Instrumentation instrumentation, boolean isLauncherTest) {
+        mIsLauncherTest = isLauncherTest;
         mInstrumentation = instrumentation;
         mDevice = UiDevice.getInstance(instrumentation);
 
@@ -415,6 +417,11 @@
                 TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
+    public int getAndResetActivityStopCount() {
+        return getTestInfo(TestProtocol.REQUEST_GET_AND_RESET_ACTIVITY_STOP_COUNT).getInt(
+                TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     Rect getGridTaskRectForTablet() {
         return ((Rect) getTestInfo(TestProtocol.REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET)
                 .getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD));
@@ -628,10 +635,19 @@
 
     public void onTestStart() {
         mTestStartTime = System.currentTimeMillis();
+        assertNoUnexpectedStops();
     }
 
     public void onTestFinish() {
         mTestStartTime = -1;
+        assertNoUnexpectedStops();
+    }
+
+    /** Verify that the activity stop count is zero. */
+    public void assertNoUnexpectedStops() {
+        if (mIsLauncherTest) {
+            assertEquals("Unexpected activity stops", 0, getAndResetActivityStopCount());
+        }
     }
 
     private String formatSystemHealthMessage(String message) {
@@ -1005,6 +1021,9 @@
                 event -> TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE
                         .equals(event.getClassName().toString()),
                 () -> "Launcher activity didn't stop", actionName);
+
+        // Reset activity stop count.
+        getAndResetActivityStopCount();
     }
 
     /**
@@ -2257,6 +2276,7 @@
     }
 
     public Closable eventsCheck() {
+        assertNoUnexpectedStops();
         Assert.assertTrue("Nested event checking", mEventChecker == null);
         disableSensorRotation();
         final Integer initialPid = getPid();
@@ -2264,6 +2284,7 @@
         if (eventChecker.start()) mEventChecker = eventChecker;
 
         return () -> {
+            assertNoUnexpectedStops();
             if (initialPid != null && initialPid.intValue() != getPid()) {
                 if (mOnLauncherCrashed != null) mOnLauncherCrashed.run();
                 checkForAnomaly();