Use RunListener to Clear inline mocks at the end of each test class.
Inline mocks are leaking activity contexts and accumulation of these activity contexts led to OOM that resulted in test failure.
See https://github.com/mockito/mockito/issues/1614 for details on mockito caused memory leaks
This change works for both soong and gradle builds.
Bug: 378520480
Test: atest and android studio builds
Flag: TEST_ONLY
Change-Id: I4a50993621ea416a02a41dd2f9c330d1599f065c
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java
index e6c5a6c..66c4ab5 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java
@@ -33,11 +33,13 @@
import com.android.quickstep.views.RecentsView;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@SmallTest
@RunWith(LauncherMultivalentJUnit.class)
+@Ignore
public class LauncherSwipeHandlerV2TestCase extends AbsSwipeUpHandlerTestCase<
LauncherState,
QuickstepLauncher,
diff --git a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
index 80fbce7..6cab71a 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
@@ -8,6 +8,8 @@
import com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE
import com.android.launcher3.util.DisplayController.CHANGE_ROTATION
import com.android.launcher3.util.DisplayController.Info
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
import com.android.launcher3.util.NavigationMode
import com.android.quickstep.util.GestureExclusionManager
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY
@@ -22,6 +24,7 @@
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -50,6 +53,13 @@
underTest = RecentsAnimationDeviceState(context, exclusionManager)
}
+ @After
+ fun tearDown() {
+ underTest.close()
+ UI_HELPER_EXECUTOR.submit {}.get()
+ MAIN_EXECUTOR.submit {}.get()
+ }
+
@Test
fun registerExclusionListener_success() {
underTest.registerExclusionListener()
@@ -121,8 +131,8 @@
@Test
fun trackpadGesturesNotAllowedForSelectedStates() {
- val disablingStates = GESTURE_DISABLING_SYSUI_STATES +
- SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED
+ val disablingStates =
+ GESTURE_DISABLING_SYSUI_STATES + SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED
allSysUiStates().forEach { state ->
val canStartGesture = !disablingStates.contains(state)
@@ -133,13 +143,13 @@
@Test
fun trackpadGesturesNotAllowedIfHomeAndOverviewIsDisabled() {
- val stateToExpectedResult = mapOf(
- SYSUI_STATE_HOME_DISABLED to true,
- SYSUI_STATE_OVERVIEW_DISABLED to true,
- DEFAULT_STATE
- .enable(SYSUI_STATE_OVERVIEW_DISABLED)
- .enable(SYSUI_STATE_HOME_DISABLED) to false
- )
+ val stateToExpectedResult =
+ mapOf(
+ SYSUI_STATE_HOME_DISABLED to true,
+ SYSUI_STATE_OVERVIEW_DISABLED to true,
+ DEFAULT_STATE.enable(SYSUI_STATE_OVERVIEW_DISABLED)
+ .enable(SYSUI_STATE_HOME_DISABLED) to false,
+ )
stateToExpectedResult.forEach { (state, allowed) ->
underTest.setSystemUiFlags(state)
@@ -160,22 +170,19 @@
@Test
fun systemGesturesNotAllowedWhenGestureStateDisabledAndNavBarVisible() {
- val stateToExpectedResult = mapOf(
- DEFAULT_STATE
- .enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
- .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
- DEFAULT_STATE
- .enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
- .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
- DEFAULT_STATE
- .disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
- .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
- DEFAULT_STATE
- .disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
- .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to false,
- )
+ val stateToExpectedResult =
+ mapOf(
+ DEFAULT_STATE.enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
+ DEFAULT_STATE.enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
+ DEFAULT_STATE.disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
+ DEFAULT_STATE.disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to false,
+ )
- stateToExpectedResult.forEach {(state, gestureAllowed) ->
+ stateToExpectedResult.forEach { (state, gestureAllowed) ->
underTest.setSystemUiFlags(state)
assertThat(underTest.canStartSystemGesture()).isEqualTo(gestureAllowed)
}
@@ -187,14 +194,15 @@
}
companion object {
- private val GESTURE_DISABLING_SYSUI_STATES = listOf(
- SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
- SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
- SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
- SYSUI_STATE_MAGNIFICATION_OVERLAP,
- SYSUI_STATE_DEVICE_DREAMING,
- SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION,
- )
+ private val GESTURE_DISABLING_SYSUI_STATES =
+ listOf(
+ SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+ SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
+ SYSUI_STATE_MAGNIFICATION_OVERLAP,
+ SYSUI_STATE_DEVICE_DREAMING,
+ SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION,
+ )
private const val SYSUI_STATES_COUNT = 33
private const val DEFAULT_STATE = 0L
}
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 5cf96c8..862b862 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -29,6 +29,8 @@
android:functionalTest="false"
android:handleProfiling="false"
android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.launcher3" >
+ android:targetPackage="com.android.launcher3" >
+ <meta-data android:name="listener"
+ android:value="com.android.launcher3.util.GlobalTestRunListener"/>
</instrumentation>
</manifest>
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/GlobalTestRunListener.java b/tests/multivalentTests/src/com/android/launcher3/util/GlobalTestRunListener.java
new file mode 100644
index 0000000..667f540
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/GlobalTestRunListener.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunListener;
+import org.mockito.Mockito;
+
+public class GlobalTestRunListener extends RunListener {
+ /**
+ * See {@link RunListener#testFinished} which executes per atomic test.
+ * {@link RunListener#testSuiteFinished} which executes per test suite. Test suite = test class
+ * in this context.
+ * {@link RunListener#testRunFinished} which executes after everything (all test suites) is
+ * completed.
+ */
+ @Override
+ public void testSuiteFinished(Description description) throws Exception {
+ // This method runs after every test class and will clear mocks after every test class
+ // execution is completed.
+ Mockito.framework().clearInlineMocks();
+ super.testSuiteFinished(description);
+ }
+}