Using model-time scrolling in all apps
This should solve flakes when the test thread wakes up too rarely to
inject enough touch events.
Change-Id: I461583d35eb4bfe0192b81c242aacf8d20e353d1
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
index 948f39e..d3042cf 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
@@ -19,7 +19,6 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.quickstep.logging.UserEventDispatcherExtension.ALL_APPS_PREDICTION_TIPS;
-import android.app.ActivityManager;
import android.content.Context;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
@@ -39,6 +38,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.FloatingHeaderView;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.UserManagerCompat;
@@ -152,7 +152,7 @@
|| !launcher.isInState(ALL_APPS)
|| hasSeenAllAppsTip(launcher)
|| UserManagerCompat.getInstance(launcher).isDemoUser()
- || ActivityManager.isRunningInTestHarness()) {
+ || Utilities.IS_RUNNING_IN_TEST_HARNESS) {
return false;
}
diff --git a/src/com/android/launcher3/TestProtocol.java b/src/com/android/launcher3/TestProtocol.java
index ecbaa5b..eefecda 100644
--- a/src/com/android/launcher3/TestProtocol.java
+++ b/src/com/android/launcher3/TestProtocol.java
@@ -24,6 +24,7 @@
public static final String SCROLL_Y_FIELD = "scrollY";
public static final String STATE_FIELD = "state";
public static final String SWITCHED_TO_STATE_MESSAGE = "TAPL_SWITCHED_TO_STATE";
+ public static final String SCROLL_FINISHED_MESSAGE = "TAPL_SCROLL_FINISHED";
public static final String RESPONSE_MESSAGE_POSTFIX = "_RESPONSE";
public static final int NORMAL_STATE_ORDINAL = 0;
public static final int SPRING_LOADED_STATE_ORDINAL = 1;
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 180ca48..548d5de 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -32,7 +32,8 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
-import com.android.launcher3.graphics.DrawableFactory;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -419,4 +420,13 @@
public boolean hasOverlappingRendering() {
return false;
}
+
+ @Override
+ public void onScrollStateChanged(int state) {
+ super.onScrollStateChanged(state);
+
+ if (state == SCROLL_STATE_IDLE && Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
+ }
+ }
}
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index 7467119..1d62b43 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -24,7 +24,6 @@
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
-import android.app.ActivityManager;
import android.content.SharedPreferences;
import android.os.Handler;
import android.view.MotionEvent;
@@ -32,6 +31,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.states.InternalStateHandler;
@@ -134,7 +134,7 @@
&& !shouldShowForWorkProfile(launcher))
|| AbstractFloatingView.getTopOpenView(launcher) != null
|| UserManagerCompat.getInstance(launcher).isDemoUser()
- || ActivityManager.isRunningInTestHarness()) {
+ || Utilities.IS_RUNNING_IN_TEST_HARNESS) {
return;
}
@@ -159,7 +159,7 @@
|| (launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)
&& !shouldShowForWorkProfile(launcher))
|| UserManagerCompat.getInstance(launcher).isDemoUser()
- || ActivityManager.isRunningInTestHarness()) {
+ || Utilities.IS_RUNNING_IN_TEST_HARNESS) {
return;
}
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index b4d0c54..86f773f 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -62,6 +62,13 @@
sendEventToTest(accessibilityManager, TestProtocol.SWITCHED_TO_STATE_MESSAGE, parcel);
}
+ public static void sendScrollFinishedEventToTest(Context context) {
+ final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
+ if (accessibilityManager == null) return;
+
+ sendEventToTest(accessibilityManager, TestProtocol.SCROLL_FINISHED_MESSAGE, null);
+ }
+
private static void sendEventToTest(
AccessibilityManager accessibilityManager, String eventTag, Bundle data) {
final AccessibilityEvent e = AccessibilityEvent.obtain(
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 68bdfe3..7ad7b74 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -18,6 +18,8 @@
import static com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel.ZERO_BUTTON;
+import android.graphics.Rect;
+
import androidx.annotation.NonNull;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.Direction;
@@ -32,7 +34,6 @@
public class AllApps extends LauncherInstrumentation.VisibleContainer {
private static final int MAX_SCROLL_ATTEMPTS = 40;
private static final int MIN_INTERACT_SIZE = 100;
- private static final int FLING_SPEED = LauncherInstrumentation.needSlowGestures() ? 1000 : 3000;
private final int mHeight;
@@ -102,7 +103,7 @@
"search_container_all_apps");
int attempts = 0;
- allAppsContainer.setGestureMargins(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
+ final Rect margins = new Rect(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
for (int scroll = getScroll(allAppsContainer);
scroll != 0;
@@ -113,7 +114,7 @@
"Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
++attempts <= MAX_SCROLL_ATTEMPTS);
- allAppsContainer.scroll(Direction.UP, 1);
+ mLauncher.scrollWithModelTime(allAppsContainer, Direction.UP, 1, margins, 50);
}
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) {
@@ -133,7 +134,7 @@
// Try to figure out how much percentage of the container needs to be scrolled in order
// to reveal the app icon to have the MIN_INTERACT_SIZE
final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f);
- allAppsContainer.scroll(Direction.DOWN, pct);
+ mLauncher.scrollWithModelTime(allAppsContainer, Direction.DOWN, pct, null, 10);
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"scrolled an icon in all apps to make it visible - and then")) {
mLauncher.waitForIdle();
@@ -150,9 +151,8 @@
mLauncher.addContextLayer("want to fling forward in all apps")) {
final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center to avoid starting at elements near the top.
- allAppsContainer.setGestureMargins(0, 0, 0, mHeight / 2);
- allAppsContainer.fling(Direction.DOWN,
- (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ mLauncher.scrollWithModelTime(
+ allAppsContainer, Direction.DOWN, 1, new Rect(0, 0, 0, mHeight / 2), 10);
verifyActiveContainer();
}
}
@@ -165,9 +165,8 @@
mLauncher.addContextLayer("want to fling backward in all apps")) {
final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center, for symmetry with forward.
- allAppsContainer.setGestureMargins(0, mHeight / 2, 0, 0);
- allAppsContainer.fling(Direction.UP,
- (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ mLauncher.scrollWithModelTime(
+ allAppsContainer, Direction.UP, 1, new Rect(0, mHeight / 2, 0, 0), 10);
verifyActiveContainer();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 4d8ff1b..e5d27ad 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -27,6 +27,7 @@
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Point;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -46,6 +47,7 @@
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.Configurator;
+import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
@@ -360,7 +362,7 @@
? NORMAL_STATE_ORDINAL : BACKGROUND_APP_STATE_ORDINAL;
final Point displaySize = getRealDisplaySize();
- swipeViaMovePointer(
+ swipeWithModelTime(
displaySize.x / 2, displaySize.y - 1,
displaySize.x / 2, 0,
finalState, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
@@ -548,18 +550,65 @@
() -> mDevice.swipe(startX, startY, endX, endY, steps));
}
- void swipeViaMovePointer(
+ void swipeWithModelTime(
int startX, int startY, int endX, int endY, int expectedState, int steps) {
- changeStateViaGesture(startX, startY, endX, endY, expectedState, () -> {
- final long downTime = SystemClock.uptimeMillis();
- final Point start = new Point(startX, startY);
- final Point end = new Point(endX, endY);
- sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start);
- final long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS, start,
- end);
- sendPointer(
- downTime, endTime, MotionEvent.ACTION_UP, end);
- });
+ changeStateViaGesture(startX, startY, endX, endY, expectedState,
+ () -> swipeWithModelTime(startX, startY, endX, endY, steps));
+ }
+
+ void scrollWithModelTime(
+ UiObject2 container, Direction direction, float percent, Rect margins, int steps) {
+ final Rect rect = container.getVisibleBounds();
+ if (margins != null) {
+ rect.left += margins.left;
+ rect.top += margins.top;
+ rect.right -= margins.right;
+ rect.bottom -= margins.bottom;
+ }
+
+ final int startX;
+ final int startY;
+ final int endX;
+ final int endY;
+
+ switch (direction) {
+ case UP: {
+ startX = endX = rect.centerX();
+ final int vertCenter = rect.centerY();
+ final float halfGestureHeight = rect.height() * percent / 2.0f;
+ startY = (int) (vertCenter - halfGestureHeight);
+ endY = (int) (vertCenter + halfGestureHeight);
+ }
+ break;
+ case DOWN: {
+ startX = endX = rect.centerX();
+ final int vertCenter = rect.centerY();
+ final float halfGestureHeight = rect.height() * percent / 2.0f;
+ startY = (int) (vertCenter + halfGestureHeight);
+ endY = (int) (vertCenter - halfGestureHeight);
+ }
+ break;
+ default:
+ fail("Unsupported direction");
+ return;
+ }
+
+ executeAndWaitForEvent(
+ () -> swipeWithModelTime(startX, startY, endX, endY, steps),
+ event -> TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName()),
+ "Didn't receive a scroll end message: " + startX + ", " + startY
+ + ", " + endX + ", " + endY);
+ }
+
+ // Inject a swipe gesture. Inject exactly 'steps' motion points, incrementing event time by a
+ // fixed interval each time.
+ private void swipeWithModelTime(int startX, int startY, int endX, int endY, int steps) {
+ final long downTime = SystemClock.uptimeMillis();
+ final Point start = new Point(startX, startY);
+ final Point end = new Point(endX, endY);
+ sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start);
+ final long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS, start, end);
+ sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end);
}
private void changeStateViaGesture(int startX, int startY, int endX, int endY,
@@ -673,10 +722,7 @@
}
static void sleep(int duration) {
- try {
- Thread.sleep(duration);
- } catch (InterruptedException e) {
- }
+ SystemClock.sleep(duration);
}
int getEdgeSensitivityWidth() {