Merge "Fade in badges on top of icons after swipe up animation." into ub-launcher3-qt-dev
diff --git a/go/quickstep/res/layout/task_item_view.xml b/go/quickstep/res/layout/task_item_view.xml
index 699178d..ab2cf28 100644
--- a/go/quickstep/res/layout/task_item_view.xml
+++ b/go/quickstep/res/layout/task_item_view.xml
@@ -18,7 +18,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="@dimen/task_item_height"
-    android:orientation="horizontal">
+    android:orientation="horizontal"
+    android:clipChildren="false">
     <com.android.quickstep.views.TaskThumbnailIconView
         android:id="@+id/task_icon_and_thumbnail"
         android:layout_width="match_parent"
diff --git a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
index bcb6343..87b4d4e 100644
--- a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
@@ -38,6 +38,7 @@
 import android.content.res.Resources;
 import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.util.ArraySet;
 import android.util.AttributeSet;
@@ -768,6 +769,7 @@
         Rect endRect = new Rect();
         thumbnailView.getGlobalVisibleRect(endRect);
         Rect appBounds = appTarget.sourceContainerBounds;
+        RectF currentAppRect = new RectF();
 
         SyncRtSurfaceTransactionApplierCompat surfaceApplier =
                 new SyncRtSurfaceTransactionApplierCompat(this);
@@ -810,17 +812,30 @@
 
             @Override
             public void onUpdate(float percent) {
-                appMatrix.preScale(mScaleX.value, mScaleY.value,
+                Matrix m = new Matrix();
+                m.preScale(mScaleX.value, mScaleY.value,
                         appBounds.width() / 2.0f, appBounds.height() / 2.0f);
-                appMatrix.postTranslate(mTranslationX.value, mTranslationY.value);
-
+                m.postTranslate(mTranslationX.value, mTranslationY.value);
+                appMatrix.preConcat(m);
                 params[1] = new SurfaceParams(appTarget.leash, mAlpha.value, appMatrix,
                         null /* windowCrop */, getLayer(appTarget, boostedMode),
                         0 /* cornerRadius */);
                 surfaceApplier.scheduleApply(params);
+
+                m.mapRect(currentAppRect, new RectF(appBounds));
+                setViewToRect(thumbnailView, new RectF(endRect), currentAppRect);
                 appMatrix.reset();
             }
         });
+        remoteAppAnim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                thumbnailView.setTranslationY(0);
+                thumbnailView.setTranslationX(0);
+                thumbnailView.setScaleX(1);
+                thumbnailView.setScaleY(1);
+            }
+        });
         anim.play(remoteAppAnim);
     }
 
@@ -886,6 +901,27 @@
         }
     }
 
+    /**
+     * Set view properties so that the view fits to the target rect.
+     *
+     * @param view view to set
+     * @param origRect original rect that view was located
+     * @param targetRect rect to set to
+     */
+    private void setViewToRect(View view, RectF origRect, RectF targetRect) {
+        float dX = targetRect.left - origRect.left;
+        float dY = targetRect.top - origRect.top;
+        view.setTranslationX(dX);
+        view.setTranslationY(dY);
+
+        float scaleX = targetRect.width() / origRect.width();
+        float scaleY = targetRect.height() / origRect.height();
+        view.setPivotX(0);
+        view.setPivotY(0);
+        view.setScaleX(scaleX);
+        view.setScaleY(scaleY);
+    }
+
     @Override
     public void setInsets(Rect insets) {
         mInsets = insets;
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
index 6358109..7a6cd2d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
@@ -43,9 +43,11 @@
 public class FlingAndHoldTouchController extends PortraitStatesTouchController {
 
     private static final long PEEK_ANIM_DURATION = 100;
+    private static final float MAX_DISPLACEMENT_PERCENT = 0.75f;
 
     private final MotionPauseDetector mMotionPauseDetector;
     private final float mMotionPauseMinDisplacement;
+    private final float mMotionPauseMaxDisplacement;
 
     private AnimatorSet mPeekAnim;
 
@@ -53,6 +55,7 @@
         super(l, false /* allowDragToOverview */);
         mMotionPauseDetector = new MotionPauseDetector(l);
         mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
+        mMotionPauseMaxDisplacement = getShiftRange() * MAX_DISPLACEMENT_PERCENT;
     }
 
     @Override
@@ -101,7 +104,9 @@
 
     @Override
     public boolean onDrag(float displacement, MotionEvent event) {
-        mMotionPauseDetector.setDisallowPause(-displacement < mMotionPauseMinDisplacement);
+        float upDisplacement = -displacement;
+        mMotionPauseDetector.setDisallowPause(upDisplacement < mMotionPauseMinDisplacement
+                || upDisplacement > mMotionPauseMaxDisplacement);
         mMotionPauseDetector.addPosition(displacement, event.getEventTime());
         return super.onDrag(displacement, event);
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 7ad7b74..a296975 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -114,7 +114,7 @@
                         "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
                         ++attempts <= MAX_SCROLL_ATTEMPTS);
 
-                mLauncher.scrollWithModelTime(allAppsContainer, Direction.UP, 1, margins, 50);
+                mLauncher.scroll(allAppsContainer, Direction.UP, 1, margins, 50);
             }
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) {
@@ -134,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);
-            mLauncher.scrollWithModelTime(allAppsContainer, Direction.DOWN, pct, null, 10);
+            mLauncher.scroll(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();
@@ -151,7 +151,7 @@
                      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.
-            mLauncher.scrollWithModelTime(
+            mLauncher.scroll(
                     allAppsContainer, Direction.DOWN, 1, new Rect(0, 0, 0, mHeight / 2), 10);
             verifyActiveContainer();
         }
@@ -165,7 +165,7 @@
                      mLauncher.addContextLayer("want to fling backward in all apps")) {
             final UiObject2 allAppsContainer = verifyActiveContainer();
             // Start the gesture in the center, for symmetry with forward.
-            mLauncher.scrollWithModelTime(
+            mLauncher.scroll(
                     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 6801931..ec62188 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -365,10 +365,10 @@
                         ? NORMAL_STATE_ORDINAL : BACKGROUND_APP_STATE_ORDINAL;
                 final Point displaySize = getRealDisplaySize();
 
-                swipeWithModelTime(
+                swipeToState(
                         displaySize.x / 2, displaySize.y - 1,
                         displaySize.x / 2, 0,
-                        finalState, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
+                        ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, finalState);
             }
         } else {
             log(action = "clicking home button");
@@ -532,6 +532,14 @@
     }
 
     @NonNull
+    UiObject2 waitForLauncherObjectByClass(String clazz) {
+        final BySelector selector = getLauncherObjectSelectorByClass(clazz);
+        final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
+        assertNotNull("Can't find a launcher object; selector: " + selector, object);
+        return object;
+    }
+
+    @NonNull
     UiObject2 waitForFallbackLauncherObject(String resName) {
         final BySelector selector = getFallbackLauncherObjectSelector(resName);
         final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
@@ -543,6 +551,10 @@
         return By.res(getLauncherPackageName(), resName);
     }
 
+    BySelector getLauncherObjectSelectorByClass(String clazz) {
+        return By.pkg(getLauncherPackageName()).clazz(clazz);
+    }
+
     BySelector getFallbackLauncherObjectSelector(String resName) {
         return By.res(getOverviewPackageName(), resName);
     }
@@ -565,14 +577,12 @@
                 () -> mDevice.swipe(startX, startY, endX, endY, steps));
     }
 
-    void swipeWithModelTime(
-            int startX, int startY, int endX, int endY, int expectedState, int steps) {
+    void swipeToState(int startX, int startY, int endX, int endY, int steps, int expectedState) {
         changeStateViaGesture(startX, startY, endX, endY, expectedState,
-                () -> swipeWithModelTime(startX, startY, endX, endY, steps));
+                () -> linearGesture(startX, startY, endX, endY, steps));
     }
 
-    void scrollWithModelTime(
-            UiObject2 container, Direction direction, float percent, Rect margins, int steps) {
+    void scroll(UiObject2 container, Direction direction, float percent, Rect margins, int steps) {
         final Rect rect = container.getVisibleBounds();
         if (margins != null) {
             rect.left += margins.left;
@@ -609,7 +619,7 @@
         }
 
         executeAndWaitForEvent(
-                () -> swipeWithModelTime(startX, startY, endX, endY, steps),
+                () -> linearGesture(startX, startY, endX, endY, steps),
                 event -> TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName()),
                 "Didn't receive a scroll end message: " + startX + ", " + startY
                         + ", " + endX + ", " + endY);
@@ -617,7 +627,7 @@
 
     // 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) {
+    private void linearGesture(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);
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index e625510..ec99d26 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -49,13 +49,14 @@
                 "want to switch from overview to all apps")) {
             verifyActiveContainer();
 
-            // Swipe from the prediction row to the top.
+            // Swipe from an app icon to the top.
             LauncherInstrumentation.log("Overview.switchToAllApps before swipe");
-            final UiObject2 predictionRow = mLauncher.waitForLauncherObject("prediction_row");
-            mLauncher.swipe(mLauncher.getDevice().getDisplayWidth() / 2,
-                    predictionRow.getVisibleBounds().centerY(),
+            final UiObject2 appIcon = mLauncher.waitForLauncherObjectByClass(
+                    "android.widget.TextView");
+            mLauncher.swipeToState(mLauncher.getDevice().getDisplayWidth() / 2,
+                    appIcon.getVisibleBounds().centerY(),
                     mLauncher.getDevice().getDisplayWidth() / 2,
-                    0, ALL_APPS_STATE_ORDINAL);
+                    0, 50, ALL_APPS_STATE_ORDINAL);
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "swiped all way up from overview")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index c0bafa2..3cab1a1 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -65,13 +65,14 @@
             LauncherInstrumentation.log(
                     "switchToAllApps: swipeHeight = " + swipeHeight + ", slop = "
                             + mLauncher.getTouchSlop());
-            mLauncher.swipe(
+
+            mLauncher.swipeToState(
                     start.x,
                     start.y,
                     start.x,
                     start.y - swipeHeight - mLauncher.getTouchSlop(),
-                    ALL_APPS_STATE_ORDINAL
-            );
+                    60,
+                    ALL_APPS_STATE_ORDINAL);
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "swiped to all apps")) {