Merge "Revert "Include Launcher3QuickstepLib for tapl"" into ub-launcher3-master
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index 76abe8d..96b0a9e 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -48,7 +48,7 @@
     private ShadowGenerator mShadowGenerator;
 
     private Drawable mWrapperIcon;
-    private int mWrapperBackgroundColor;
+    private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
 
     protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) {
         mContext = context.getApplicationContext();
diff --git a/quickstep/recents_ui_overrides/res/layout/hint.xml b/quickstep/recents_ui_overrides/res/layout/hint.xml
deleted file mode 100644
index 7e2d6af..0000000
--- a/quickstep/recents_ui_overrides/res/layout/hint.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-<com.android.quickstep.hints.HintView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="@dimen/chip_hint_height"
-    android:layout_gravity="center_horizontal|bottom"
-    android:paddingStart="@dimen/chip_hint_start_padding"
-    android:paddingEnd="@dimen/chip_hint_end_padding"
-    android:background="@drawable/chip_hint_background_light"
-    android:gravity="center"
-    android:layout_marginHorizontal="@dimen/chip_hint_horizontal_margin"
-    android:orientation="horizontal"
-    android:elevation="@dimen/chip_hint_elevation"
-    android:layoutDirection="ltr">
-
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="@dimen/chip_icon_size"
-        android:layout_height="@dimen/chip_icon_size"
-        android:visibility="gone"
-        android:scaleType="fitCenter"
-        android:adjustViewBounds="true"
-        android:contentDescription="@null"/>
-
-    <TextView
-        android:id="@+id/label"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/chip_text_height"
-        android:paddingTop="@dimen/chip_text_top_padding"
-        android:paddingStart="@dimen/chip_text_start_padding"
-        android:fontFamily="google-sans-medium"
-        android:textAlignment="textStart"
-        android:singleLine="true"
-        android:textColor="@color/chip_hint_foreground_color"
-        android:textSize="@dimen/chip_text_size"
-        android:ellipsize="none"
-        android:includeFontPadding="true"/>
-
-
-</com.android.quickstep.hints.HintView>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/res/layout/hint_container.xml b/quickstep/recents_ui_overrides/res/layout/hint_container.xml
index 336f63e..f8723fc 100644
--- a/quickstep/recents_ui_overrides/res/layout/hint_container.xml
+++ b/quickstep/recents_ui_overrides/res/layout/hint_container.xml
@@ -14,9 +14,10 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.quickstep.hints.HintsContainer
+<com.android.quickstep.hints.ChipsContainer
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="@dimen/chip_hint_height"
+    android:layout_gravity="bottom"
     android:gravity="center_horizontal"
     android:orientation="horizontal"/>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index 50cc4da..81ff0c7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -62,7 +62,6 @@
 
         if (swipeUpToHome) {
             list.add(new FlingAndHoldTouchController(launcher));
-            list.add(new OverviewToAllAppsTouchController(launcher));
         } else {
             if (launcher.getDeviceProfile().isVerticalBarLayout()) {
                 list.add(new OverviewToAllAppsTouchController(launcher));
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java
index e02c696..109a4c5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java
@@ -78,6 +78,11 @@
     }
 
     @Override
+    public int getType() {
+        return TYPE_ASSISTANT;
+    }
+
+    @Override
     public void onMotionEvent(MotionEvent ev) {
         // TODO add logging
         switch (ev.getActionMasked()) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/DeviceLockedInputConsumer.java
index 047f34c..d919a3e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/DeviceLockedInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/DeviceLockedInputConsumer.java
@@ -31,6 +31,11 @@
     }
 
     @Override
+    public int getType() {
+        return TYPE_DEVICE_LOCKED;
+    }
+
+    @Override
     public void onMotionEvent(MotionEvent ev) {
         // For now, just start the home intent so user is prompted to unlock the device.
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java
index 8dfb9ab..ad9fe78 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java
@@ -23,7 +23,16 @@
 
 @TargetApi(Build.VERSION_CODES.O)
 public interface InputConsumer {
-    InputConsumer NO_OP = new InputConsumer() { };
+
+    int TYPE_NO_OP = 0;
+    int TYPE_OVERVIEW = 1;
+    int TYPE_OTHER_ACTIVITY = 2;
+    int TYPE_ASSISTANT = 3;
+    int TYPE_DEVICE_LOCKED = 4;
+
+    InputConsumer NO_OP = () -> TYPE_NO_OP;
+
+    int getType();
 
     default boolean isActive() {
         return false;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
index 67bfeaa..e3afb92 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
@@ -148,6 +148,11 @@
     }
 
     @Override
+    public int getType() {
+        return TYPE_OTHER_ACTIVITY;
+    }
+
+    @Override
     public void onMotionEvent(MotionEvent ev) {
         if (mVelocityTracker == null) {
             return;
@@ -225,7 +230,7 @@
                             mTouchSlop) {
                         mPassedTouchSlop = true;
 
-                        TOUCH_INTERACTION_LOG.startQuickStep();
+                        TOUCH_INTERACTION_LOG.addLog("startQuickstep");
                         if (mIsDeferredDownTarget) {
                             // Deferred gesture, start the animation and gesture tracking once
                             // we pass the actual touch slop
@@ -288,7 +293,7 @@
     }
 
     private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
-        TOUCH_INTERACTION_LOG.startRecentsAnimation();
+        TOUCH_INTERACTION_LOG.addLog("startRecentsAnimation");
 
         RecentsAnimationListenerSet listenerSet = mSwipeSharedState.getActiveListener();
         final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler(
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java
index 28c4db4..cce5cb3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java
@@ -60,6 +60,11 @@
     }
 
     @Override
+    public int getType() {
+        return TYPE_OVERVIEW;
+    }
+
+    @Override
     public void onMotionEvent(MotionEvent ev) {
         if (mInvalidated) {
             return;
@@ -120,7 +125,7 @@
             OverviewCallbacks.get(mActivity).closeAllWindows();
             ActivityManagerWrapper.getInstance()
                     .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
-            TOUCH_INTERACTION_LOG.startQuickStep();
+            TOUCH_INTERACTION_LOG.addLog("startQuickstep");
         }
 
         mTrackingStarted = true;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionLog.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionLog.java
deleted file mode 100644
index 4b660d4..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionLog.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2017 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;
-
-import android.view.MotionEvent;
-import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.LinkedList;
-
-/**
- * Keeps track of debugging logs for a particular quickstep gesture.
- */
-public class TouchInteractionLog {
-
-    // The number of gestures to log
-    private static final int MAX_NUM_LOG_GESTURES = 5;
-
-    private final Calendar mCalendar = Calendar.getInstance();
-    private final SimpleDateFormat mDateFormat = new SimpleDateFormat("MMM dd - kk:mm:ss:SSS");
-    private final LinkedList<ArrayList<String>> mGestureLogs = new LinkedList<>();
-
-    public void prepareForNewGesture() {
-        mGestureLogs.add(new ArrayList<>());
-        while (mGestureLogs.size() > MAX_NUM_LOG_GESTURES) {
-            mGestureLogs.pop();
-        }
-        getCurrentLog().add("[" + mDateFormat.format(mCalendar.getTime()) + "]");
-    }
-
-    public void setInputConsumer(InputConsumer consumer) {
-        getCurrentLog().add("tc=" + consumer.getClass().getSimpleName());
-    }
-
-    public void addMotionEvent(MotionEvent event) {
-        getCurrentLog().add("ev=" + event.getActionMasked());
-    }
-
-    public void startQuickStep() {
-        getCurrentLog().add("qstStart");
-    }
-
-    public void startRecentsAnimation() {
-        getCurrentLog().add("raStart");
-    }
-
-    public void startRecentsAnimationCallback(int numTargets) {
-        getCurrentLog().add("raStartCb=" + numTargets);
-    }
-
-    public void cancelRecentsAnimation() {
-        getCurrentLog().add("raCancel");
-    }
-
-    public void finishRecentsAnimation(boolean toHome) {
-        getCurrentLog().add("raFinish=" + toHome);
-    }
-
-    public void dump(PrintWriter pw) {
-        pw.println("TouchInteractionLog {");
-        for (ArrayList<String> gesture : mGestureLogs) {
-            pw.print("    ");
-            for (String log : gesture) {
-                pw.print(log + " ");
-            }
-            pw.println();
-        }
-        pw.println("}");
-    }
-
-    private ArrayList<String> getCurrentLog() {
-        return mGestureLogs.getLast();
-    }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index d1d0e86..a3c3ff9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -45,6 +45,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.logging.EventLogArray;
 import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.util.UiThreadHelper;
 import com.android.systemui.shared.recents.IOverviewProxy;
@@ -70,7 +71,8 @@
     public static final LooperExecutor BACKGROUND_EXECUTOR =
             new LooperExecutor(UiThreadHelper.getBackgroundLooper());
 
-    public static final TouchInteractionLog TOUCH_INTERACTION_LOG = new TouchInteractionLog();
+    public static final EventLogArray TOUCH_INTERACTION_LOG =
+            new EventLogArray("touch_interaction_log", 40);
 
     public static final int EDGE_NAV_BAR = 1 << 8;
 
@@ -281,15 +283,13 @@
             return;
         }
         MotionEvent event = (MotionEvent) ev;
+        TOUCH_INTERACTION_LOG.addLog("onMotionEvent", event.getActionMasked());
         if (event.getAction() == ACTION_DOWN) {
-            TOUCH_INTERACTION_LOG.prepareForNewGesture();
             boolean useSharedState = mConsumer.isActive();
             mConsumer.onConsumerAboutToBeSwitched();
             mConsumer = newConsumer(useSharedState, event);
-            TOUCH_INTERACTION_LOG.setInputConsumer(mConsumer);
+            TOUCH_INTERACTION_LOG.addLog("setInputConsumer", mConsumer.getType());
         }
-        TOUCH_INTERACTION_LOG.addMotionEvent(event);
-
         mConsumer.onMotionEvent(event);
     }
 
@@ -342,6 +342,6 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        TOUCH_INTERACTION_LOG.dump(pw);
+        TOUCH_INTERACTION_LOG.dump("", pw);
     }
 }
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 fa827e7..7dc58a5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -671,7 +671,7 @@
         initTransitionEndpoints(dp);
 
         mRecentsAnimationWrapper.setController(targetSet);
-        TOUCH_INTERACTION_LOG.startRecentsAnimationCallback(targetSet.apps.length);
+        TOUCH_INTERACTION_LOG.addLog("startRecentsAnimationCallback", targetSet.apps.length);
         setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
 
         mPassedOverviewThreshold = false;
@@ -682,7 +682,7 @@
         mRecentsAnimationWrapper.setController(null);
         mActivityInitListener.unregister();
         setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
-        TOUCH_INTERACTION_LOG.cancelRecentsAnimation();
+        TOUCH_INTERACTION_LOG.addLog("cancelRecentsAnimation");
     }
 
     @UiThread
@@ -1025,7 +1025,7 @@
     @UiThread
     private void resumeLastTask() {
         mRecentsAnimationWrapper.finish(false /* toRecents */, null);
-        TOUCH_INTERACTION_LOG.finishRecentsAnimation(false);
+        TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false);
     }
 
     @UiThread
@@ -1043,7 +1043,7 @@
                         mMainThreadHandler);
             });
         }
-        TOUCH_INTERACTION_LOG.finishRecentsAnimation(false);
+        TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false);
         doLogGesture(NEW_TASK);
     }
 
@@ -1152,7 +1152,7 @@
                         () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
             }
         }
-        TOUCH_INTERACTION_LOG.finishRecentsAnimation(true);
+        TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", true);
     }
 
     private void finishCurrentTransitionToHome() {
@@ -1160,7 +1160,7 @@
             mRecentsAnimationWrapper.finish(true /* toRecents */,
                     () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
         }
-        TOUCH_INTERACTION_LOG.finishRecentsAnimation(true);
+        TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", true);
         doLogGesture(HOME);
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/ChipsContainer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/ChipsContainer.java
new file mode 100644
index 0000000..8fc89f2
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/ChipsContainer.java
@@ -0,0 +1,72 @@
+/*
+ * 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.hints;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.view.View;
+import android.widget.FrameLayout;
+
+public class ChipsContainer extends FrameLayout {
+
+    private static final String TAG = "ChipsContainer";
+
+    public static final FloatProperty<ChipsContainer> HINT_VISIBILITY =
+            new FloatProperty<ChipsContainer>("hint_visibility") {
+                @Override
+                public void setValue(ChipsContainer chipsContainer, float v) {
+                    chipsContainer.setHintVisibility(v);
+                }
+
+                @Override
+                public Float get(ChipsContainer chipsContainer) {
+                    return chipsContainer.mHintVisibility;
+                }
+            };
+
+    private float mHintVisibility;
+
+    public ChipsContainer(Context context) {
+        super(context);
+    }
+
+    public ChipsContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public ChipsContainer(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public ChipsContainer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public void setView(View v) {
+        removeAllViews();
+        addView(v);
+    }
+
+    public void setHintVisibility(float v) {
+        if (v == 1) {
+            setVisibility(VISIBLE);
+        } else {
+            setVisibility(GONE);
+        }
+        mHintVisibility = v;
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintsContainer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintsContainer.java
deleted file mode 100644
index 22b1217..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintsContainer.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * 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.hints;
-
-import static com.android.quickstep.hints.UiHintListenerConstants.HINTS_KEY;
-import static com.android.quickstep.hints.UiHintListenerConstants.ON_HINTS_RETURNED_CODE;
-import static com.android.quickstep.hints.UiInterfaceConstants.REQUEST_HINTS_CODE;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.util.AttributeSet;
-import android.util.FloatProperty;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.widget.LinearLayout;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.R;
-
-import java.util.ArrayList;
-
-public class HintsContainer extends LinearLayout {
-
-    private static final String TAG = "HintsView";
-
-    public static final FloatProperty<HintsContainer> HINT_VISIBILITY =
-            new FloatProperty<HintsContainer>("hint_visibility") {
-                @Override
-                public void setValue(HintsContainer hintsContainer, float v) {
-                    hintsContainer.setHintVisibility(v);
-                }
-
-                @Override
-                public Float get(HintsContainer hintsContainer) {
-                    return hintsContainer.mHintVisibility;
-                }
-            };
-
-    private static Intent mServiceIntent =
-            new Intent("com.android.systemui.action.UI_PULL_INTERFACE")
-                    .setClassName(
-                            "com.android.systemui.navbarhint",
-                            "com.android.systemui.navbarhint.service.HintService");
-
-    @Nullable
-    private Messenger mHintServiceInterface;
-    private UiHintListener mUiHintListener;
-    private boolean mBound = false;
-    private float mHintVisibility;
-
-    private final ServiceConnection mServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
-            mHintServiceInterface = new Messenger(iBinder);
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName componentName) {
-            mHintServiceInterface = null;
-            attemptBinding();
-        }
-
-        @Override
-        public void onBindingDied(ComponentName componentName) {
-            mHintServiceInterface = null;
-            attemptBinding();
-        }
-    };
-
-    public HintsContainer(Context context) {
-        super(context);
-    }
-
-    public HintsContainer(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public HintsContainer(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    public HintsContainer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (mUiHintListener == null) {
-            mUiHintListener = new UiHintListener(this);
-        }
-        if (!mBound) {
-            attemptBinding();
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (mBound) {
-            getContext().unbindService(mServiceConnection);
-            mBound = false;
-        }
-        super.onDetachedFromWindow();
-    }
-
-    public void setHintVisibility(float v) {
-        if (v == 1) {
-            getHints();
-            setVisibility(VISIBLE);
-        } else {
-            setVisibility(GONE);
-        }
-        mHintVisibility = v;
-    }
-
-    private void attemptBinding() {
-        if (mBound) {
-            getContext().unbindService(mServiceConnection);
-            mBound = false;
-        }
-        boolean success = getContext().bindService(mServiceIntent,
-                mServiceConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
-        if (success) {
-            mBound = true;
-        } else {
-            Log.w(TAG, "Binding to hint supplier failed");
-        }
-    }
-    
-    private void sendOnHintTap(Bundle hint) {
-        if (mHintServiceInterface != null) {
-            Message msg = Message.obtain(null, UiInterfaceConstants.ON_HINT_TAP_CODE);
-            Bundle data = new Bundle();
-            data.putString(UiInterfaceConstants.HINT_ID_KEY, HintUtil.getId(hint));
-            data.putInt(UiInterfaceConstants.WIDTH_PX_KEY, getWidth());
-            data.putInt(UiInterfaceConstants.HEIGHT_PX_KEY, getHeight());
-            data.putInt(UiInterfaceConstants.HINT_SPACE_WIDTH_PX_KEY, 0);
-            data.putInt(UiInterfaceConstants.HINT_SPACE_HEIGHT_PX_KEY, 0);
-            msg.setData(data);
-            try {
-                mHintServiceInterface.send(msg);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to send hint tap", e);
-            }
-        }
-    }
-
-    private void getHints() {
-        if (mHintServiceInterface != null) {
-            try {
-                Message m = Message.obtain(null, REQUEST_HINTS_CODE);
-                m.replyTo = new Messenger(mUiHintListener);
-                mHintServiceInterface.send(m);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to send message", e);
-            }
-        }
-    }
-
-    private static class UiHintListener extends Handler {
-        private HintsContainer mView;
-
-        UiHintListener(HintsContainer v) {
-            mView = v;
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case ON_HINTS_RETURNED_CODE:
-                    handleHints(msg);
-                    break;
-                default:
-                    Log.e(TAG, "UiPullInterface got unrecognized code: " + msg.what);
-                    break;
-            }
-        }
-
-        private void handleHints(Message msg) {
-            Bundle bundle = msg.getData();
-            ArrayList<Bundle> hints = bundle.getParcelableArrayList(HINTS_KEY);
-
-            if (hints != null) {
-                mView.removeAllViews();
-
-                for (Bundle hint : hints) {
-                    HintView h = (HintView) LayoutInflater.from(mView.getContext()).inflate(
-                            R.layout.hint, mView, false);
-                    h.setHint(hint);
-                    h.setOnClickListener((v) -> mView.sendOnHintTap(hint));
-                    mView.addView(h);
-                }
-            }
-        }
-    }
-}
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 88fe2ee..97bce5e 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
@@ -42,9 +42,10 @@
 import com.android.launcher3.R;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.util.PendingAnimation;
+import com.android.launcher3.views.BaseDragLayer;
 import com.android.launcher3.views.ScrimView;
 import com.android.quickstep.OverviewInteractionState;
-import com.android.quickstep.hints.HintsContainer;
+import com.android.quickstep.hints.ChipsContainer;
 import com.android.quickstep.util.ClipAnimationHelper;
 import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
 import com.android.quickstep.util.LayoutUtils;
@@ -77,7 +78,7 @@
     private float mTranslationYFactor;
 
     private final TransformParams mTransformParams = new TransformParams();
-    private HintsContainer mHintsContainer;
+    private ChipsContainer mChipsContainer;
 
     public LauncherRecentsView(Context context) {
         this(context, null);
@@ -111,8 +112,9 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mHintsContainer = mActivity.findViewById(R.id.hints);
-        mHintsContainer.setPadding(0, 0, 0, mActivity.getDeviceProfile().chipHintBottomMarginPx);
+        mChipsContainer = mActivity.findViewById(R.id.hints);
+        BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) mChipsContainer.getLayoutParams();
+        params.bottomMargin = mActivity.getDeviceProfile().chipHintBottomMarginPx;
     }
 
     public void setTranslationYFactor(float translationFactor) {
@@ -131,11 +133,15 @@
     }
 
     public void setHintVisibility(float v) {
-        if (mHintsContainer != null && ENABLE_HINTS_IN_OVERVIEW.get()) {
-            mHintsContainer.setHintVisibility(v);
+        if (mChipsContainer != null && ENABLE_HINTS_IN_OVERVIEW.get()) {
+            mChipsContainer.setHintVisibility(v);
         }
     }
 
+    public ChipsContainer getChipsContainer() {
+        return mChipsContainer;
+    }
+
     @Override
     public void draw(Canvas canvas) {
         maybeDrawEmptyMessage(canvas);
@@ -192,7 +198,7 @@
 
         if (ENABLE_HINTS_IN_OVERVIEW.get()) {
             anim.anim.play(ObjectAnimator.ofFloat(
-                    mHintsContainer, HintsContainer.HINT_VISIBILITY, 0));
+                    mChipsContainer, ChipsContainer.HINT_VISIBILITY, 0));
         }
 
         return anim;
@@ -206,10 +212,10 @@
 
         if (ENABLE_HINTS_IN_OVERVIEW.get()) {
             anim.anim.play(ObjectAnimator.ofFloat(
-                    mHintsContainer, HintsContainer.HINT_VISIBILITY, 0));
+                    mChipsContainer, ChipsContainer.HINT_VISIBILITY, 0));
             anim.addEndListener(onEndListener -> {
                 if (!onEndListener.isSuccess) {
-                    mHintsContainer.setHintVisibility(1);
+                    mChipsContainer.setHintVisibility(1);
                 }
             });
         }
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index f7126d0..f5e5dd3 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -39,7 +39,6 @@
     <dimen name="motion_pause_detector_speed_somewhat_fast">0.285dp</dimen>
     <dimen name="motion_pause_detector_speed_fast">0.5dp</dimen>
     <dimen name="motion_pause_detector_min_displacement">48dp</dimen>
-    <dimen name="motion_pause_detector_max_orthogonal_displacement">48dp</dimen>
 
     <!-- Launcher app transition -->
     <dimen name="content_trans_y">50dp</dimen>
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 411e593..a0ab301 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -175,7 +175,7 @@
         }
     }
 
-    public void notifySwipeUpSettingChanged(boolean swipeUpEnabled) {
+    private void notifySwipeUpSettingChanged(boolean swipeUpEnabled) {
         mUiHandler.removeMessages(MSG_SET_SWIPE_UP_ENABLED);
         mUiHandler.obtainMessage(MSG_SET_SWIPE_UP_ENABLED, swipeUpEnabled ? 1 : 0, 0).
                 sendToTarget();
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index 21d8144..8a117c8 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -40,7 +40,6 @@
     private final float mSpeedSomewhatFast;
     private final float mSpeedFast;
     private final float mMinDisplacementForPause;
-    private final float mMaxOrthogonalDisplacementForPause;
     private final Alarm mForcePauseTimeout;
 
     private Long mPreviousTime = null;
@@ -62,8 +61,6 @@
         mSpeedSomewhatFast = res.getDimension(R.dimen.motion_pause_detector_speed_somewhat_fast);
         mSpeedFast = res.getDimension(R.dimen.motion_pause_detector_speed_fast);
         mMinDisplacementForPause = res.getDimension(R.dimen.motion_pause_detector_min_displacement);
-        mMaxOrthogonalDisplacementForPause = res.getDimension(
-                R.dimen.motion_pause_detector_max_orthogonal_displacement);
         mForcePauseTimeout = new Alarm();
         mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
     }
@@ -77,7 +74,6 @@
         if (mOnMotionPauseListener != null) {
             mOnMotionPauseListener.onMotionPauseChanged(mIsPaused);
         }
-        mForcePauseTimeout.setAlarm(FORCE_PAUSE_TIMEOUT);
     }
 
     /**
@@ -94,6 +90,7 @@
         if (mFirstOrthogonalPosition == null) {
             mFirstOrthogonalPosition = orthogonalPosition;
         }
+        mForcePauseTimeout.setAlarm(FORCE_PAUSE_TIMEOUT);
         long time = SystemClock.uptimeMillis();
         if (mPreviousTime != null && mPreviousPosition != null) {
             long changeInTime = Math.max(1, time - mPreviousTime);
@@ -108,7 +105,6 @@
         }
         mPreviousTime = time;
         mPreviousPosition = position;
-        mForcePauseTimeout.setAlarm(FORCE_PAUSE_TIMEOUT);
     }
 
     private void checkMotionPaused(float velocity, float prevVelocity,
@@ -135,9 +131,11 @@
             }
         }
         boolean passedMinDisplacement = totalDisplacement.primary >= mMinDisplacementForPause;
-        boolean passedMaxOrthogonalDisplacement =
-                totalDisplacement.orthogonal >= mMaxOrthogonalDisplacementForPause;
-        isPaused &= passedMinDisplacement && !passedMaxOrthogonalDisplacement;
+        boolean isDisplacementOrthogonal = totalDisplacement.orthogonal > totalDisplacement.primary;
+        if (!passedMinDisplacement || isDisplacementOrthogonal) {
+            mForcePauseTimeout.cancelAlarm();
+            isPaused = false;
+        }
         updatePaused(isPaused);
     }
 
diff --git a/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java b/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
index 7274090..c5975a9 100644
--- a/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
+++ b/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
@@ -19,6 +19,11 @@
 import static com.android.quickstep.QuickStepOnOffRule.Mode.BOTH;
 import static com.android.quickstep.QuickStepOnOffRule.Mode.OFF;
 import static com.android.quickstep.QuickStepOnOffRule.Mode.ON;
+import static com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME;
+
+import static org.junit.Assert.assertTrue;
+
+import android.provider.Settings;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -69,38 +74,52 @@
                 @Override
                 public void evaluate() throws Throwable {
                     try {
-                        if (mode == ON || mode == BOTH) {
-                            evaluateWithQuickstepOn();
-                        }
-                        if (mode == OFF || mode == BOTH) {
-                            evaluateWithQuickstepOff();
+                        if (SwipeUpSetting.isSwipeUpSettingAvailable()) {
+                            if (mode == ON || mode == BOTH) {
+                                evaluateWithQuickstepOn();
+                            }
+                            if (mode == OFF || mode == BOTH) {
+                                evaluateWithQuickstepOff();
+                            }
+                        } else {
+                            // Execute without changing the setting, if the requested mode is
+                            // compatible.
+                            final boolean swipeUpEnabledDefaultValue =
+                                    SwipeUpSetting.isSwipeUpEnabledDefaultValue();
+                            if (mode == BOTH ||
+                                    mode == ON && swipeUpEnabledDefaultValue ||
+                                    mode == OFF && !swipeUpEnabledDefaultValue) {
+                                evaluateWithoutChangingSetting(base);
+                            }
                         }
                     } finally {
-                        overrideSwipeUpEnabled(null);
+                        setSwipeUpSetting(null);
+
                     }
                 }
 
-                private void evaluateWithQuickstepOff() throws Throwable {
-                    overrideSwipeUpEnabled(false);
+                public void setSwipeUpSetting(String value) {
+                    assertTrue("Couldn't change Quickstep mode",
+                            Settings.Secure.putString(
+                                    InstrumentationRegistry.getInstrumentation().getTargetContext().
+                                            getContentResolver(),
+                                    SWIPE_UP_SETTING_NAME,
+                                    value));
+                }
+
+                public void evaluateWithoutChangingSetting(Statement base) throws Throwable {
                     base.evaluate();
                 }
 
+                private void evaluateWithQuickstepOff() throws Throwable {
+                    setSwipeUpSetting("0");
+                    evaluateWithoutChangingSetting(base);
+                }
+
                 private void evaluateWithQuickstepOn() throws Throwable {
-                    overrideSwipeUpEnabled(true);
+                    setSwipeUpSetting("1");
                     base.evaluate();
                 }
-
-                private void overrideSwipeUpEnabled(Boolean swipeUpEnabledOverride)
-                        throws Throwable {
-                    mLauncher.overrideSwipeUpEnabled(swipeUpEnabledOverride);
-                    mMainThreadExecutor.execute(() -> OverviewInteractionState.INSTANCE.get(
-                            InstrumentationRegistry.getInstrumentation().getTargetContext()).
-                            notifySwipeUpSettingChanged(mLauncher.isSwipeUpEnabled()));
-                    // TODO(b/124236673): avoid using sleep().
-                    mLauncher.getDevice().waitForIdle();
-                    Thread.sleep(2000);
-                    mLauncher.getDevice().waitForIdle();
-                }
             };
         } else {
             return base;
diff --git a/res/drawable/horizontal_ellipsis.xml b/res/drawable/horizontal_ellipsis.xml
index ad08529..65e958d 100644
--- a/res/drawable/horizontal_ellipsis.xml
+++ b/res/drawable/horizontal_ellipsis.xml
@@ -22,6 +22,6 @@
         android:tint="?android:attr/textColorSecondary" >
 
     <path
-        android:pathData="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
+        android:pathData="M6 10c-1.1 0-2 0.9-2 2s0.9 2 2 2 2-0.9 2-2-0.9-2-2-2zm12 0c-1.1 0-2 0.9-2 2s0.9 2 2 2 2-0.9 2-2-0.9-2-2-2zm-6 0c-1.1 0-2 0.9-2 2s0.9 2 2 2 2-0.9 2-2-0.9-2-2-2z"
         android:fillColor="@android:color/white" />
 </vector>
\ No newline at end of file
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 91c3705..c9cea80 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -38,6 +38,15 @@
             android:theme="@style/HomeScreenElementTheme"
             launcher:pageIndicator="@+id/page_indicator" />
 
+        <!-- DO NOT CHANGE THE ID -->
+        <com.android.launcher3.Hotseat
+            android:id="@+id/hotseat"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:theme="@style/HomeScreenElementTheme"
+            android:importantForAccessibility="no"
+            launcher:containerType="hotseat" />
+
         <include
             android:id="@+id/overview_panel"
             layout="@layout/overview_panel"
@@ -71,15 +80,6 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent" />
 
-        <!-- DO NOT CHANGE THE ID -->
-        <com.android.launcher3.Hotseat
-            android:id="@+id/hotseat"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:theme="@style/HomeScreenElementTheme"
-            android:importantForAccessibility="no"
-            launcher:containerType="hotseat" />
-
     </com.android.launcher3.dragndrop.DragLayer>
 
 </com.android.launcher3.LauncherRootView>
diff --git a/res/layout/snackbar.xml b/res/layout/snackbar.xml
index bca3308..b818943 100644
--- a/res/layout/snackbar.xml
+++ b/res/layout/snackbar.xml
@@ -29,7 +29,7 @@
         android:ellipsize="end"
         android:textSize="@dimen/snackbar_max_text_size"
         android:textColor="?android:attr/textColorPrimary"
-        android:theme="@style/TextTitle"/>
+        style="@style/TextTitle"/>
     <TextView
         android:id="@+id/action"
         android:layout_height="@dimen/snackbar_content_height"
@@ -42,6 +42,6 @@
         android:textStyle="bold"
         android:textSize="@dimen/snackbar_max_text_size"
         android:textColor="?android:attr/colorAccent"
-        android:theme="@style/TextTitle"
+        style="@style/TextTitle"
         android:capitalize="sentences"/>
 </merge>
\ No newline at end of file
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index e5b1448..62bc53a 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -24,7 +24,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -33,9 +32,11 @@
 import android.os.Process;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Patterns;
+import android.util.Xml;
 
 import com.android.launcher3.LauncherProvider.SqlArguments;
 import com.android.launcher3.LauncherSettings.Favorites;
@@ -149,9 +150,6 @@
     private static final String HOTSEAT_CONTAINER_NAME =
             Favorites.containerToString(Favorites.CONTAINER_HOTSEAT);
 
-    private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
-            "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
-
     @Thunk final Context mContext;
     @Thunk final AppWidgetHost mAppWidgetHost;
     protected final LayoutParserCallback mCallback;
@@ -207,7 +205,7 @@
      */
     protected int parseLayout(int layoutId, IntArray screenIds)
             throws XmlPullParserException, IOException {
-        XmlResourceParser parser = mSourceRes.getXml(layoutId);
+        XmlPullParser parser = mSourceRes.getXml(layoutId);
         beginDocument(parser, mRootTag);
         final int depth = parser.getDepth();
         int type;
@@ -228,7 +226,7 @@
      * Parses container and screenId attribute from the current tag, and puts it in the out.
      * @param out array of size 2.
      */
-    protected void parseContainerAndScreen(XmlResourceParser parser, int[] out) {
+    protected void parseContainerAndScreen(XmlPullParser parser, int[] out) {
         if (HOTSEAT_CONTAINER_NAME.equals(getAttributeValue(parser, ATTR_CONTAINER))) {
             out[0] = Favorites.CONTAINER_HOTSEAT;
             // Hack: hotseat items are stored using screen ids
@@ -243,7 +241,7 @@
      * Parses the current node and returns the number of elements added.
      */
     protected int parseAndAddNode(
-            XmlResourceParser parser, ArrayMap<String, TagParser> tagParserMap, IntArray screenIds)
+            XmlPullParser parser, ArrayMap<String, TagParser> tagParserMap, IntArray screenIds)
         throws XmlPullParserException, IOException {
 
         if (TAG_INCLUDE.equals(parser.getName())) {
@@ -324,7 +322,7 @@
          * Parses the tag and adds to the db
          * @return the id of the row added or -1;
          */
-        int parseAndAdd(XmlResourceParser parser)
+        int parseAndAdd(XmlPullParser parser)
                 throws XmlPullParserException, IOException;
     }
 
@@ -334,7 +332,7 @@
     protected class AppShortcutParser implements TagParser {
 
         @Override
-        public int parseAndAdd(XmlResourceParser parser) {
+        public int parseAndAdd(XmlPullParser parser) {
             final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
             final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
 
@@ -371,7 +369,7 @@
         /**
          * Helper method to allow extending the parser capabilities
          */
-        protected int invalidPackageOrClass(XmlResourceParser parser) {
+        protected int invalidPackageOrClass(XmlPullParser parser) {
             Log.w(TAG, "Skipping invalid <favorite> with no component");
             return -1;
         }
@@ -383,7 +381,7 @@
     protected class AutoInstallParser implements TagParser {
 
         @Override
-        public int parseAndAdd(XmlResourceParser parser) {
+        public int parseAndAdd(XmlPullParser parser) {
             final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
             final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
             if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) {
@@ -414,7 +412,7 @@
         }
 
         @Override
-        public int parseAndAdd(XmlResourceParser parser) {
+        public int parseAndAdd(XmlPullParser parser) {
             final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
             final int iconId = getAttributeResourceValue(parser, ATTR_ICON, 0);
 
@@ -449,7 +447,7 @@
                     intent, Favorites.ITEM_TYPE_SHORTCUT);
         }
 
-        protected Intent parseIntent(XmlResourceParser parser) {
+        protected Intent parseIntent(XmlPullParser parser) {
             final String url = getAttributeValue(parser, ATTR_URL);
             if (TextUtils.isEmpty(url) || !Patterns.WEB_URL.matcher(url).matches()) {
                 if (LOGD) Log.d(TAG, "Ignoring shortcut, invalid url: " + url);
@@ -470,7 +468,7 @@
     protected class PendingWidgetParser implements TagParser {
 
         @Override
-        public int parseAndAdd(XmlResourceParser parser)
+        public int parseAndAdd(XmlPullParser parser)
                 throws XmlPullParserException, IOException {
             final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
             final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
@@ -541,7 +539,7 @@
         }
 
         @Override
-        public int parseAndAdd(XmlResourceParser parser)
+        public int parseAndAdd(XmlPullParser parser)
                 throws XmlPullParserException, IOException {
             final String title;
             final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
@@ -649,7 +647,7 @@
      * Return attribute value, attempting launcher-specific namespace first
      * before falling back to anonymous attribute.
      */
-    protected static String getAttributeValue(XmlResourceParser parser, String attribute) {
+    protected static String getAttributeValue(XmlPullParser parser, String attribute) {
         String value = parser.getAttributeValue(
                 "http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute);
         if (value == null) {
@@ -662,13 +660,14 @@
      * Return attribute resource value, attempting launcher-specific namespace
      * first before falling back to anonymous attribute.
      */
-    protected static int getAttributeResourceValue(XmlResourceParser parser, String attribute,
+    protected static int getAttributeResourceValue(XmlPullParser parser, String attribute,
             int defaultValue) {
-        int value = parser.getAttributeResourceValue(
+        AttributeSet attrs = Xml.asAttributeSet(parser);
+        int value = attrs.getAttributeResourceValue(
                 "http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute,
                 defaultValue);
         if (value == defaultValue) {
-            value = parser.getAttributeResourceValue(null, attribute, defaultValue);
+            value = attrs.getAttributeResourceValue(null, attribute, defaultValue);
         }
         return value;
     }
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index 44830e8..75297f6 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -10,7 +10,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -76,7 +75,7 @@
     }
 
     @Override
-    protected void parseContainerAndScreen(XmlResourceParser parser, int[] out) {
+    protected void parseContainerAndScreen(XmlPullParser parser, int[] out) {
         out[0] = LauncherSettings.Favorites.CONTAINER_DESKTOP;
         String strContainer = getAttributeValue(parser, ATTR_CONTAINER);
         if (strContainer != null) {
@@ -91,7 +90,7 @@
     public class AppShortcutWithUriParser extends AppShortcutParser {
 
         @Override
-        protected int invalidPackageOrClass(XmlResourceParser parser) {
+        protected int invalidPackageOrClass(XmlPullParser parser) {
             final String uri = getAttributeValue(parser, ATTR_URI);
             if (TextUtils.isEmpty(uri)) {
                 Log.e(TAG, "Skipping invalid <favorite> with no component or uri");
@@ -185,7 +184,7 @@
         }
 
         @Override
-        protected Intent parseIntent(XmlResourceParser parser) {
+        protected Intent parseIntent(XmlPullParser parser) {
             String uri = null;
             try {
                 uri = getAttributeValue(parser, ATTR_URI);
@@ -205,7 +204,7 @@
         private final AppShortcutWithUriParser mChildParser = new AppShortcutWithUriParser();
 
         @Override
-        public int parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
+        public int parseAndAdd(XmlPullParser parser) throws XmlPullParserException,
                 IOException {
             final int groupDepth = parser.getDepth();
             int type;
@@ -233,7 +232,7 @@
     @Thunk class PartnerFolderParser implements TagParser {
 
         @Override
-        public int parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
+        public int parseAndAdd(XmlPullParser parser) throws XmlPullParserException,
                 IOException {
             // Folder contents come from an external XML resource
             final Partner partner = Partner.get(mPackageManager);
@@ -242,7 +241,7 @@
                 final int resId = partnerRes.getIdentifier(Partner.RES_FOLDER,
                         "xml", partner.getPackageName());
                 if (resId != 0) {
-                    final XmlResourceParser partnerParser = partnerRes.getXml(resId);
+                    final XmlPullParser partnerParser = partnerRes.getXml(resId);
                     beginDocument(partnerParser, TAG_FOLDER);
 
                     FolderParser folderParser = new FolderParser(getFolderElementsMap(partnerRes));
@@ -259,7 +258,7 @@
     @Thunk class MyFolderParser extends FolderParser {
 
         @Override
-        public int parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
+        public int parseAndAdd(XmlPullParser parser) throws XmlPullParserException,
                 IOException {
             final int resId = getAttributeResourceValue(parser, ATTR_FOLDER_ITEMS, 0);
             if (resId != 0) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d65fe76..d820448 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -257,7 +257,7 @@
 
     private RotationHelper mRotationHelper;
 
-    private final Handler mHandler = new Handler();
+    final Handler mHandler = new Handler();
     private final Runnable mHandleDeferredResume = this::handleDeferredResume;
 
     @Override
@@ -1748,6 +1748,8 @@
         setWorkspaceLoading(true);
 
         // Clear the workspace because it's going to be rebound
+        mDragController.cancelDrag();
+
         mWorkspace.clearDropTargets();
         mWorkspace.removeAllWorkspaceScreens();
         mAppWidgetHost.clearViews();
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 5ab6eea..b1664f1 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -34,6 +34,7 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.AddWorkspaceItemsTask;
@@ -210,20 +211,20 @@
             final int itemId, final ItemInfo item, StackTraceElement[] stackTrace) {
         ItemInfo modelItem = sBgDataModel.itemsIdMap.get(itemId);
         if (modelItem != null && item != modelItem) {
-            // check all the data is consistent
-            if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {
-                ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;
-                ShortcutInfo shortcut = (ShortcutInfo) item;
-                if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&
-                        modelShortcut.intent.filterEquals(shortcut.intent) &&
-                        modelShortcut.id == shortcut.id &&
-                        modelShortcut.itemType == shortcut.itemType &&
-                        modelShortcut.container == shortcut.container &&
-                        modelShortcut.screenId == shortcut.screenId &&
-                        modelShortcut.cellX == shortcut.cellX &&
-                        modelShortcut.cellY == shortcut.cellY &&
-                        modelShortcut.spanX == shortcut.spanX &&
-                        modelShortcut.spanY == shortcut.spanY) {
+            // If it is a release build on a release device, check all the data is consistent as
+            // we don't want to crash non-dev users.
+            if (!Utilities.IS_DEBUG_DEVICE && !FeatureFlags.IS_DOGFOOD_BUILD &&
+                    modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {
+                if (modelItem.title.toString().equals(item.title.toString()) &&
+                        modelItem.getIntent().filterEquals(item.getIntent()) &&
+                        modelItem.id == item.id &&
+                        modelItem.itemType == item.itemType &&
+                        modelItem.container == item.container &&
+                        modelItem.screenId == item.screenId &&
+                        modelItem.cellX == item.cellX &&
+                        modelItem.cellY == item.cellY &&
+                        modelItem.spanX == item.spanX &&
+                        modelItem.spanY == item.spanY) {
                     // For all intents and purposes, this is the same object
                     return;
                 }
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 6d85612..cee1c26 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -187,6 +187,11 @@
         return new float[] {1, 0, 0};
     }
 
+    public float[] getHotseatScaleAndTranslation(Launcher launcher) {
+        // For most states, treat the hotseat as if it were part of the workspace.
+        return getWorkspaceScaleAndTranslation(launcher);
+    }
+
     /**
      * Returns 2 floats designating how to transition overview:
      *   scale for the current and adjacent pages
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index a877141..f6b54f2 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -17,7 +17,6 @@
 package com.android.launcher3;
 
 import static android.view.View.VISIBLE;
-
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
@@ -249,6 +248,22 @@
             return;
         }
 
+        if (delay > 0) {
+            // Create the animation after the delay as some properties can change between preparing
+            // the animation and running the animation.
+            int startChangeId = mConfig.mChangeId;
+            mUiHandler.postDelayed(() -> {
+                if (mConfig.mChangeId == startChangeId) {
+                    goToStateAnimated(state, fromState, onCompleteRunnable);
+                }
+            }, delay);
+        } else {
+            goToStateAnimated(state, fromState, onCompleteRunnable);
+        }
+    }
+
+    private void goToStateAnimated(LauncherState state, LauncherState fromState,
+            Runnable onCompleteRunnable) {
         // Since state NORMAL can be reached from multiple states, just assume that the
         // transition plays in reverse and use the same duration as previous state.
         mConfig.duration = state == NORMAL ? fromState.transitionDuration : state.transitionDuration;
@@ -257,12 +272,7 @@
         prepareForAtomicAnimation(fromState, state, builder);
         AnimatorSet animation = createAnimationToNewWorkspaceInternal(
                 state, builder, onCompleteRunnable);
-        Runnable runnable = new StartAnimRunnable(animation);
-        if (delay > 0) {
-            mUiHandler.postDelayed(runnable, delay);
-        } else {
-            mUiHandler.post(runnable);
-        }
+        mUiHandler.post(new StartAnimRunnable(animation));
     }
 
     /**
@@ -298,6 +308,8 @@
             if (!isWorkspaceVisible) {
                 workspace.setScaleX(0.92f);
                 workspace.setScaleY(0.92f);
+                workspace.getHotseat().setScaleX(0.92f);
+                workspace.getHotseat().setScaleY(0.92f);
             }
         }
     }
@@ -532,6 +544,8 @@
 
         private AnimatorSet mCurrentAnimation;
         private LauncherState mTargetState;
+        // Id to keep track of config changes, to tie an animation with the corresponding request
+        private int mChangeId = 0;
 
         /**
          * Cancels the current animation and resets config variables.
@@ -553,6 +567,7 @@
 
             mCurrentAnimation = null;
             playbackController = null;
+            mChangeId ++;
         }
 
         public PropertySetter getPropertySetter(AnimatorSetBuilder builder) {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 00da6fa..7fa1aa0 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1027,7 +1027,8 @@
         if (overScrollAmount < 0) {
             super.scrollTo(overScrollAmount, getScrollY());
         } else {
-            super.scrollTo(mMaxScrollX + overScrollAmount, getScrollY());
+            int x = Math.max(0, Math.min(getScrollX(), mMaxScrollX));
+            super.scrollTo(x + overScrollAmount, getScrollY());
         }
         invalidate();
     }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index c3edfe5..e699500 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -593,8 +593,9 @@
         int viewLocationTop = rect.top;
 
         if (isBubbleTextView && !fromDeepShortcutView) {
-            BubbleTextView btv = (BubbleTextView) v;
-            btv.getIconBounds(rect);
+            ((BubbleTextView) v).getIconBounds(rect);
+        } else if (isFolderIcon) {
+            ((FolderIcon) v).getPreviewBounds(rect);
         } else {
             rect.set(0, 0, rect.width(), rect.height());
         }
@@ -616,14 +617,14 @@
      *               eg {@link LauncherActivityInfo} or {@link ShortcutInfoCompat}.
      */
     public static Drawable getFullDrawable(Launcher launcher, ItemInfo info, int width, int height,
-            Object[] outObj) {
+            boolean flattenDrawable, Object[] outObj) {
         LauncherAppState appState = LauncherAppState.getInstance(launcher);
         if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
             LauncherActivityInfo activityInfo = LauncherAppsCompat.getInstance(launcher)
                     .resolveActivity(info.getIntent(), info.user);
             outObj[0] = activityInfo;
             return (activityInfo != null) ? appState.getIconCache()
-                    .getFullResIcon(activityInfo, false) : null;
+                    .getFullResIcon(activityInfo, flattenDrawable) : null;
         } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
             if (info instanceof PendingAddShortcutInfo) {
                 ShortcutConfigActivityInfo activityInfo =
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7f5ca42..7eee8af 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -44,6 +44,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Message;
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.util.AttributeSet;
@@ -521,6 +522,9 @@
         mScreenOrder.clear();
         mWorkspaceScreens.clear();
 
+        // Remove any deferred refresh callbacks
+        mLauncher.mHandler.removeCallbacksAndMessages(DeferredWidgetRefresh.class);
+
         // Ensure that the first page is always present
         bindAndInitFirstWorkspaceScreen(qsb);
 
@@ -3348,13 +3352,15 @@
             LauncherAppWidgetHost host) {
             mInfos = infos;
             mHost = host;
-            mHandler = new Handler();
+            mHandler = mLauncher.mHandler;
             mRefreshPending = true;
 
             mHost.addProviderChangeListener(this);
             // Force refresh after 10 seconds, if we don't get the provider changed event.
             // This could happen when the provider is no longer available in the app.
-            mHandler.postDelayed(this, 10000);
+            Message msg = Message.obtain(mHandler, this);
+            msg.obj = DeferredWidgetRefresh.class;
+            mHandler.sendMessageDelayed(msg, 10000);
         }
 
         @Override
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 3e09493..0507470 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -19,7 +19,6 @@
 import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
-import static com.android.launcher3.LauncherState.HOTSEAT_SEARCH_BOX;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -35,6 +34,7 @@
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
 
 /**
@@ -72,6 +72,7 @@
     private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter,
             AnimatorSetBuilder builder, AnimationConfig config) {
         float[] scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
+        float[] hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation(mLauncher);
         mNewScale = scaleAndTranslation[0];
         PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
         final int childCount = mWorkspace.getChildCount();
@@ -84,12 +85,24 @@
         Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
                 pageAlphaProvider.interpolator);
         boolean playAtomicComponent = config.playAtomicComponent();
+        Hotseat hotseat = mWorkspace.getHotseat();
         if (playAtomicComponent) {
             Interpolator scaleInterpolator = builder.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
             propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
+
+            // Set the hotseat's pivot point to match the workspace's, so that it scales together.
+            DragLayer dragLayer = mLauncher.getDragLayer();
+            int[] workspacePivot = new int[]{(int) mWorkspace.getPivotX(),
+                    (int) mWorkspace.getPivotY()};
+            dragLayer.getDescendantCoordRelativeToSelf(mWorkspace, workspacePivot);
+            dragLayer.mapCoordInSelfToDescendant(hotseat, workspacePivot);
+            hotseat.setPivotX(workspacePivot[0]);
+            hotseat.setPivotY(workspacePivot[1]);
+            float hotseatScale = hotseatScaleAndTranslation[0];
+            propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale, scaleInterpolator);
+
             float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
-            propertySetter.setViewAlpha(mLauncher.getHotseat(), hotseatIconsAlpha,
-                    fadeInterpolator);
+            propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
             propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
                     hotseatIconsAlpha, fadeInterpolator);
         }
@@ -105,6 +118,11 @@
         propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
                 scaleAndTranslation[2], translationInterpolator);
 
+        propertySetter.setFloat(hotseat, View.TRANSLATION_Y,
+                hotseatScaleAndTranslation[2], translationInterpolator);
+        propertySetter.setFloat(mWorkspace.getPageIndicator(), View.TRANSLATION_Y,
+                hotseatScaleAndTranslation[2], translationInterpolator);
+
         // Set scrim
         WorkspaceAndHotseatScrim scrim = mLauncher.getDragLayer().getScrim();
         propertySetter.setFloat(scrim, SCRIM_PROGRESS, state.getWorkspaceScrimAlpha(mLauncher),
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index bcb5eec..93bf69d 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -124,12 +124,6 @@
         float shiftCurrent = progress * mShiftRange;
 
         mAppsView.setTranslationY(shiftCurrent);
-        float hotseatTranslation = -mShiftRange + shiftCurrent;
-
-        if (!mIsVerticalLayout) {
-            mLauncher.getHotseat().setTranslationY(hotseatTranslation);
-            mLauncher.getWorkspace().getPageIndicator().setTranslationY(hotseatTranslation);
-        }
 
         // Use a light system UI (dark icons) if all apps is behind at least half of the
         // status bar.
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 8c57f46..b350767 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -116,7 +116,7 @@
             "ENABLE_HINTS_IN_OVERVIEW", false,
             "Show chip hints and gleams on the overview screen");
 
-    public static final TogglableFlag ENABLE_ASSISTANT_GESTURE = new TogglableFlag(
+    public static final TogglableFlag ENABLE_ASSISTANT_GESTURE = new ToggleableGlobalSettingsFlag(
             "ENABLE_ASSISTANT_GESTURE", false,
             "Enable swipe up from the bottom right corner to start assistant");
 
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 8a27f9d..bdbea29 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -199,7 +199,8 @@
                 Object[] outObj = new Object[1];
                 int w = mBitmap.getWidth();
                 int h = mBitmap.getHeight();
-                Drawable dr = Utilities.getFullDrawable(mLauncher, info, w, h, outObj);
+                Drawable dr = Utilities.getFullDrawable(mLauncher, info, w, h,
+                        false /* flattenDrawable */, outObj);
 
                 if (dr instanceof AdaptiveIconDrawable) {
                     int blurMargin = (int) mLauncher.getResources()
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index 794ab4e..5e41bb7 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -36,6 +36,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.folder.PreviewBackground;
+import com.android.launcher3.graphics.ShiftedBitmapDrawable;
 import com.android.launcher3.icons.BitmapRenderer;
 import com.android.launcher3.util.Preconditions;
 
@@ -133,39 +134,4 @@
 
         return new FolderAdaptiveIcon(new ColorDrawable(bg.getBgColor()), foreground, badge, mask);
     }
-
-    /**
-     * A simple drawable which draws a bitmap at a fixed position irrespective of the bounds
-     */
-    private static class ShiftedBitmapDrawable extends Drawable {
-
-        private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
-        private final Bitmap mBitmap;
-        private final float mShiftX;
-        private final float mShiftY;
-
-        ShiftedBitmapDrawable(Bitmap bitmap, float shiftX, float shiftY) {
-            mBitmap = bitmap;
-            mShiftX = shiftX;
-            mShiftY = shiftY;
-        }
-
-        @Override
-        public void draw(Canvas canvas) {
-            canvas.drawBitmap(mBitmap, mShiftX, mShiftY, mPaint);
-        }
-
-        @Override
-        public void setAlpha(int i) { }
-
-        @Override
-        public void setColorFilter(ColorFilter colorFilter) {
-            mPaint.setColorFilter(colorFilter);
-        }
-
-        @Override
-        public int getOpacity() {
-            return PixelFormat.TRANSLUCENT;
-        }
-    }
 }
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 30dbe69..67495ea 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -189,6 +189,10 @@
         return icon;
     }
 
+    public void getPreviewBounds(Rect outBounds) {
+        mBackground.getBounds(outBounds);
+    }
+
     public Folder getFolder() {
         return mFolder;
     }
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index fd4774f..ac908f4 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -33,6 +33,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.RadialGradient;
+import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.Shader;
 import android.util.Property;
@@ -154,6 +155,14 @@
         invalidate();
     }
 
+    void getBounds(Rect outBounds) {
+        int top = basePreviewOffsetY;
+        int left = basePreviewOffsetX;
+        int right = left + previewSize;
+        int bottom = top + previewSize;
+        outBounds.set(left, top, right, bottom);
+    }
+
     int getRadius() {
         return previewSize / 2;
     }
diff --git a/src/com/android/launcher3/graphics/ShiftedBitmapDrawable.java b/src/com/android/launcher3/graphics/ShiftedBitmapDrawable.java
new file mode 100644
index 0000000..52d45bb
--- /dev/null
+++ b/src/com/android/launcher3/graphics/ShiftedBitmapDrawable.java
@@ -0,0 +1,74 @@
+/*
+ * 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.launcher3.graphics;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+
+/**
+ * A simple drawable which draws a bitmap at a fixed position irrespective of the bounds
+ */
+public class ShiftedBitmapDrawable extends Drawable {
+
+    private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+    private final Bitmap mBitmap;
+    private float mShiftX;
+    private float mShiftY;
+
+    public ShiftedBitmapDrawable(Bitmap bitmap, float shiftX, float shiftY) {
+        mBitmap = bitmap;
+        mShiftX = shiftX;
+        mShiftY = shiftY;
+    }
+
+    public float getShiftX() {
+        return mShiftX;
+    }
+
+    public float getShiftY() {
+        return mShiftY;
+    }
+
+    public void setShiftX(float shiftX) {
+        mShiftX = shiftX;
+    }
+
+    public void setShiftY(float shiftY) {
+        mShiftY = shiftY;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        canvas.drawBitmap(mBitmap, mShiftX, mShiftY, mPaint);
+    }
+
+    @Override
+    public void setAlpha(int i) { }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+        mPaint.setColorFilter(colorFilter);
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/logging/EventLogArray.java b/src/com/android/launcher3/logging/EventLogArray.java
new file mode 100644
index 0000000..bfb3792
--- /dev/null
+++ b/src/com/android/launcher3/logging/EventLogArray.java
@@ -0,0 +1,136 @@
+/*
+ * 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.launcher3.logging;
+
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * A utility class to record and log events. Events are stored in a fixed size array and old logs
+ * are purged as new events come.
+ */
+public class EventLogArray {
+
+    private static final int TYPE_ONE_OFF = 0;
+    private static final int TYPE_FLOAT = 1;
+    private static final int TYPE_INTEGER = 2;
+    private static final int TYPE_BOOL_TRUE = 3;
+    private static final int TYPE_BOOL_FALSE = 4;
+
+    private final String name;
+    private final EventEntry[] logs;
+    private int nextIndex;
+
+    public EventLogArray(String name, int size) {
+        this.name = name;
+        logs = new EventEntry[size];
+        nextIndex = 0;
+    }
+
+    public void addLog(String event) {
+        addLog(TYPE_ONE_OFF, event, 0);
+    }
+
+    public void addLog(String event, int extras) {
+        addLog(TYPE_INTEGER, event, extras);
+    }
+
+    public void addLog(String event, float extras) {
+        addLog(TYPE_FLOAT, event, extras);
+    }
+
+    public void addLog(String event, boolean extras) {
+        addLog(extras ? TYPE_BOOL_TRUE : TYPE_BOOL_FALSE, event, 0);
+    }
+
+    private void addLog(int type, String event, float extras) {
+        // Merge the logs if its a duplicate
+        int last = (nextIndex + logs.length - 1) % logs.length;
+        int secondLast = (nextIndex + logs.length - 2) % logs.length;
+        if (isEntrySame(logs[last], type, event) && isEntrySame(logs[secondLast], type, event)) {
+            logs[last].update(type, event, extras);
+            logs[secondLast].duplicateCount++;
+            return;
+        }
+
+        if (logs[nextIndex] == null) {
+            logs[nextIndex] = new EventEntry();
+        }
+        logs[nextIndex].update(type, event, extras);
+        nextIndex = (nextIndex + 1) % logs.length;
+    }
+
+    public void dump(String prefix, PrintWriter writer) {
+        writer.println(prefix + name + " event history:");
+        SimpleDateFormat sdf = new SimpleDateFormat("  HH:mm:ss.SSSZ  ", Locale.US);
+        Date date = new Date();
+
+        for (int i = 0; i < logs.length; i++) {
+            EventEntry log = logs[(nextIndex + logs.length - i - 1) % logs.length];
+            if (log == null) {
+                continue;
+            }
+            date.setTime(log.time);
+
+            StringBuilder msg = new StringBuilder(prefix).append(sdf.format(date))
+                    .append(log.event);
+            switch (log.type) {
+                case TYPE_BOOL_FALSE:
+                    msg.append(": false");
+                    break;
+                case TYPE_BOOL_TRUE:
+                    msg.append(": true");
+                    break;
+                case TYPE_FLOAT:
+                    msg.append(": ").append(log.extras);
+                    break;
+                case TYPE_INTEGER:
+                    msg.append(": ").append((int) log.extras);
+                    break;
+                default: // fall out
+            }
+            if (log.duplicateCount > 0) {
+                msg.append(" & ").append(log.duplicateCount).append(" similar events");
+            }
+            writer.println(msg);
+        }
+    }
+
+    private boolean isEntrySame(EventEntry entry, int type, String event) {
+        return entry != null && entry.type == type && entry.event.equals(event);
+    }
+
+    /** A single event entry. */
+    private static class EventEntry {
+
+        private int type;
+        private String event;
+        private float extras;
+        private long time;
+        private int duplicateCount;
+
+        public void update(int type, String event, float extras) {
+            this.type = type;
+            this.event = event;
+            this.extras = extras;
+            time = System.currentTimeMillis();
+            duplicateCount = 0;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 35f7f88..fcace98 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -73,6 +73,11 @@
     }
 
     @Override
+    public float[] getHotseatScaleAndTranslation(Launcher launcher) {
+        return new float[] {1, 0, 0};
+    }
+
+    @Override
     public void onStateEnabled(Launcher launcher) {
         Workspace ws = launcher.getWorkspace();
         ws.showPageIndicatorAtCurrentScroll();
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 2b9e7b6..23ddd98 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -43,7 +43,9 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.folder.FolderShape;
+import com.android.launcher3.graphics.ShiftedBitmapDrawable;
 import com.android.launcher3.icons.LauncherIcons;
 
 import androidx.annotation.Nullable;
@@ -57,6 +59,8 @@
 
 public class FloatingIconView extends View implements Animator.AnimatorListener, ClipPathView {
 
+    private static final Rect sTmpRect = new Rect();
+
     private Runnable mStartRunnable;
     private Runnable mEndRunnable;
 
@@ -181,10 +185,11 @@
     }
 
     @WorkerThread
-    private void getIcon(Launcher launcher, ItemInfo info, boolean useDrawableAsIs,
+    private void getIcon(Launcher launcher, View v, ItemInfo info, boolean useDrawableAsIs,
             float aspectRatio) {
         final LayoutParams lp = (LayoutParams) getLayoutParams();
-        mDrawable = Utilities.getFullDrawable(launcher, info, lp.width, lp.height, new Object[1]);
+        mDrawable = Utilities.getFullDrawable(launcher, info, lp.width, lp.height, useDrawableAsIs,
+                new Object[1]);
 
         if (ADAPTIVE_ICON_WINDOW_ANIM.get() && !useDrawableAsIs
                 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
@@ -205,6 +210,12 @@
 
             int offset = getOffsetForAdaptiveIconBounds();
             mFinalDrawableBounds.set(offset, offset, lp.width - offset, mOriginalHeight - offset);
+            if (mForeground instanceof ShiftedBitmapDrawable && v instanceof FolderIcon) {
+                ShiftedBitmapDrawable sbd = (ShiftedBitmapDrawable) mForeground;
+                ((FolderIcon) v).getPreviewBounds(sTmpRect);
+                sbd.setShiftX(sbd.getShiftX() - sTmpRect.left);
+                sbd.setShiftY(sbd.getShiftY() - sTmpRect.top);
+            }
             mForeground.setBounds(mFinalDrawableBounds);
             mBackground.setBounds(mFinalDrawableBounds);
 
@@ -323,8 +334,8 @@
         // Must be called after matchPositionOf so that we know what size to load.
         if (originalView.getTag() instanceof ItemInfo) {
             new Handler(LauncherModel.getWorkerLooper()).postAtFrontOfQueue(() -> {
-                view.getIcon(launcher, (ItemInfo) originalView.getTag(), useDrawableAsIs,
-                        aspectRatio);
+                view.getIcon(launcher, originalView, (ItemInfo) originalView.getTag(),
+                        useDrawableAsIs, aspectRatio);
             });
         }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 7473189..93b4cc6 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -93,8 +93,6 @@
     private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null);
 
     private final UiDevice mDevice;
-    private final boolean mSwipeUpEnabled;
-    private Boolean mSwipeUpEnabledOverride = null;
     private final Instrumentation mInstrumentation;
     private int mExpectedRotation = Surface.ROTATION_0;
 
@@ -104,13 +102,6 @@
     public LauncherInstrumentation(Instrumentation instrumentation) {
         mInstrumentation = instrumentation;
         mDevice = UiDevice.getInstance(instrumentation);
-        final boolean swipeUpEnabledDefaultValue = SwipeUpSetting.isSwipeUpEnabledDefaultValue();
-        mSwipeUpEnabled = SwipeUpSetting.isSwipeUpSettingAvailable() ?
-                Settings.Secure.getInt(
-                        instrumentation.getTargetContext().getContentResolver(),
-                        SWIPE_UP_SETTING_NAME,
-                        swipeUpEnabledDefaultValue ? 1 : 0) == 1 :
-                swipeUpEnabledDefaultValue;
 
         // Launcher should run in test harness so that custom accessibility protocol between
         // Launcher and TAPL is enabled. In-process tests enable this protocol with a direct call
@@ -119,17 +110,18 @@
                 TestHelpers.isInLauncherProcess() || ActivityManager.isRunningInTestHarness());
     }
 
-    // Used only by TaplTests.
-    public void overrideSwipeUpEnabled(Boolean swipeUpEnabledOverride) {
-        mSwipeUpEnabledOverride = swipeUpEnabledOverride;
-    }
-
     void setActiveContainer(VisibleContainer container) {
         sActiveContainer = new WeakReference<>(container);
     }
 
     public boolean isSwipeUpEnabled() {
-        return mSwipeUpEnabledOverride != null ? mSwipeUpEnabledOverride : mSwipeUpEnabled;
+        final boolean swipeUpEnabledDefaultValue = SwipeUpSetting.isSwipeUpEnabledDefaultValue();
+        return SwipeUpSetting.isSwipeUpSettingAvailable() ?
+                Settings.Secure.getInt(
+                        mInstrumentation.getTargetContext().getContentResolver(),
+                        SWIPE_UP_SETTING_NAME,
+                        swipeUpEnabledDefaultValue ? 1 : 0) == 1 :
+                swipeUpEnabledDefaultValue;
     }
 
     static void log(String message) {