Merge "TAPL: verify input events" into ub-launcher3-master
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8066d38..06f3453 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -76,6 +76,7 @@
 import android.view.KeyboardShortcutInfo;
 import android.view.LayoutInflater;
 import android.view.Menu;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
@@ -121,6 +122,7 @@
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.qsb.QsbContainerView;
 import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.touch.AllAppsSwipeController;
 import com.android.launcher3.touch.ItemClickHandler;
@@ -1778,10 +1780,21 @@
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
+        if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+            TestLogging.recordEvent("Key event: " + event);
+        }
         return (event.getKeyCode() == KeyEvent.KEYCODE_HOME) || super.dispatchKeyEvent(event);
     }
 
     @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (Utilities.IS_RUNNING_IN_TEST_HARNESS && ev.getAction() != MotionEvent.ACTION_MOVE) {
+            TestLogging.recordEvent("Touch event: " + ev);
+        }
+        return super.dispatchTouchEvent(ev);
+    }
+
+    @Override
     public void onBackPressed() {
         if (finishAutoCancelActionMode()) {
             return;
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
index 8f9fec9..835790d 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
@@ -56,7 +56,8 @@
 
             final int endY = start.y + swipeHeight;
             LauncherInstrumentation.log("AllAppsFromOverview.switchBackToOverview before swipe");
-            mLauncher.swipeToState(start.x, start.y, start.x, endY, 60, OVERVIEW_STATE_ORDINAL);
+            mLauncher.swipeToState(start.x, start.y, start.x, endY, 60, OVERVIEW_STATE_ORDINAL,
+                    LauncherInstrumentation.GestureScope.INSIDE);
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("swiped down")) {
                 return new Overview(mLauncher);
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 50bdf5c..c37e451 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -62,6 +62,10 @@
         }
     }
 
+    protected boolean zeroButtonToOverviewGestureStartsInLauncher() {
+        return false;
+    }
+
     protected void goToOverviewUnchecked() {
         switch (mLauncher.getNavigationModel()) {
             case ZERO_BUTTON: {
@@ -74,19 +78,26 @@
                         new Point(centerX, startY - swipeHeight - mLauncher.getTouchSlop());
 
                 final long downTime = SystemClock.uptimeMillis();
-                mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start);
+                final LauncherInstrumentation.GestureScope gestureScope =
+                        zeroButtonToOverviewGestureStartsInLauncher()
+                                ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
+                                : LauncherInstrumentation.GestureScope.OUTSIDE;
+                mLauncher.sendPointer(
+                        downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
                 mLauncher.executeAndWaitForEvent(
                         () -> mLauncher.movePointer(
                                 downTime,
                                 downTime,
                                 ZERO_BUTTON_SWIPE_UP_GESTURE_DURATION,
                                 start,
-                                end),
+                                end,
+                                gestureScope),
                         event -> TestProtocol.PAUSE_DETECTED_MESSAGE.equals(event.getClassName()),
                         () -> "Pause wasn't detected");
                 mLauncher.runToState(
                         () -> mLauncher.sendPointer(
-                                downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, end),
+                                downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, end,
+                                gestureScope),
                         OVERVIEW_STATE_ORDINAL);
                 break;
             }
@@ -109,7 +120,8 @@
                     startY = endY = mLauncher.getDevice().getDisplayHeight() / 2;
                 }
 
-                mLauncher.swipeToState(startX, startY, endX, endY, 10, OVERVIEW_STATE_ORDINAL);
+                mLauncher.swipeToState(startX, startY, endX, endY, 10, OVERVIEW_STATE_ORDINAL,
+                        LauncherInstrumentation.GestureScope.OUTSIDE);
                 break;
             }
 
@@ -162,7 +174,12 @@
                     endX = startX;
                     endY = 0;
                 }
-                mLauncher.swipeToState(startX, startY, endX, endY, 20, expectedState);
+                mLauncher.swipeToState(startX, startY, endX, endY, 20, expectedState,
+                        mLauncher.getNavigationModel()
+                                == LauncherInstrumentation.NavigationModel.ZERO_BUTTON
+                                ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
+                                : LauncherInstrumentation.GestureScope.OUTSIDE
+                );
                 break;
             }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index e13ea52..e5c83e2 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -82,7 +82,8 @@
                 flingForwardImpl();
             }
 
-            mLauncher.waitForObjectInContainer(verifyActiveContainer(), clearAllSelector).click();
+            mLauncher.clickLauncherObject(
+                    mLauncher.waitForObjectInContainer(verifyActiveContainer(), clearAllSelector));
         }
     }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java
index 1a0fe3d..c06e254 100644
--- a/tests/tapl/com/android/launcher3/tapl/Home.java
+++ b/tests/tapl/com/android/launcher3/tapl/Home.java
@@ -61,6 +61,11 @@
     }
 
     @Override
+    protected boolean zeroButtonToOverviewGestureStartsInLauncher() {
+        return true;
+    }
+
+    @Override
     protected int getExpectedStateForQuickSwitch() {
         return QUICK_SWITCH_STATE_ORDINAL;
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index f88a616..1722d5b 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -56,7 +56,7 @@
                 mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds());
 
         mLauncher.executeAndWaitForEvent(
-                () -> mObject.click(),
+                () -> mLauncher.clickLauncherObject(mObject),
                 event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
                 () -> "Launching an app didn't open a new window: " + mObject.getText());
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 3670392..63ec998 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -49,7 +49,6 @@
 import android.view.accessibility.AccessibilityEvent;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.BySelector;
@@ -69,9 +68,11 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.lang.ref.WeakReference;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.Deque;
 import java.util.LinkedList;
 import java.util.List;
@@ -94,13 +95,14 @@
     private static final int GESTURE_STEP_MS = 16;
     private static long START_TIME = System.currentTimeMillis();
 
-    static final Pattern LOG_TIME = Pattern.compile(
-            "[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\\.[0-9][0-9][0-9]");
-
     static final Pattern EVENT_LOG_ENTRY = Pattern.compile(
-            "(?<time>[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\\.[0-9][0-9][0-9])"
+            "[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\\.[0-9][0-9][0-9]"
                     + ".*" + TestProtocol.TAPL_EVENTS_TAG + ": (?<event>.*)");
 
+    private static final Pattern EVENT_TOUCH_DOWN = getTouchEventPattern("ACTION_DOWN");
+    private static final Pattern EVENT_TOUCH_UP = getTouchEventPattern("ACTION_UP");
+    private static final Pattern EVENT_TOUCH_CANCEL = getTouchEventPattern("ACTION_CANCEL");
+
     // Types for launcher containers that the user is interacting with. "Background" is a
     // pseudo-container corresponding to inactive launcher covered by another app.
     public enum ContainerType {
@@ -109,6 +111,13 @@
 
     public enum NavigationModel {ZERO_BUTTON, TWO_BUTTON, THREE_BUTTON}
 
+    // Where the gesture happens: outside of Launcher, inside or from inside to outside.
+    enum GestureScope {
+        OUTSIDE, INSIDE, INSIDE_TO_OUTSIDE
+    }
+
+    ;
+
     // Base class for launcher containers.
     static abstract class VisibleContainer {
         protected final LauncherInstrumentation mLauncher;
@@ -160,6 +169,15 @@
 
     private String mTimeBeforeFirstLogEvent;
 
+    private static Pattern getTouchEventPattern(String action) {
+        // The pattern includes sanity checks that we don't get a multi-touch events or other
+        // surprises.
+        return Pattern.compile(
+                "Touch event: MotionEvent.*?action=" + action + ".*?id\\[0\\]=0"
+                        +
+                        ".*?toolType\\[0\\]=TOOL_TYPE_FINGER.*?buttonState=0.*?pointerCount=1");
+    }
+
     /**
      * Constructs the root of TAPL hierarchy. You get all other objects from it.
      */
@@ -577,7 +595,7 @@
                             displaySize.x / 2, displaySize.y - 1,
                             displaySize.x / 2, 0,
                             ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
-                            false);
+                            false, GestureScope.INSIDE_TO_OUTSIDE);
                     try (LauncherInstrumentation.Closable c = addContextLayer(
                             "Swiped up from context menu to home")) {
                         waitUntilGone(CONTEXT_MENU_RES_ID);
@@ -594,7 +612,10 @@
                         swipeToState(
                                 displaySize.x / 2, displaySize.y - 1,
                                 displaySize.x / 2, 0,
-                                ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, NORMAL_STATE_ORDINAL);
+                                ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, NORMAL_STATE_ORDINAL,
+                                hasLauncherObject(By.textStartsWith(""))
+                                        ? GestureScope.INSIDE_TO_OUTSIDE
+                                        : GestureScope.OUTSIDE);
                     }
                 }
             } else {
@@ -763,11 +784,18 @@
         return object;
     }
 
-    @Nullable
     private boolean hasLauncherObject(String resId) {
         return mDevice.hasObject(getLauncherObjectSelector(resId));
     }
 
+    private boolean hasLauncherObject(BySelector selector) {
+        return mDevice.hasObject(makeLauncherSelector(selector));
+    }
+
+    private BySelector makeLauncherSelector(BySelector selector) {
+        return By.copy(selector).pkg(getLauncherPackageName());
+    }
+
     @NonNull
     UiObject2 waitForLauncherObject(String resName) {
         return waitForObjectBySelector(getLauncherObjectSelector(resName));
@@ -775,12 +803,12 @@
 
     @NonNull
     UiObject2 waitForLauncherObject(BySelector selector) {
-        return waitForObjectBySelector(By.copy(selector).pkg(getLauncherPackageName()));
+        return waitForObjectBySelector(makeLauncherSelector(selector));
     }
 
     @NonNull
     UiObject2 tryWaitForLauncherObject(BySelector selector, long timeout) {
-        return tryWaitForObjectBySelector(By.copy(selector).pkg(getLauncherPackageName()), timeout);
+        return tryWaitForObjectBySelector(makeLauncherSelector(selector), timeout);
     }
 
     @NonNull
@@ -857,8 +885,11 @@
         return actualState == expectedState;
     }
 
-    void swipeToState(int startX, int startY, int endX, int endY, int steps, int expectedState) {
-        runToState(() -> linearGesture(startX, startY, endX, endY, steps, false), expectedState);
+    void swipeToState(int startX, int startY, int endX, int endY, int steps, int expectedState,
+            GestureScope gestureScope) {
+        runToState(
+                () -> linearGesture(startX, startY, endX, endY, steps, false, gestureScope),
+                expectedState);
     }
 
     int getBottomGestureSize() {
@@ -871,6 +902,12 @@
         return container.getVisibleBounds().bottom - bottomGestureStartOnScreen;
     }
 
+    void clickLauncherObject(UiObject2 object) {
+        expectEvent(LauncherInstrumentation.EVENT_TOUCH_DOWN);
+        expectEvent(LauncherInstrumentation.EVENT_TOUCH_UP);
+        object.click();
+    }
+
     void scrollToLastVisibleRow(
             UiObject2 container,
             Collection<UiObject2> items,
@@ -942,7 +979,8 @@
         }
 
         executeAndWaitForEvent(
-                () -> linearGesture(startX, startY, endX, endY, steps, slowDown),
+                () -> linearGesture(
+                        startX, startY, endX, endY, steps, slowDown, GestureScope.INSIDE),
                 event -> TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName()),
                 () -> "Didn't receive a scroll end message: " + startX + ", " + startY
                         + ", " + endX + ", " + endY);
@@ -950,21 +988,24 @@
 
     // Inject a swipe gesture. Inject exactly 'steps' motion points, incrementing event time by a
     // fixed interval each time.
-    void linearGesture(int startX, int startY, int endX, int endY, int steps, boolean slowDown) {
+    void linearGesture(int startX, int startY, int endX, int endY, int steps, boolean slowDown,
+            GestureScope gestureScope) {
         log("linearGesture: " + startX + ", " + startY + " -> " + endX + ", " + endY);
         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(start, end, steps, downTime, slowDown);
-        sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end);
+        sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
+        final long endTime = movePointer(start, end, steps, downTime, slowDown, gestureScope);
+        sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope);
     }
 
-    long movePointer(Point start, Point end, int steps, long downTime, boolean slowDown) {
-        long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS, start, end);
+    long movePointer(Point start, Point end, int steps, long downTime, boolean slowDown,
+            GestureScope gestureScope) {
+        long endTime = movePointer(
+                downTime, downTime, steps * GESTURE_STEP_MS, start, end, gestureScope);
         if (slowDown) {
             endTime = movePointer(downTime, endTime + GESTURE_STEP_MS, 5 * GESTURE_STEP_MS, end,
-                    end);
+                    end, gestureScope);
         }
         return endTime;
     }
@@ -999,13 +1040,27 @@
                 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
     }
 
-    void sendPointer(long downTime, long currentTime, int action, Point point) {
+    void sendPointer(long downTime, long currentTime, int action, Point point,
+            GestureScope gestureScope) {
+        if (gestureScope != GestureScope.OUTSIDE) {
+            switch (action) {
+                case MotionEvent.ACTION_DOWN:
+                    expectEvent(EVENT_TOUCH_DOWN);
+                    break;
+                case MotionEvent.ACTION_UP:
+                    expectEvent(gestureScope == GestureScope.INSIDE
+                            ? EVENT_TOUCH_UP : EVENT_TOUCH_CANCEL);
+                    break;
+            }
+        }
+
         final MotionEvent event = getMotionEvent(downTime, currentTime, action, point.x, point.y);
         mInstrumentation.getUiAutomation().injectInputEvent(event, true);
         event.recycle();
     }
 
-    long movePointer(long downTime, long startTime, long duration, Point from, Point to) {
+    long movePointer(long downTime, long startTime, long duration, Point from, Point to,
+            GestureScope gestureScope) {
         log("movePointer: " + from + " to " + to);
         final Point point = new Point();
         long steps = duration / GESTURE_STEP_MS;
@@ -1019,7 +1074,7 @@
             point.x = from.x + (int) (progress * (to.x - from.x));
             point.y = from.y + (int) (progress * (to.y - from.y));
 
-            sendPointer(downTime, currentTime, MotionEvent.ACTION_MOVE, point);
+            sendPointer(downTime, currentTime, MotionEvent.ACTION_MOVE, point, gestureScope);
         }
         return currentTime;
     }
@@ -1032,9 +1087,10 @@
     UiObject2 clickAndGet(@NonNull final UiObject2 target, @NonNull String resName) {
         final Point targetCenter = target.getVisibleCenter();
         final long downTime = SystemClock.uptimeMillis();
-        sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter);
+        sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter, GestureScope.INSIDE);
         final UiObject2 result = waitForLauncherObject(resName);
-        sendPointer(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, targetCenter);
+        sendPointer(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, targetCenter,
+                GestureScope.INSIDE);
         return result;
     }
 
@@ -1133,9 +1189,6 @@
                             + " -s " + TestProtocol.TAPL_EVENTS_TAG);
             final Matcher matcher = EVENT_LOG_ENTRY.matcher(logcatEvents);
             while (matcher.find()) {
-                final String eventTime = matcher.group("time");
-                if (eventTime.equals(mTimeBeforeFirstLogEvent)) continue;
-
                 events.add(matcher.group("event"));
             }
             return events;
@@ -1147,15 +1200,9 @@
     private void startRecordingEvents() {
         Assert.assertTrue("Already recording events", mExpectedEvents == null);
         mExpectedEvents = new ArrayList<>();
-
-        try {
-            final String lastLogLine =
-                    mDevice.executeShellCommand("logcat -d --pid=" + getPid() + " -t 1");
-            final Matcher matcher = LOG_TIME.matcher(lastLogLine);
-            mTimeBeforeFirstLogEvent = matcher.find() ? matcher.group().replaceAll(" ", "") : null;
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
+        mTimeBeforeFirstLogEvent = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
+                .format(new Date())
+                .replaceAll(" ", "");
     }
 
     private void stopRecordingEvents() {
diff --git a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
index 461610d..c2f701b 100644
--- a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
@@ -38,7 +38,7 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             LauncherInstrumentation.log("OptionsPopupMenuItem before click "
                     + mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds());
-            mObject.click();
+            mLauncher.clickLauncherObject(mObject);
             mLauncher.assertTrue(
                     "App didn't start: " + By.pkg(expectedPackageName),
                     mLauncher.getDevice().wait(Until.hasObject(By.pkg(expectedPackageName)),
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 6622c6e..4d673a8 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -60,7 +60,8 @@
                     mLauncher.getDevice().getDisplayWidth() / 2,
                     0,
                     12,
-                    ALL_APPS_STATE_ORDINAL);
+                    ALL_APPS_STATE_ORDINAL,
+                    LauncherInstrumentation.GestureScope.INSIDE);
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "swiped all way up from overview")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 0d93cbc..b21b242 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -53,7 +53,8 @@
             final Rect taskBounds = mTask.getVisibleBounds();
             final int centerX = taskBounds.centerX();
             final int centerY = taskBounds.centerY();
-            mLauncher.linearGesture(centerX, centerY, centerX, 0, 10, false);
+            mLauncher.linearGesture(centerX, centerY, centerX, 0, 10, false,
+                    LauncherInstrumentation.GestureScope.INSIDE);
             mLauncher.waitForIdle();
         }
     }
@@ -67,7 +68,7 @@
             try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                     "clicking an overview task")) {
                 mLauncher.executeAndWaitForEvent(
-                        () -> mTask.click(),
+                        () -> mLauncher.clickLauncherObject(mTask),
                         event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
                         () -> "Launching task didn't open a new window: "
                                 + mTask.getParent().getContentDescription());
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 1d2c821..a0d5443 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -38,11 +38,21 @@
 import com.android.launcher3.ResourceUtils;
 import com.android.launcher3.testing.TestProtocol;
 
+import java.util.regex.Pattern;
+
 /**
  * Operations on the workspace screen.
  */
 public final class Workspace extends Home {
     private static final int FLING_STEPS = 10;
+
+    static final Pattern EVENT_CTRL_W_DOWN = Pattern.compile(
+            "Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_W"
+                    + ".*?metaState=META_CTRL_ON");
+    static final Pattern EVENT_CTRL_W_UP = Pattern.compile(
+            "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_W"
+                    + ".*?metaState=META_CTRL_ON");
+
     private final UiObject2 mHotseat;
 
     Workspace(LauncherInstrumentation launcher) {
@@ -108,7 +118,7 @@
                     0,
                     startY - swipeHeight - mLauncher.getTouchSlop(),
                     12,
-                    ALL_APPS_STATE_ORDINAL);
+                    ALL_APPS_STATE_ORDINAL, LauncherInstrumentation.GestureScope.INSIDE);
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "swiped to all apps")) {
@@ -195,17 +205,19 @@
         launcher.runToState(
                 () -> {
                     launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
-                            launchableCenter);
+                            launchableCenter, LauncherInstrumentation.GestureScope.INSIDE);
                     LauncherInstrumentation.log("dragIconToWorkspace: sent down");
                     launcher.waitForLauncherObject(longPressIndicator);
                     LauncherInstrumentation.log("dragIconToWorkspace: indicator");
-                    launcher.movePointer(launchableCenter, dest, 10, downTime, true);
+                    launcher.movePointer(launchableCenter, dest, 10, downTime, true,
+                            LauncherInstrumentation.GestureScope.INSIDE);
                 },
                 SPRING_LOADED_STATE_ORDINAL);
         LauncherInstrumentation.log("dragIconToWorkspace: moved pointer");
         launcher.runToState(
                 () -> launcher.sendPointer(
-                        downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest),
+                        downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest,
+                        LauncherInstrumentation.GestureScope.INSIDE),
                 NORMAL_STATE_ORDINAL);
         LauncherInstrumentation.log("dragIconToWorkspace: end");
         launcher.waitUntilGone("drop_target_bar");
@@ -248,6 +260,8 @@
     public Widgets openAllWidgets() {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             verifyActiveContainer();
+            mLauncher.expectEvent(EVENT_CTRL_W_DOWN);
+            mLauncher.expectEvent(EVENT_CTRL_W_UP);
             mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
             try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer("pressed Ctrl+W")) {
                 return new Widgets(mLauncher);