Merge "Trigger heap dump when heap exceeds a limit" into ub-launcher3-qt-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 1c66968..d14de70 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -83,4 +83,16 @@
     public int getVisibleElements(Launcher launcher) {
         return super.getVisibleElements(launcher) & ~RECENTS_CLEAR_ALL_BUTTON;
     }
+
+    @Override
+    public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
+        if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
+            // Translate hotseat offscreen if we show it in overview.
+            ScaleAndTranslation scaleAndTranslation = super.getHotseatScaleAndTranslation(launcher);
+            scaleAndTranslation.translationY = LayoutUtils.getShelfTrackingDistance(launcher,
+                    launcher.getDeviceProfile());
+            return scaleAndTranslation;
+        }
+        return super.getHotseatScaleAndTranslation(launcher);
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 9a99c15..5c9b200 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -127,6 +127,10 @@
             // We have no all apps content, so we're still at the fully down progress.
             return super.getVerticalProgress(launcher);
         }
+        return getDefaultVerticalProgress(launcher);
+    }
+
+    public static float getDefaultVerticalProgress(Launcher launcher) {
         return 1 - (getDefaultSwipeHeight(launcher)
                 / launcher.getAllAppsController().getShiftRange());
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 0d06c19..e7d085c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -16,7 +16,6 @@
 package com.android.quickstep;
 
 import static android.view.View.TRANSLATION_Y;
-
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.NORMAL;
@@ -62,6 +61,7 @@
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.SpringObjectAnimator;
 import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.uioverrides.states.OverviewState;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.views.FloatingIconView;
 import com.android.quickstep.SysUINavigationMode.Mode;
@@ -260,8 +260,11 @@
                 }
                 float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(activity);
                 float shelfOverviewProgress = OVERVIEW.getVerticalProgress(activity);
+                // Peek based on default overview progress so we can see hotseat if we're showing
+                // that instead of predictions in overview.
+                float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(activity);
                 float shelfPeekingProgress = shelfHiddenProgress
-                        - (shelfHiddenProgress - shelfOverviewProgress) * 0.25f;
+                        - (shelfHiddenProgress - defaultOverviewProgress) * 0.25f;
                 float toProgress = mShelfState == ShelfAnimState.HIDE
                         ? shelfHiddenProgress
                         : mShelfState == ShelfAnimState.PEEK
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
index d0ea73a..6897c1e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
@@ -29,8 +29,6 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.Utilities;
 import com.android.quickstep.util.ClipAnimationHelper;
 import com.android.quickstep.util.MultiValueUpdateListener;
@@ -123,6 +121,7 @@
                 new RemoteAnimationTargetSet(targets, MODE_OPENING);
         targetSet.addDependentTransactionApplier(applier);
 
+        final RecentsView recentsView = v.getRecentsView();
         final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
         appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
         appAnimator.addUpdateListener(new MultiValueUpdateListener() {
@@ -153,7 +152,10 @@
                 // TODO: Take into account the current fullscreen progress for animating the insets
                 params.setProgress(1 - percent);
                 RectF taskBounds = inOutHelper.applyTransform(targetSet, params);
-                if (!skipViewChanges) {
+                int taskIndex = recentsView.indexOfChild(v);
+                int centerTaskIndex = recentsView.getCurrentPage();
+                boolean parallaxCenterAndAdjacentTask = taskIndex != centerTaskIndex;
+                if (!skipViewChanges && parallaxCenterAndAdjacentTask) {
                     float scale = taskBounds.width() / mThumbnailRect.width();
                     v.setScaleX(scale);
                     v.setScaleY(scale);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
index 837423a..8f92772 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
@@ -34,11 +34,14 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
+import android.gesture.Gesture;
 import android.graphics.PointF;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
 import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
@@ -56,8 +59,7 @@
 /**
  * Touch consumer for handling events to launch assistant from launcher
  */
-public class AssistantTouchConsumer extends DelegateInputConsumer
-    implements SwipeDetector.Listener {
+public class AssistantTouchConsumer extends DelegateInputConsumer {
 
     private static final String TAG = "AssistantTouchConsumer";
     private static final long RETRACT_ANIMATION_DURATION_MS = 300;
@@ -68,7 +70,6 @@
     private static final int OPA_BUNDLE_TRIGGER_DIAG_SWIPE_GESTURE = 83;
     private static final String INVOCATION_TYPE_KEY = "invocation_type";
     private static final int INVOCATION_TYPE_GESTURE = 1;
-    private static final int INVOCATION_TYPE_FLING = 6;
 
     private final PointF mDownPos = new PointF();
     private final PointF mLastPos = new PointF();
@@ -90,7 +91,7 @@
     private final float mSquaredSlop;
     private final ISystemUiProxy mSysUiProxy;
     private final Context mContext;
-    private final SwipeDetector mSwipeDetector;
+    private final GestureDetector mGestureDetector;
 
     public AssistantTouchConsumer(Context context, ISystemUiProxy systemUiProxy,
             ActivityControlHelper activityControlHelper, InputConsumer delegate,
@@ -107,8 +108,8 @@
 
         mSquaredSlop = slop * slop;
         mActivityControlHelper = activityControlHelper;
-        mSwipeDetector = new SwipeDetector(mContext, this, SwipeDetector.VERTICAL);
-        mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false);
+
+        mGestureDetector = new GestureDetector(context, new AssistantGestureListener());
     }
 
     @Override
@@ -119,7 +120,7 @@
     @Override
     public void onMotionEvent(MotionEvent ev) {
         // TODO add logging
-        mSwipeDetector.onTouchEvent(ev);
+        mGestureDetector.onTouchEvent(ev);
 
         switch (ev.getActionMasked()) {
             case ACTION_DOWN: {
@@ -171,13 +172,8 @@
                         mStartDragPos.set(mLastPos.x, mLastPos.y);
                         mDragTime = SystemClock.uptimeMillis();
 
-                        // Determine if angle is larger than threshold for assistant detection
-                        float angle = (float) Math.toDegrees(
-                            Math.atan2(mDownPos.y - mLastPos.y, mDownPos.x - mLastPos.x));
-                        mDirection = angle > 90 ? UPLEFT : UPRIGHT;
-                        angle = angle > 90 ? 180 - angle : angle;
-
-                        if (angle > mAngleThreshold && angle < 90) {
+                        if (isValidAssistantGestureAngle(
+                            mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y)) {
                             setActive(ev);
                         } else {
                             mState = STATE_DELEGATE_ACTIVE;
@@ -261,6 +257,19 @@
         }
     }
 
+    /**
+     * Determine if angle is larger than threshold for assistant detection
+     */
+    private boolean isValidAssistantGestureAngle(float deltaX, float deltaY) {
+        float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
+        mDirection = angle > 90 ? UPLEFT : UPRIGHT;
+
+        // normalize so that angle is measured clockwise from horizontal in the bottom right corner
+        // and counterclockwise from horizontal in the bottom left corner
+        angle = angle > 90 ? 180 - angle : angle;
+        return (angle > mAngleThreshold && angle < 90);
+    }
+
     public static boolean withinTouchRegion(Context context, MotionEvent ev) {
         final Resources res = context.getResources();
         final int width = res.getDisplayMetrics().widthPixels;
@@ -269,32 +278,28 @@
         return (ev.getX() > width - size || ev.getX() < size) && ev.getY() > height - size;
     }
 
-    @Override
-    public void onDragStart(boolean start) {
-        // do nothing
-    }
+    private class AssistantGestureListener extends SimpleOnGestureListener {
+        @Override
+        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+            if (isValidAssistantGestureAngle(velocityX, -velocityY)
+                && !mLaunchedAssistant && mState != STATE_DELEGATE_ACTIVE) {
+                mLastProgress = 1;
+                try {
+                    mSysUiProxy.onAssistantGestureCompletion(
+                        (float) Math.sqrt(velocityX * velocityX + velocityY * velocityY));
+                    startAssistantInternal(FLING);
 
-    @Override
-    public boolean onDrag(float displacement) {
-        return false;
-    }
-
-    @Override
-    public void onDragEnd(float velocity, boolean fling) {
-        if (fling && !mLaunchedAssistant && mState != STATE_DELEGATE_ACTIVE) {
-            mLastProgress = 1;
-            try {
-                mSysUiProxy.onAssistantGestureCompletion(velocity);
-                startAssistantInternal(FLING);
-
-                Bundle args = new Bundle();
-                args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
-                mSysUiProxy.startAssistant(args);
-                mLaunchedAssistant = true;
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to send SysUI start/send assistant progress: " + mLastProgress,
-                    e);
+                    Bundle args = new Bundle();
+                    args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
+                    mSysUiProxy.startAssistant(args);
+                    mLaunchedAssistant = true;
+                } catch (RemoteException e) {
+                    Log.w(TAG,
+                        "Failed to send SysUI start/send assistant progress: " + mLastProgress,
+                        e);
+                }
             }
+            return true;
         }
     }
 }
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 5b2e27e..03441c8 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
@@ -33,9 +33,11 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Hotseat;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.LauncherStateManager.StateListener;
@@ -250,4 +252,16 @@
             setDisallowScrollToClearAll(!hasClearAllButton);
         }
     }
+
+    @Override
+    protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            // Allow touches to go through to the hotseat.
+            Hotseat hotseat = mActivity.getHotseat();
+            boolean touchingHotseat = hotseat.isShown()
+                    && mActivity.getDragLayer().isEventOverView(hotseat, ev, this);
+            return !touchingHotseat;
+        }
+        return super.shouldStealTouchFromSiblingsBelow(ev);
+    }
 }
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 9058e7e..a8987a3 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
@@ -521,6 +521,10 @@
 
 
         // Do not let touch escape to siblings below this view.
+        return isHandlingTouch() || shouldStealTouchFromSiblingsBelow(ev);
+    }
+
+    protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) {
         return true;
     }
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 80ea78f..ad2783e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -430,6 +430,10 @@
         super.onConfigurationChanged(newConfig);
     }
 
+    public void reload() {
+        onIdpChanged(mDeviceProfile.inv);
+    }
+
     private boolean supportsFakeLandscapeUI() {
         return FeatureFlags.FAKE_LANDSCAPE_UI.get() && !mRotationHelper.homeScreenCanRotate();
     }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index ac392a6..d79f5d5 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -301,7 +301,8 @@
                 }
             }
         } else if (IS_DOGFOOD_BUILD && ACTION_FORCE_ROLOAD.equals(action)) {
-            forceReload();
+            Launcher l = (Launcher) getCallback();
+            l.reload();
         }
     }
 
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 8b03691..4425e2a 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -223,6 +223,7 @@
     }
 
     public void reapplyState(boolean cancelCurrentAnimation) {
+        boolean wasInAnimation = mConfig.mCurrentAnimation != null;
         if (cancelCurrentAnimation) {
             cancelAnimation();
         }
@@ -230,6 +231,9 @@
             for (StateHandler handler : getStateHandlers()) {
                 handler.setState(mState);
             }
+            if (wasInAnimation) {
+                onStateTransitionEnd(mState);
+            }
         }
     }
 
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 80e17c9..dfa3e1b 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1204,6 +1204,7 @@
                     if (((initialScrollX >= mMaxScrollX) && (isVelocityXLeft || !isFling)) ||
                             ((initialScrollX <= mMinScrollX) && (!isVelocityXLeft || !isFling))) {
                         mScroller.springBack(getScrollX(), mMinScrollX, mMaxScrollX);
+                        mNextPage = getPageNearestToCenterOfScreen();
                     } else {
                         mScroller.setInterpolator(mDefaultInterpolator);
                         mScroller.fling(initialScrollX, -velocityX,
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index c62fc3d..a351b9a 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -2,6 +2,8 @@
 
 import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
 import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
@@ -28,15 +30,12 @@
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.SpringObjectAnimator;
 import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.anim.SpringObjectAnimator;
 import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ScrimView;
 
-import androidx.dynamicanimation.animation.FloatPropertyCompat;
-
 /**
  * Handles AllApps view transition.
  * 1) Slides all apps view using direct manipulation
@@ -139,6 +138,15 @@
         } else {
             mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
         }
+
+        if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+            // Translate hotseat with the shelf until reaching overview.
+            float overviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
+            if (progress >= overviewProgress || mLauncher.isInState(BACKGROUND_APP)) {
+                float hotseatShift = (progress - overviewProgress) * mShiftRange;
+                mLauncher.getHotseat().setTranslationY(hotseatShift);
+            }
+        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 54d0db1..54efcb7 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -109,7 +109,7 @@
             "Show chip hints and gleams on the overview screen");
 
     public static final TogglableFlag FAKE_LANDSCAPE_UI = new TogglableFlag(
-            "FAKE_LANDSCAPE_UI", true,
+            "FAKE_LANDSCAPE_UI", false,
             "Rotate launcher UI instead of using transposed layout");
 
     public static void initialize(Context context) {
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index ac152db..51c7022 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -116,11 +116,25 @@
         mMultiValueAlpha = new MultiValueAlpha(this, alphaChannelCount);
     }
 
+    /**
+     * Same as {@link #isEventOverView(View, MotionEvent, View)} where evView == this drag layer.
+     */
     public boolean isEventOverView(View view, MotionEvent ev) {
         getDescendantRectRelativeToSelf(view, mHitRect);
         return mHitRect.contains((int) ev.getX(), (int) ev.getY());
     }
 
+    /**
+     * Given a motion event in evView's coordinates, return whether the event is within another
+     * view's bounds.
+     */
+    public boolean isEventOverView(View view, MotionEvent ev, View evView) {
+        int[] xy = new int[] {(int) ev.getX(), (int) ev.getY()};
+        getDescendantCoordRelativeToSelf(evView, xy);
+        getDescendantRectRelativeToSelf(view, mHitRect);
+        return mHitRect.contains(xy[0], xy[1]);
+    }
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         int action = ev.getAction();