Merge "Reading navigation_bar_gesture_height for bottom swipe region" into ub-launcher3-qt-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 2ff5c0c..bbc6eb3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -170,7 +170,8 @@
             STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
 
     public enum GestureEndTarget {
-        HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE, false),
+        HOME(1, STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT, true, false,
+                ContainerType.WORKSPACE, false),
 
         RECENTS(1, STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT
                 | STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER, true),
@@ -331,9 +332,8 @@
                         | STATE_SCALED_CONTROLLER_RECENTS,
                 this::finishCurrentTransitionToRecents);
 
-        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_COMPLETED
-                        | STATE_SCALED_CONTROLLER_HOME | STATE_APP_CONTROLLER_RECEIVED
-                        | STATE_LAUNCHER_DRAWN,
+        mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED
+                        | STATE_SCALED_CONTROLLER_HOME,
                 this::finishCurrentTransitionToHome);
         mStateCallback.addCallback(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED,
                 this::reset);
@@ -1251,7 +1251,14 @@
                 if (mTaskSnapshot == null) {
                     mTaskSnapshot = controller.screenshotTask(mRunningTaskId);
                 }
-                TaskView taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot);
+                final TaskView taskView;
+                if (mGestureEndTarget == HOME) {
+                    // Capture the screenshot before finishing the transition to home to ensure it's
+                    // taken in the correct orientation, but no need to update the thumbnail.
+                    taskView = null;
+                } else {
+                    taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot);
+                }
                 if (taskView != null) {
                     // Defer finishing the animation until the next launcher frame with the
                     // new thumbnail
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
index 3f4ad58..77dc6f3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -16,26 +16,22 @@
 package com.android.quickstep.util;
 
 import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
 import android.content.res.Resources;
 import android.graphics.PointF;
 import android.graphics.RectF;
-import android.util.FloatProperty;
 
 import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
 import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.FlingSpringAnim;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
 
 /**
  * Applies spring forces to animate from a starting rect to a target rect,
@@ -43,14 +39,6 @@
  */
 public class RectFSpringAnim {
 
-    /**
-     * Although the rect position animation takes an indefinite amount of time since it depends on
-     * the initial velocity and applied forces, scaling from the starting rect to the target rect
-     * can be done in parallel at a fixed duration. Update callbacks are sent based on the progress
-     * of this animation, while the end callback is sent after all animations finish.
-     */
-    private static final long RECT_SCALE_DURATION = 250;
-
     private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_X =
             new FloatPropertyCompat<RectFSpringAnim>("rectCenterXSpring") {
                 @Override
@@ -79,17 +67,17 @@
                 }
             };
 
-    private static final FloatProperty<RectFSpringAnim> RECT_SCALE_PROGRESS =
-            new FloatProperty<RectFSpringAnim>("rectScaleProgress") {
+    private static final FloatPropertyCompat<RectFSpringAnim> RECT_SCALE_PROGRESS =
+            new FloatPropertyCompat<RectFSpringAnim>("rectScaleProgress") {
                 @Override
-                public Float get(RectFSpringAnim anim) {
-                    return anim.mCurrentScaleProgress;
+                public float getValue(RectFSpringAnim object) {
+                    return object.mCurrentScaleProgress;
                 }
 
                 @Override
-                public void setValue(RectFSpringAnim anim, float currentScaleProgress) {
-                    anim.mCurrentScaleProgress = currentScaleProgress;
-                    anim.onUpdate();
+                public void setValue(RectFSpringAnim object, float value) {
+                    object.mCurrentScaleProgress = value;
+                    object.onUpdate();
                 }
             };
 
@@ -106,7 +94,7 @@
     private float mCurrentScaleProgress;
     private FlingSpringAnim mRectXAnim;
     private FlingSpringAnim mRectYAnim;
-    private ValueAnimator mRectScaleAnim;
+    private SpringAnimation mRectScaleAnim;
     private boolean mAnimsStarted;
     private boolean mRectXAnimEnded;
     private boolean mRectYAnimEnded;
@@ -177,17 +165,18 @@
         mRectYAnim = new FlingSpringAnim(this, RECT_Y, startY, endY, startVelocityY,
                 mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);
 
-        mRectScaleAnim = ObjectAnimator.ofPropertyValuesHolder(this,
-                PropertyValuesHolder.ofFloat(RECT_SCALE_PROGRESS, 1))
-                .setDuration(RECT_SCALE_DURATION);
-        mRectScaleAnim.setInterpolator(DEACCEL);
-        mRectScaleAnim.addListener(new AnimationSuccessListener() {
-            @Override
-            public void onAnimationSuccess(Animator animator) {
-                mRectScaleAnimEnded = true;
-                maybeOnEnd();
-            }
-        });
+        float minVisibleChange = 1f / mStartRect.height();
+        mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
+                .setSpring(new SpringForce(1f)
+                .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+                .setStiffness(SpringForce.STIFFNESS_LOW))
+                .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
+                .setMaxValue(1f)
+                .setMinimumVisibleChange(minVisibleChange)
+                .addEndListener((animation, canceled, value, velocity) -> {
+                    mRectScaleAnimEnded = true;
+                    maybeOnEnd();
+                });
 
         mRectXAnim.start();
         mRectYAnim.start();
@@ -202,7 +191,9 @@
         if (mAnimsStarted) {
             mRectXAnim.end();
             mRectYAnim.end();
-            mRectScaleAnim.end();
+            if (mRectScaleAnim.canSkipToEnd()) {
+                mRectScaleAnim.skipToEnd();
+            }
         }
     }
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 43d6311..f02859f 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -127,7 +127,7 @@
         assertNotNull("OverviewTask.open returned null", task.open());
         assertTrue("Test activity didn't open from Overview", mDevice.wait(Until.hasObject(
                 By.pkg(getAppPackageName()).text("TestActivity2")),
-                LONG_WAIT_TIME_MS));
+                DEFAULT_UI_TIMEOUT));
         executeOnLauncher(launcher -> assertTrue(
                 "Launcher activity is the top activity; expecting another activity to be the top "
                         + "one",
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 75ff66e..61c7306 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -184,5 +184,13 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity-alias>
+        <activity-alias android:name="Activity11"
+                        android:label="TestActivity11"
+                        android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity-alias>
     </application>
 </manifest>
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index b4355ae..a19857c 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -91,7 +91,6 @@
 
     public static final long SHORT_UI_TIMEOUT = 300;
     public static final long DEFAULT_UI_TIMEOUT = 10000;
-    protected static final int LONG_WAIT_TIME_MS = 60000;
     private static final String TAG = "AbstractLauncherUiTest";
     private static int sScreenshotCount = 0;
 
@@ -394,7 +393,7 @@
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         instrumentation.getTargetContext().startActivity(intent);
         assertTrue(packageName + " didn't start",
-                mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), LONG_WAIT_TIME_MS));
+                mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), DEFAULT_UI_TIMEOUT));
     }
 
     protected void startTestActivity(int activityNumber) {
@@ -410,7 +409,7 @@
         assertTrue(packageName + " didn't start",
                 mDevice.wait(
                         Until.hasObject(By.pkg(packageName).text("TestActivity" + activityNumber)),
-                        LONG_WAIT_TIME_MS));
+                        DEFAULT_UI_TIMEOUT));
     }
 
     protected static String resolveSystemApp(String category) {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index a4711f5..7978c79 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -115,7 +115,7 @@
     private static final String APPS_RES_ID = "apps_view";
     private static final String OVERVIEW_RES_ID = "overview_panel";
     private static final String WIDGETS_RES_ID = "widgets_list_view";
-    public static final int WAIT_TIME_MS = 60000;
+    public static final int WAIT_TIME_MS = 10000;
     private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
 
     private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null);
@@ -541,25 +541,22 @@
 
     @NonNull
     UiObject2 waitForLauncherObject(String resName) {
-        final BySelector selector = getLauncherObjectSelector(resName);
-        final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
-        assertNotNull("Can't find a launcher object; selector: " + selector, object);
-        return object;
+        return waitForObjectBySelector(getLauncherObjectSelector(resName));
     }
 
     @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;
+        return waitForObjectBySelector(getLauncherObjectSelectorByClass(clazz));
     }
 
     @NonNull
     UiObject2 waitForFallbackLauncherObject(String resName) {
-        final BySelector selector = getFallbackLauncherObjectSelector(resName);
+        return waitForObjectBySelector(getFallbackLauncherObjectSelector(resName));
+    }
+
+    private UiObject2 waitForObjectBySelector(BySelector selector) {
         final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
-        assertNotNull("Can't find a fallback launcher object; selector: " + selector, object);
+        assertNotNull("Can't find a launcher object; selector: " + selector, object);
         return object;
     }