Merge "Suppress ViewInflationDuringSwipeUp test." into ub-launcher3-master
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 1bbeca4..daaa95b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -5,16 +5,18 @@
 import android.content.Context;
 import android.os.Bundle;
 
-import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.testing.TestInformationHandler;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.uioverrides.states.OverviewState;
 import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
-import com.android.launcher3.util.DefaultDisplay;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.recents.model.Task;
 
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 
 public class QuickstepTestInformationHandler extends TestInformationHandler {
 
@@ -54,10 +56,8 @@
                     final int leftMargin = MAIN_EXECUTOR.submit(() ->
                             getRecentsView().getLeftGestureMargin()).get();
                     response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, leftMargin);
-                } catch (ExecutionException e) {
-                    e.printStackTrace();
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
+                } catch (ExecutionException | InterruptedException e) {
+                    throw new RuntimeException(e);
                 }
                 return response;
             }
@@ -67,13 +67,31 @@
                     final int rightMargin = MAIN_EXECUTOR.submit(() ->
                             getRecentsView().getRightGestureMargin()).get();
                     response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, rightMargin);
-                } catch (ExecutionException e) {
-                    e.printStackTrace();
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
+                } catch (ExecutionException | InterruptedException e) {
+                    throw new RuntimeException(e);
                 }
                 return response;
             }
+
+            case TestProtocol.REQUEST_RECENT_TASKS_LIST: {
+                ArrayList<String> taskBaseIntentComponents = new ArrayList<>();
+                CountDownLatch latch = new CountDownLatch(1);
+                RecentsModel.INSTANCE.get(mContext).getTasks((tasks) -> {
+                    for (Task t : tasks) {
+                        taskBaseIntentComponents.add(
+                                t.key.baseIntent.getComponent().flattenToString());
+                    }
+                    latch.countDown();
+                });
+                try {
+                    latch.await(2, TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+                response.putStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        taskBaseIntentComponents);
+                return response;
+            }
         }
 
         return super.call(method);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 764e0f3..1545ec5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -35,6 +35,7 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
+import android.widget.FrameLayout;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Hotseat;
@@ -46,11 +47,14 @@
 import com.android.launcher3.appprediction.PredictionUiStateManager;
 import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
 import com.android.launcher3.uioverrides.DejankBinderTracker;
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.views.ScrimView;
 import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.util.AppWindowAnimationHelper;
 import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
 import com.android.quickstep.util.LayoutUtils;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.RecentsExtraCard;
 
 /**
  * {@link RecentsView} used in Launcher activity
@@ -62,6 +66,25 @@
 
     private final TransformParams mTransformParams = new TransformParams();
 
+    private RecentsExtraCard mRecentsExtraCardPlugin;
+    private RecentsExtraViewContainer mRecentsExtraViewContainer;
+    private PluginListener<RecentsExtraCard> mRecentsExtraCardPluginListener =
+            new PluginListener<RecentsExtraCard>() {
+        @Override
+        public void onPluginConnected(RecentsExtraCard recentsExtraCard, Context context) {
+            createRecentsExtraCard();
+            mRecentsExtraCardPlugin = recentsExtraCard;
+            mRecentsExtraCardPlugin.setupView(context, mRecentsExtraViewContainer, mActivity);
+        }
+
+        @Override
+        public void onPluginDisconnected(RecentsExtraCard plugin) {
+            removeView(mRecentsExtraViewContainer);
+            mRecentsExtraCardPlugin = null;
+            mRecentsExtraViewContainer = null;
+        }
+    };
+
     public LauncherRecentsView(Context context) {
         this(context, null);
     }
@@ -298,4 +321,66 @@
         }
         return super.shouldStealTouchFromSiblingsBelow(ev);
     }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        PluginManagerWrapper.INSTANCE.get(getContext())
+                .addPluginListener(mRecentsExtraCardPluginListener, RecentsExtraCard.class);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(
+                mRecentsExtraCardPluginListener);
+    }
+
+    @Override
+    protected int computeMinScrollX() {
+        if (canComputeScrollX() && !mIsRtl) {
+            return computeScrollX();
+        }
+        return super.computeMinScrollX();
+    }
+
+    @Override
+    protected int computeMaxScrollX() {
+        if (canComputeScrollX() && mIsRtl) {
+            return computeScrollX();
+        }
+        return super.computeMaxScrollX();
+    }
+
+    private boolean canComputeScrollX() {
+        return mRecentsExtraCardPlugin != null && getTaskViewCount() > 0
+                && !mDisallowScrollToClearAll;
+    }
+
+    private int computeScrollX() {
+        int scrollIndex = getTaskViewStartIndex() - 1;
+        while (scrollIndex >= 0 && getChildAt(scrollIndex) instanceof RecentsExtraViewContainer
+                && ((RecentsExtraViewContainer) getChildAt(scrollIndex)).isScrollable()) {
+            scrollIndex--;
+        }
+        return getScrollForPage(scrollIndex + 1);
+    }
+
+    private void createRecentsExtraCard() {
+        mRecentsExtraViewContainer = new RecentsExtraViewContainer(getContext());
+        FrameLayout.LayoutParams helpCardParams =
+                new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+                        FrameLayout.LayoutParams.MATCH_PARENT);
+        mRecentsExtraViewContainer.setLayoutParams(helpCardParams);
+        mRecentsExtraViewContainer.setScrollable(true);
+        addView(mRecentsExtraViewContainer, 0);
+    }
+
+    @Override
+    public void resetTaskVisuals() {
+        super.resetTaskVisuals();
+        if (mRecentsExtraViewContainer != null) {
+            mRecentsExtraViewContainer.setAlpha(mContentAlpha);
+        }
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java
new file mode 100644
index 0000000..1ea6d4a
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 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.quickstep.views;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * Empty view to house recents overview extra card
+ */
+public class RecentsExtraViewContainer extends FrameLayout implements RecentsView.PageCallbacks {
+
+    private boolean mScrollable = false;
+
+    public RecentsExtraViewContainer(Context context) {
+        super(context);
+    }
+
+    public RecentsExtraViewContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public RecentsExtraViewContainer(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    /**
+     * Determine whether the view should be scrolled to in the recents overview, similar to the
+     * taskviews.
+     * @return true if viewed should be scrolled to, false if not
+     */
+    public boolean isScrollable() {
+        return mScrollable;
+    }
+
+    public void setScrollable(boolean scrollable) {
+        this.mScrollable = scrollable;
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index ea06991..6120b9e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -17,6 +17,7 @@
 package com.android.quickstep.views;
 
 import static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_PIXELS;
+
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
 import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
@@ -102,13 +103,13 @@
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.ViewPool;
 import com.android.quickstep.RecentsAnimationController;
+import com.android.quickstep.RecentsAnimationTargets;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.RecentsModel.TaskThumbnailChangeListener;
 import com.android.quickstep.TaskThumbnailCache;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.ViewUtils;
 import com.android.quickstep.util.AppWindowAnimationHelper;
-import com.android.quickstep.RecentsAnimationTargets;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -189,7 +190,7 @@
     private final ViewPool<TaskView> mTaskViewPool;
 
     private boolean mDwbToastShown;
-    private boolean mDisallowScrollToClearAll;
+    protected boolean mDisallowScrollToClearAll;
     private boolean mOverlayEnabled;
     private boolean mFreezeViewVisibility;
 
@@ -291,7 +292,7 @@
     private LayoutTransition mLayoutTransition;
 
     @ViewDebug.ExportedProperty(category = "launcher")
-    private float mContentAlpha = 1;
+    protected float mContentAlpha = 1;
     @ViewDebug.ExportedProperty(category = "launcher")
     protected float mFullscreenProgress = 0;
 
@@ -1850,6 +1851,7 @@
         return Math.max(insets.getSystemGestureInsets().right, insets.getSystemWindowInsetRight());
     }
 
+
     /** If it's in the live tile mode, switch the running task into screenshot mode. */
     public void switchToScreenshot(Runnable onFinishRunnable) {
         TaskView taskView = getRunningTaskView();
@@ -1864,4 +1866,25 @@
         taskView.getThumbnail().refresh();
         ViewUtils.postDraw(taskView, onFinishRunnable);
     }
+
+    @Override
+    public void addView(View child, int index) {
+        super.addView(child, index);
+        if (isExtraCardView(child, index)) {
+            mTaskViewStartIndex++;
+        }
+    }
+
+    @Override
+    public void removeView(View view) {
+        if (isExtraCardView(view, indexOfChild(view))) {
+            mTaskViewStartIndex--;
+        }
+        super.removeView(view);
+    }
+
+    private boolean isExtraCardView(View view, int index) {
+        return !(view instanceof TaskView) && !(view instanceof ClearAllButton)
+                && index <= mTaskViewStartIndex;
+    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index fcbc314..aa5fce1 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
 import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage;
 import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
+import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_ACTIVITY_TIMEOUT;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.resolveSystemApp;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.startAppFast;
@@ -36,6 +37,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Instrumentation;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -55,7 +57,6 @@
 import com.android.launcher3.testcomponent.TestCommandReceiver;
 import com.android.launcher3.util.Wait;
 import com.android.launcher3.util.rule.FailureWatcher;
-import com.android.launcher3.util.rule.SimpleActivityRule;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 import com.android.quickstep.views.RecentsView;
 
@@ -86,10 +87,6 @@
     @Rule
     public final TestRule mOrderSensitiveRules;
 
-    @Rule
-    public final SimpleActivityRule<RecentsActivity> mActivityMonitor =
-            new SimpleActivityRule(RecentsActivity.class);
-
     public FallbackRecentsTest() throws RemoteException {
         Instrumentation instrumentation = getInstrumentation();
         Context context = instrumentation.getContext();
@@ -143,7 +140,7 @@
     @NavigationModeSwitch
     @Test
     public void goToOverviewFromApp() {
-        startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
+        startAppFastAndWaitForRecentTask(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
 
         mLauncher.getBackground().switchToOverview();
     }
@@ -159,7 +156,7 @@
         if (!TestHelpers.isInLauncherProcess()) return null;
         Object[] result = new Object[1];
         Wait.atMost("Failed to get from recents", () -> MAIN_EXECUTOR.submit(() -> {
-            RecentsActivity activity = mActivityMonitor.getActivity();
+            RecentsActivity activity = RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
             if (activity == null) {
                 return false;
             }
@@ -177,13 +174,15 @@
     @NavigationModeSwitch
     @Test
     public void testOverview() {
-        startAppFast(getAppPackageName());
-        startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
+        startAppFastAndWaitForRecentTask(getAppPackageName());
+        startAppFastAndWaitForRecentTask(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
         startTestActivity(2);
+        Wait.atMost("Expected three apps in the task list",
+                () -> mLauncher.getRecentTasks().size() >= 3, DEFAULT_ACTIVITY_TIMEOUT);
 
         BaseOverview overview = mLauncher.getBackground().switchToOverview();
-        executeOnRecents(
-                recents -> assertTrue("Don't have at least 3 tasks", getTaskCount(recents) >= 3));
+        executeOnRecents(recents ->
+                assertTrue("Don't have at least 3 tasks", getTaskCount(recents) >= 3));
 
         // Test flinging forward and backward.
         overview.flingForward();
@@ -229,4 +228,24 @@
     private int getTaskCount(RecentsActivity recents) {
         return recents.<RecentsView>getOverviewPanel().getTaskViewCount();
     }
+
+    /**
+     * Workaround for b/141580748, there was an issue where the recent task is only updated when the
+     * activity starting the task is resumed.  In this case, we should wait until the task is in
+     * the recents task list before continuing.
+     */
+    private void startAppFastAndWaitForRecentTask(String packageName) {
+        startAppFast(packageName);
+        Wait.atMost("Expected app in task list",
+                () -> containsRecentTaskWithPackage(packageName), DEFAULT_ACTIVITY_TIMEOUT);
+    }
+
+    private boolean containsRecentTaskWithPackage(String packageName) {
+        for (ComponentName cn : mLauncher.getRecentTasks()) {
+            if (cn.getPackageName().equals(packageName)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index fa9cc3a..8296cf9 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -115,9 +115,7 @@
                             mLauncher.getAppsView().getAppsStore().getDeferUpdatesFlags()).get();
                     response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
                             deferUpdatesFlags);
-                } catch (ExecutionException e) {
-                    throw new RuntimeException(e);
-                } catch (InterruptedException e) {
+                } catch (ExecutionException | InterruptedException e) {
                     throw new RuntimeException(e);
                 }
                 break;
@@ -130,9 +128,7 @@
                             .get();
                     response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
                             deferUpdatesFlags);
-                } catch (ExecutionException e) {
-                    throw new RuntimeException(e);
-                } catch (InterruptedException e) {
+                } catch (ExecutionException | InterruptedException e) {
                     throw new RuntimeException(e);
                 }
                 break;
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index add4565..5110977 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -75,6 +75,7 @@
     public static final String REQUEST_JAVA_LEAK = "java-leak";
     public static final String REQUEST_NATIVE_LEAK = "native-leak";
     public static final String REQUEST_VIEW_LEAK = "view-leak";
+    public static final String REQUEST_RECENT_TASKS_LIST = "recent-tasks-list";
 
     public static boolean sDebugTracing = false;
     public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 3912b44..45c0d90 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -767,11 +767,6 @@
         // Match the position of the original view.
         view.matchPositionOf(launcher, originalView, isOpening, positionOut);
 
-        // Must be called after matchPositionOf so that we know what size to load.
-        if (shouldLoadIcon) {
-            view.checkIconResult(originalView, isOpening);
-        }
-
         // We need to add it to the overlay, but keep it invisible until animation starts..
         view.setVisibility(INVISIBLE);
         parent.addView(view);
@@ -798,6 +793,14 @@
                 view.finish(dragLayer);
             }
         };
+
+        // Must be called after matchPositionOf so that we know what size to load.
+        // Must be called after the fastFinish listener and end runnable is created so that
+        // the icon is not left in a hidden state.
+        if (shouldLoadIcon) {
+            view.checkIconResult(originalView, isOpening);
+        }
+
         return view;
     }
 
diff --git a/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java b/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java
new file mode 100644
index 0000000..0ebea3d
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 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.systemui.plugins;
+
+import android.app.Activity;
+import android.content.Context;
+import android.widget.FrameLayout;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Implement this interface to allow extra card on recents overview.
+ */
+@ProvidesInterface(action = RecentsExtraCard.ACTION, version = RecentsExtraCard.VERSION)
+public interface RecentsExtraCard extends Plugin {
+
+    String ACTION = "com.android.systemui.action.PLUGIN_RECENTS_EXTRA_CARD";
+    int VERSION = 1;
+
+    /**
+     * Sets up the recents overview extra card and fills in data.
+     *
+     * @param context Plugin context
+     * @param frameLayout PlaceholderView
+     * @param activity Recents activity to hold extra view
+     */
+    void setupView(Context context, FrameLayout frameLayout, Activity activity);
+}
diff --git a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
index 7ef946d..efbd9c9 100644
--- a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
+++ b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
@@ -48,6 +48,7 @@
     public void setUp() throws Exception {
         super.setUp();
         mDevice.pressHome();
+        waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null);
         waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL);
         mSessionId = -1;
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 338f714..8ccfc05 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -55,7 +55,7 @@
             final int leftMargin = mLauncher.getTestInfo(
                     TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN).
                     getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
-            mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin, 0, 0, 0), 20);
+            mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, 0, 0), 20);
             verifyActiveContainer();
         }
     }
@@ -89,7 +89,7 @@
             final int rightMargin = mLauncher.getTestInfo(
                     TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN).
                     getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
-            mLauncher.scroll(overview, Direction.RIGHT, new Rect(0, 0, rightMargin, 0), 20);
+            mLauncher.scroll(overview, Direction.RIGHT, new Rect(0, 0, rightMargin + 1, 0), 20);
             verifyActiveContainer();
         }
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 3248d6a..484cbb6 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -64,8 +64,7 @@
 import com.android.launcher3.testing.TestProtocol;
 import com.android.systemui.shared.system.QuickStepContract;
 
-import org.junit.Assert;
-
+import java.util.ArrayList;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.lang.ref.WeakReference;
@@ -78,6 +77,8 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 
+import org.junit.Assert;
+
 /**
  * The main tapl object. The only object that can be explicitly constructed by the using code. It
  * produces all other objects.
@@ -822,8 +823,8 @@
         switch (direction) {
             case UP: {
                 startX = endX = rect.centerX();
-                startY = rect.top + 1;
-                endY = rect.bottom;
+                startY = rect.top;
+                endY = rect.bottom - 1;
             }
             break;
             case DOWN: {
@@ -834,8 +835,8 @@
             break;
             case LEFT: {
                 startY = endY = rect.centerY();
-                startX = rect.left + 1;
-                endX = rect.right;
+                startX = rect.left;
+                endX = rect.right - 1;
             }
             break;
             case RIGHT: {
@@ -997,4 +998,14 @@
     public void produceViewLeak() {
         getTestInfo(TestProtocol.REQUEST_VIEW_LEAK);
     }
+
+    public ArrayList<ComponentName> getRecentTasks() {
+        ArrayList<ComponentName> tasks = new ArrayList<>();
+        ArrayList<String> components = getTestInfo(TestProtocol.REQUEST_RECENT_TASKS_LIST)
+                .getStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+        for (String s : components) {
+            tasks.add(ComponentName.unflattenFromString(s));
+        }
+        return tasks;
+    }
 }
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 0195693..5fcaa55 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -48,7 +48,7 @@
             mLauncher.scroll(
                     widgetsContainer,
                     Direction.DOWN,
-                    new Rect(0, 0, 0, mLauncher.getBottomGestureMargin(widgetsContainer)),
+                    new Rect(0, 0, 0, mLauncher.getBottomGestureMargin(widgetsContainer) + 1),
                     FLING_STEPS);
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) {
                 verifyActiveContainer();
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 0aa36dd..d1261e0 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -181,7 +181,7 @@
     public void flingForward() {
         final UiObject2 workspace = verifyActiveContainer();
         mLauncher.scroll(workspace, Direction.RIGHT,
-                new Rect(0, 0, mLauncher.getEdgeSensitivityWidth(), 0),
+                new Rect(0, 0, mLauncher.getEdgeSensitivityWidth() + 1, 0),
                 FLING_STEPS);
         verifyActiveContainer();
     }
@@ -193,7 +193,7 @@
     public void flingBackward() {
         final UiObject2 workspace = verifyActiveContainer();
         mLauncher.scroll(workspace, Direction.LEFT,
-                new Rect(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0),
+                new Rect(mLauncher.getEdgeSensitivityWidth() + 1, 0, 0, 0),
                 FLING_STEPS);
         verifyActiveContainer();
     }