From dd33b64a64a481193f380f996633c3085aee721d Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Wed, 31 Jan 2024 19:03:05 -0800 Subject: [PATCH] Make sure TAPL waits for Launcher activity to stop each time it stops This helps to ensure that the test doesn't proceed while the activity is still stopping and it's state hasn't settled. We introduce a count of STOP events and make sure it's 0 except for cases where stops are safe to ignore or we have waited for them. Bug: 313926097 Flag: N/A Test: presubmit Change-Id: I51c73c89854fcaa390d47a57389da18b2ce0ee6c --- src/com/android/launcher3/Launcher.java | 10 +++++++++ .../testing/TestInformationHandler.java | 10 +++++++++ .../testing/shared/TestProtocol.java | 3 +++ .../launcher3/ui/AbstractLauncherUiTest.java | 3 +++ .../util/rule/TestIsolationRule.java | 8 +++++-- .../tapl/LauncherInstrumentation.java | 21 +++++++++++++++++++ 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 44a1bf0685..b39e76a0d9 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -412,6 +412,8 @@ public class Launcher extends StatefulActivity private final SettingsCache.OnChangeListener mNaturalScrollingChangedListener = enabled -> mIsNaturalScrollingEnabled = enabled; + private int mActivityStopCount; // Used only by tests + public static Launcher getLauncher(Context context) { return fromContext(context); } @@ -1053,10 +1055,18 @@ public class Launcher extends StatefulActivity 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 315b5e3a93..87be4d1a0e 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -208,6 +208,16 @@ public class TestInformationHandler implements ResourceBasedOverride { .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 3e188e6fb1..16cfc66ab7 100644 --- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java +++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java @@ -177,6 +177,9 @@ public final class TestProtocol { 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 79d8c60049..3ee951cdb9 100644 --- a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -598,6 +598,9 @@ public abstract class AbstractLauncherUiTest { 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 2b45902813..e98dcf4dee 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 @@ public class TestIsolationRule implements TestRule { 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 fef93b7626..bfaaf5a569 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 @@ public final class LauncherInstrumentation { 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 @@ public final class LauncherInstrumentation { */ @Deprecated public LauncherInstrumentation(Instrumentation instrumentation, boolean isLauncherTest) { + mIsLauncherTest = isLauncherTest; mInstrumentation = instrumentation; mDevice = UiDevice.getInstance(instrumentation); @@ -410,6 +412,11 @@ public final class LauncherInstrumentation { 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)); @@ -623,10 +630,19 @@ public final class LauncherInstrumentation { 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) { @@ -1000,6 +1016,9 @@ public final class LauncherInstrumentation { event -> TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE .equals(event.getClassName().toString()), () -> "Launcher activity didn't stop", actionName); + + // Reset activity stop count. + getAndResetActivityStopCount(); } /** @@ -2252,6 +2271,7 @@ public final class LauncherInstrumentation { } public Closable eventsCheck() { + assertNoUnexpectedStops(); Assert.assertTrue("Nested event checking", mEventChecker == null); disableSensorRotation(); final Integer initialPid = getPid(); @@ -2259,6 +2279,7 @@ public final class LauncherInstrumentation { if (eventChecker.start()) mEventChecker = eventChecker; return () -> { + assertNoUnexpectedStops(); if (initialPid != null && initialPid.intValue() != getPid()) { if (mOnLauncherCrashed != null) mOnLauncherCrashed.run(); checkForAnomaly();