Merge "Only detect swipe directions that lead to new states" into ub-launcher3-edmonton
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 7e15434..179f21d 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -104,9 +104,9 @@
   VERTICAL_SCROLL = 9;
   HOME_INTENT = 10; // Deprecated, use enum Command instead
   BACK_BUTTON = 11; // Deprecated, use enum Command instead
-  // GO_TO_PLAYSTORE
   QUICK_SCRUB_BUTTON = 12;
   CLEAR_ALL_BUTTON = 13;
+  CANCEL_TARGET = 14;
 }
 
 // Used to define the action component of the LauncherEvent.
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index bab2cd7..c76ad83 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -21,6 +21,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.launcher3" >
 
+    <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="28"/>
     <uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
     <application
         android:backupAgent="com.android.launcher3.LauncherBackupAgent"
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 70e545f..120d6f9 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/layout/overview_clear_all_button.xml b/quickstep/res/layout/overview_clear_all_button.xml
index 0dc5d7c..9c4b618 100644
--- a/quickstep/res/layout/overview_clear_all_button.xml
+++ b/quickstep/res/layout/overview_clear_all_button.xml
@@ -7,7 +7,6 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="start|top"
-    android:fontFamily="sans-serif-medium"
     android:text="@string/recents_clear_all"
     android:textColor="?attr/workspaceTextColor"
     android:visibility="invisible"
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index b8b360a..429f3a2 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -24,7 +24,7 @@
         android:layout_height="match_parent"
         android:layout_marginTop="@dimen/task_thumbnail_top_margin" />
 
-    <ImageView
+    <com.android.quickstep.views.IconView
         android:id="@+id/icon"
         android:layout_width="@dimen/task_thumbnail_icon_size"
         android:layout_height="@dimen/task_thumbnail_icon_size"
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 37929b6..7673f69 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -17,4 +17,6 @@
     <string name="task_overlay_factory_class" translatable="false"></string>
 
     <string name="overview_callbacks_class" translatable="false"></string>
+
+    <string name="user_event_dispatcher_class" translatable="false">com.google.quickstep.logging.UserEventDispatcherExtension</string>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 94aaf15..34635bf 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -543,6 +543,7 @@
                         t.deferTransactionUntil(target.leash, surface, getNextFrameNumber(surface));
                     }
                 }
+                t.setEarlyWakeup();
                 t.apply();
 
                 matrix.reset();
@@ -657,6 +658,7 @@
                         t.setMatrix(app.leash, matrix);
                     }
                 }
+                t.setEarlyWakeup();
                 t.apply();
 
                 matrix.reset();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index 7da50c8..5a216f6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.uioverrides;
 
 import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
-import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
 
 import android.view.View;
@@ -47,10 +46,6 @@
 
     @Override
     public void onStateEnabled(Launcher launcher) {
-        if (!launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)) {
-            launcher.getSharedPrefs().edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
-        }
-
         AbstractFloatingView.closeAllOpenViews(launcher);
         dispatchWindowStateChanged(launcher);
     }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 61422e0..f87f006 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.uioverrides;
 
 import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
-import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
 import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
 
@@ -59,10 +58,6 @@
 
     @Override
     public void onStateEnabled(Launcher launcher) {
-        if (!launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)) {
-            launcher.getSharedPrefs().edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
-        }
-
         RecentsView rv = launcher.getOverviewPanel();
         rv.setOverviewStateEnabled(true);
         AbstractFloatingView.closeAllOpenViews(launcher);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index cb83a0d..06099b9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -21,6 +21,8 @@
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN;
+import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN;
 
 import android.content.Context;
 
@@ -28,6 +30,7 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
 import com.android.launcher3.LauncherStateManager.StateHandler;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.util.TouchController;
@@ -89,6 +92,55 @@
         recents.reset();
     }
 
+    public static void onCreate(Launcher launcher) {
+        if (!launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)) {
+            launcher.getStateManager().addStateListener(new LauncherStateManager.StateListener() {
+                @Override
+                public void onStateSetImmediately(LauncherState state) {
+                }
+
+                @Override
+                public void onStateTransitionStart(LauncherState toState) {
+                }
+
+                @Override
+                public void onStateTransitionComplete(LauncherState finalState) {
+                    boolean swipeUpEnabled = OverviewInteractionState.getInstance(launcher)
+                            .isSwipeUpGestureEnabled();
+                    LauncherState prevState = launcher.getStateManager().getLastState();
+
+                    if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
+                            && finalState == ALL_APPS && prevState == NORMAL))) {
+                        launcher.getSharedPrefs().edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
+                        launcher.getStateManager().removeStateListener(this);
+                    }
+                }
+            });
+        }
+
+        if (!launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)) {
+            launcher.getStateManager().addStateListener(new LauncherStateManager.StateListener() {
+                @Override
+                public void onStateSetImmediately(LauncherState state) {
+                }
+
+                @Override
+                public void onStateTransitionStart(LauncherState toState) {
+                }
+
+                @Override
+                public void onStateTransitionComplete(LauncherState finalState) {
+                    LauncherState prevState = launcher.getStateManager().getLastState();
+
+                    if (finalState == ALL_APPS && prevState == OVERVIEW) {
+                        launcher.getSharedPrefs().edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
+                        launcher.getStateManager().removeStateListener(this);
+                    }
+                }
+            });
+        }
+    }
+
     public static void onStart(Context context) {
         RecentsModel model = RecentsModel.getInstance(context);
         if (model != null) {
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 8a6abb2..85106ba 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -59,8 +59,6 @@
 
     LayoutListener createLayoutListener(T activity);
 
-    void onQuickstepGestureStarted(T activity, boolean activityVisible);
-
     /**
      * Updates the UI to indicate quick interaction.
      * @return true if there any any UI change as a result of this
@@ -117,11 +115,6 @@
         }
 
         @Override
-        public void onQuickstepGestureStarted(Launcher activity, boolean activityVisible) {
-            activity.onQuickstepGestureStarted(activityVisible);
-        }
-
-        @Override
         public boolean onQuickInteractionStart(Launcher activity, boolean activityVisible) {
             LauncherState fromState = activity.getStateManager().getState();
             activity.getStateManager().goToState(FAST_OVERVIEW, activityVisible);
@@ -137,10 +130,7 @@
 
         @Override
         public void executeOnWindowAvailable(Launcher activity, Runnable action) {
-            if (activity.getWorkspace().runOnOverlayHidden(action)) {
-                // Notify the activity that qiuckscrub has started
-                onQuickstepGestureStarted(activity, true);
-            }
+            activity.getWorkspace().runOnOverlayHidden(action);
         }
 
         @Override
@@ -192,8 +182,8 @@
             return new AnimationFactory() {
                 @Override
                 public void createActivityController(long transitionLength) {
-                    createActivityControllerInternal(activity, activityVisible, transitionLength,
-                            callback);
+                    createActivityControllerInternal(activity, activityVisible, startState,
+                            transitionLength, callback);
                 }
 
                 @Override
@@ -204,10 +194,12 @@
         }
 
         private void createActivityControllerInternal(Launcher activity, boolean wasVisible,
-                long transitionLength, Consumer<AnimatorPlaybackController> callback) {
+                LauncherState startState, long transitionLength,
+                Consumer<AnimatorPlaybackController> callback) {
             if (wasVisible) {
                 DeviceProfile dp = activity.getDeviceProfile();
                 long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
+                activity.getStateManager().goToState(startState, false);
                 callback.accept(activity.getStateManager()
                         .createAnimationToNewWorkspace(OVERVIEW, accuracy));
                 return;
@@ -310,11 +302,6 @@
     class FallbackActivityControllerHelper implements ActivityControlHelper<RecentsActivity> {
 
         @Override
-        public void onQuickstepGestureStarted(RecentsActivity activity, boolean activityVisible) {
-            // TODO:
-        }
-
-        @Override
         public boolean onQuickInteractionStart(RecentsActivity activity, boolean activityVisible) {
             // Activity does not need any UI change for quickscrub.
             return false;
diff --git a/quickstep/src/com/android/quickstep/LongSwipeHelper.java b/quickstep/src/com/android/quickstep/LongSwipeHelper.java
index 4ce18b3..edc7457 100644
--- a/quickstep/src/com/android/quickstep/LongSwipeHelper.java
+++ b/quickstep/src/com/android/quickstep/LongSwipeHelper.java
@@ -142,6 +142,7 @@
                 }
             }
         }
+        transaction.setEarlyWakeup();
         transaction.apply();
     }
 
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 6ce9372..2d41a5b 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -22,6 +22,8 @@
 import static android.view.MotionEvent.ACTION_UP;
 import static android.view.MotionEvent.INVALID_POINTER_ID;
 
+import static com.android.systemui.shared.system.ActivityManagerWrapper
+        .CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
 
 import android.annotation.TargetApi;
@@ -73,6 +75,7 @@
     private final ActivityControlHelper mActivityControlHelper;
     private final MainThreadExecutor mMainThreadExecutor;
     private final Choreographer mBackgroundThreadChoreographer;
+    private final OverviewCallbacks mOverviewCallbacks;
 
     private final boolean mIsDeferredDownTarget;
     private final PointF mDownPos = new PointF();
@@ -92,8 +95,10 @@
     public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo,
             RecentsModel recentsModel, Intent homeIntent, ActivityControlHelper activityControl,
             MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer,
-            @HitTarget int downHitTarget, VelocityTracker velocityTracker) {
+            @HitTarget int downHitTarget, OverviewCallbacks overviewCallbacks,
+            VelocityTracker velocityTracker) {
         super(base);
+
         mRunningTask = runningTaskInfo;
         mRecentsModel = recentsModel;
         mHomeIntent = homeIntent;
@@ -102,6 +107,7 @@
         mMainThreadExecutor = mainThreadExecutor;
         mBackgroundThreadChoreographer = backgroundThreadChoreographer;
         mIsDeferredDownTarget = activityControl.deferStartingActivity(downHitTarget);
+        mOverviewCallbacks = overviewCallbacks;
     }
 
     @Override
@@ -187,6 +193,11 @@
         if (mInteractionHandler == null) {
             return;
         }
+
+        mOverviewCallbacks.closeAllWindows();
+        ActivityManagerWrapper.getInstance().closeSystemWindows(
+                CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+
         // Notify the handler that the gesture has actually started
         mInteractionHandler.onGestureStarted();
     }
diff --git a/quickstep/src/com/android/quickstep/OverviewCallbacks.java b/quickstep/src/com/android/quickstep/OverviewCallbacks.java
index 62938a7..ac4a40b 100644
--- a/quickstep/src/com/android/quickstep/OverviewCallbacks.java
+++ b/quickstep/src/com/android/quickstep/OverviewCallbacks.java
@@ -40,4 +40,6 @@
     public void onInitOverviewTransition() { }
 
     public void onResetOverview() { }
+
+    public void closeAllWindows() { }
 }
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index 7bb9877..ae7de87 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -43,7 +43,7 @@
      * Snap to a new page when crossing these thresholds. The first and last auto-advance.
      */
     private static final float[] QUICK_SCRUB_THRESHOLDS = new float[] {
-            0.05f, 0.35f, 0.65f, 0.95f
+            0.04f, 0.27f, 0.50f, 0.73f, 0.96f
     };
 
     private static final String TAG = "QuickScrubController";
@@ -106,7 +106,7 @@
         };
         int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
                 * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
-        if (mRecentsView.snapToPage(page, snapDuration)) {
+        if (mRecentsView.getChildCount() > 0 && mRecentsView.snapToPage(page, snapDuration)) {
             // Settle on the page then launch it
             mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable);
         } else {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index c9afcb5..3babd1f 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -164,6 +164,7 @@
     private ISystemUiProxy mISystemUiProxy;
     private OverviewCommandHelper mOverviewCommandHelper;
     private OverviewInteractionState mOverviewInteractionState;
+    private OverviewCallbacks mOverviewCallbacks;
 
     private Choreographer mMainThreadChoreographer;
     private Choreographer mBackgroundThreadChoreographer;
@@ -179,6 +180,7 @@
         mMainThreadChoreographer = Choreographer.getInstance();
         mEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
         mOverviewInteractionState = OverviewInteractionState.getInstance(this);
+        mOverviewCallbacks = OverviewCallbacks.get(this);
 
         sConnected = true;
 
@@ -230,7 +232,8 @@
             return new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
                             mOverviewCommandHelper.overviewIntent,
                             mOverviewCommandHelper.getActivityControlHelper(), mMainThreadExecutor,
-                            mBackgroundThreadChoreographer, downHitTarget, tracker);
+                            mBackgroundThreadChoreographer, downHitTarget, mOverviewCallbacks,
+                            tracker);
         }
     }
 
@@ -330,7 +333,7 @@
             if (mInvalidated) {
                 return;
             }
-            mActivityHelper.onQuickstepGestureStarted(mActivity, true);
+            OverviewCallbacks.get(mActivity).closeAllWindows();
             ActivityManagerWrapper.getInstance()
                     .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
         }
@@ -341,10 +344,11 @@
                 return;
             }
             if (interactionType == INTERACTION_QUICK_SCRUB) {
+                OverviewCallbacks.get(mActivity).closeAllWindows();
                 ActivityManagerWrapper.getInstance()
                         .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
-                mStartPending = true;
 
+                mStartPending = true;
                 Runnable action = () -> {
                     mQuickScrubController.onQuickScrubStart(mActivityHelper.onQuickInteractionStart(
                             mActivity, true), mActivityHelper);
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 027f2e9..9dae9df 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -24,7 +24,6 @@
 import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_START_DURATION;
 import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
 import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
-import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
@@ -69,7 +68,6 @@
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.LatencyTrackerCompat;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -165,10 +163,12 @@
     private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
 
     private final Context mContext;
-    private final int mRunningTaskId;
     private final ActivityControlHelper<T> mActivityControlHelper;
     private final ActivityInitListener mActivityInitListener;
 
+    private final int mRunningTaskId;
+    private ThumbnailData mTaskSnapshot;
+
     private MultiStateCallback mStateCallback;
     private AnimatorPlaybackController mLauncherTransitionController;
 
@@ -564,8 +564,6 @@
         mGestureStarted = true;
         mRecentsAnimationWrapper.hideCurrentInputMethod();
         mRecentsAnimationWrapper.enableInputConsumer();
-        ActivityManagerWrapper.getInstance().closeSystemWindows(
-                CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
     }
 
     /**
@@ -579,8 +577,6 @@
             // Once the gesture starts, we can no longer transition home through the button, so
             // reset the force override of the activity visibility
             mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
-            mActivityControlHelper.onQuickstepGestureStarted(
-                    curActivity, mWasLauncherAlreadyVisible);
         }
     }
 
@@ -711,9 +707,11 @@
         synchronized (mRecentsAnimationWrapper) {
             if (mRecentsAnimationWrapper.controller != null) {
                 // Update the screenshot of the task
-                ThumbnailData thumbnail =
-                        mRecentsAnimationWrapper.controller.screenshotTask(mRunningTaskId);
-                final TaskView taskView = mRecentsView.updateThumbnail(mRunningTaskId, thumbnail);
+                if (mTaskSnapshot == null) {
+                    mTaskSnapshot = mRecentsAnimationWrapper.controller
+                            .screenshotTask(mRunningTaskId);
+                }
+                TaskView taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot);
                 mRecentsView.setRunningTaskHidden(false);
                 if (taskView != null) {
                     // Defer finishing the animation until the next launcher frame with the
@@ -780,7 +778,12 @@
             int scrollForSecondTask = mRecentsView.getChildCount() > 1
                     ? mRecentsView.getScrollForPage(1) : scrollForFirstTask;
             int offsetFromFirstTask = scrollForFirstTask - scrollForSecondTask;
-            float interpolation = offsetFromFirstTask / (mRecentsView.getWidth() / 2);
+            final float interpolation;
+            if (mRecentsView.getWidth() == 0) {
+                interpolation = scrollForSecondTask == scrollForFirstTask ? 0 : 1;
+            } else {
+                interpolation = (float) offsetFromFirstTask / (mRecentsView.getWidth() / 2);
+            }
             mClipAnimationHelper.offsetTarget(
                     firstTask.getCurveScaleForInterpolation(interpolation), offsetFromFirstTask,
                     mActivityControlHelper.getTranslationYForQuickScrub(mActivity));
@@ -886,10 +889,11 @@
 
     private void onLongSwipeGestureFinishUi(float velocity, boolean isFling) {
         if (!mUiLongSwipeMode || mLongSwipeController == null) {
+            mUiLongSwipeMode = false;
             handleNormalGestureEnd(velocity, isFling);
             return;
         }
-
+        mUiLongSwipeMode = false;
         finishCurrentTransitionToHome();
         mLongSwipeController.end(velocity, isFling,
                 () -> setStateOnUiThread(STATE_HANDLER_INVALIDATED));
diff --git a/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
new file mode 100644
index 0000000..d4cdd35
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 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.logging;
+
+import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.systemui.shared.system.MetricsLoggerCompat;
+
+/**
+ * This class handles AOSP MetricsLogger function calls.
+ */
+public class UserEventDispatcherExtension extends UserEventDispatcher {
+
+    public void logStateChangeAction(int action, int dir, int srcChildTargetType,
+                                     int srcParentContainerType, int dstContainerType,
+                                     int pageIndex) {
+        new MetricsLoggerCompat().visibility(MetricsLoggerCompat.OVERVIEW_ACTIVITY,
+                dstContainerType == LauncherLogProto.ContainerType.TASKSWITCHER);
+        super.logStateChangeAction(action, dir, srcChildTargetType, srcParentContainerType,
+                dstContainerType, pageIndex);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
index 5e21467..14b4046 100644
--- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -170,6 +170,7 @@
 
             mTaskTransformCallback.accept(transaction, app);
         }
+        transaction.setEarlyWakeup();
         transaction.apply();
         return currentRect;
     }
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
index 7fc3efb..bbf223d 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
@@ -60,6 +60,5 @@
             t.setLayer(target.leash, layer);
             t.show(target.leash);
         }
-        t.setEarlyWakeup();
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewDrawable.java b/quickstep/src/com/android/quickstep/util/TaskViewDrawable.java
index 8549df3..34f580b 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewDrawable.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewDrawable.java
@@ -21,7 +21,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.util.FloatProperty;
-import android.widget.ImageView;
+import android.view.View;
 
 import com.android.launcher3.Utilities;
 import com.android.quickstep.views.RecentsView;
@@ -47,7 +47,7 @@
             (t) -> (Math.max(t, 0.3f) - 0.3f) / 0.7f;
 
     private final RecentsView mParent;
-    private final ImageView mIconView;
+    private final View mIconView;
     private final int[] mIconPos;
 
     private final TaskThumbnailView mThumbnailView;
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index 14867ab..f3a0e4f 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -23,9 +23,9 @@
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.TextView;
+import android.widget.Button;
 
-public class ClearAllButton extends TextView {
+public class ClearAllButton extends Button {
     RecentsView mRecentsView;
 
     public ClearAllButton(Context context, @Nullable AttributeSet attrs) {
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
new file mode 100644
index 0000000..c359966
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
+ * when the drawable changes.
+ */
+public class IconView extends View {
+
+    private Drawable mDrawable;
+
+    public IconView(Context context) {
+        super(context);
+    }
+
+    public IconView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public IconView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public void setDrawable(Drawable d) {
+        if (mDrawable != null) {
+            mDrawable.setCallback(null);
+        }
+        mDrawable = d;
+        if (mDrawable != null) {
+            mDrawable.setCallback(this);
+            mDrawable.setBounds(0, 0, getWidth(), getHeight());
+        }
+        invalidate();
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        if (mDrawable != null) {
+            mDrawable.setBounds(0, 0, w, h);
+        }
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || who == mDrawable;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+
+        final Drawable drawable = mDrawable;
+        if (drawable != null && drawable.isStateful()
+                && drawable.setState(getDrawableState())) {
+            invalidateDrawable(drawable);
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mDrawable != null) {
+            mDrawable.draw(canvas);
+        }
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 6e70a55..f04101a 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -41,7 +41,6 @@
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
-import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -315,52 +314,25 @@
         final int childCount = getChildCount();
         if (mShowEmptyMessage || childCount == 0) return 0;
 
-        // Current visible coordinate of the end of the oldest task.
         final View lastChild = getChildAt(childCount - 1);
+
+        // Current visible coordinate of the end of the oldest task.
         final int carouselCurrentEnd =
                 (mIsRtl ? lastChild.getLeft() : lastChild.getRight()) - getScrollX();
 
-        // As the end (let's call it E aka carouselCurrentEnd) of the carousel moves over Clear
-        // all button, the button changes trasparency.
-        // fullAlphaX and zeroAlphaX are the points of the 100% and 0% alpha correspondingly.
-        // Alpha changes linearly between 100% and 0% as E moves through this range. It doesn't
-        // change outside of the range.
+        // Visible button-facing end of a centered task.
+        final int centeredTaskEnd = mIsRtl ?
+                getPaddingLeft() + mInsets.left :
+                getWidth() - getPaddingRight() - mInsets.right;
 
-        // Once E hits the border of the Clear-All button that looks towards the most recent
-        // task, the whole button is uncovered, and it should have alpha 100%.
-        final float fullAlphaX = mIsRtl ?
-                mClearAllButton.getX() + mClearAllButton.getWidth() :
-                mClearAllButton.getX();
-
-        // X coordinate of the carousel scrolled as far as possible in the direction towards the
-        // button. Logically, the button is "behind" the least recent task. This is the
-        // coordinate of the end of the least recent task in the carousel just after opening,
-        // with the most recent task in the center, and the rest of tasks go from that point
-        // towards and potentially behind the button.
-        final int carouselMotionLimit = getScrollForPage(childCount - 1) - getScrollForPage(0) +
-                (mIsRtl ?
-                        getPaddingLeft() + mInsets.left :
-                        getWidth() - getPaddingRight() - mInsets.right);
-
-        // The carousel might not be able to ever cover a part of the Clear-all button. Then
-        // always show the button as 100%. Technically, this check also prevents dividing by zero
-        // or getting a negative transparency ratio.
-        if (mIsRtl ? carouselMotionLimit >= fullAlphaX : carouselMotionLimit <= fullAlphaX) {
-            return 1;
-        }
-
-        // If the carousel is able to cover the button completely, we make the button completely
-        // transparent when E hits the border of the button farthest from the most recent task.
-        // Or, the carousel may not be able to move that far towards the button so it completely
-        // covers the it. Then we set the motion limit position of the carousel as the point
-        // where the button reaches 0 alpha.
-        final float zeroAlphaX = mIsRtl ?
-                Math.max(mClearAllButton.getX(), carouselMotionLimit) :
-                Math.min(mClearAllButton.getX() + mClearAllButton.getWidth(), carouselMotionLimit);
+        // The distance of the carousel travel during which the alpha changes from 0 to 1. This
+        // is the motion between the oldest task in its centered position and the oldest task
+        // scrolled to the end.
+        final int alphaChangeRange = (mIsRtl ? 0 : mMaxScrollX) - getScrollForPage(childCount - 1);
 
         return Utilities.boundToRange(
-                (zeroAlphaX - carouselCurrentEnd) /
-                        (zeroAlphaX - fullAlphaX), 0, 1);
+                ((float) (centeredTaskEnd - carouselCurrentEnd)) /
+                        alphaChangeRange, 0, 1);
     }
 
     private void updateClearAllButtonAlpha() {
@@ -481,11 +453,12 @@
         mInsets.set(insets);
         DeviceProfile dp = mActivity.getDeviceProfile();
         getTaskSize(dp, mTempRect);
+
         mTempRect.top -= getResources()
                 .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
         setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top,
-                dp.widthPx - mTempRect.right - mInsets.right,
-                dp.heightPx - mTempRect.bottom - mInsets.bottom);
+                dp.availableWidthPx + mInsets.left - mTempRect.right,
+                dp.availableHeightPx + mInsets.top - mTempRect.bottom);
     }
 
     protected abstract void getTaskSize(DeviceProfile dp, Rect outRect);
@@ -745,12 +718,15 @@
                 duration, LINEAR, anim);
     }
 
-    private void removeTask(Task task, PendingAnimation.OnEndListener onEndListener) {
+    private void removeTask(Task task, PendingAnimation.OnEndListener onEndListener,
+            boolean shouldLog) {
         if (task != null) {
             ActivityManagerWrapper.getInstance().removeTask(task.key.id);
-            mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
-                    onEndListener.logAction, Direction.UP,
-                    TaskUtils.getComponentKeyForTask(task.key));
+            if (shouldLog) {
+                mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
+                        onEndListener.logAction, Direction.UP,
+                        TaskUtils.getComponentKeyForTask(task.key));
+            }
         }
     }
 
@@ -833,7 +809,7 @@
         mPendingAnimation.addEndListener((onEndListener) -> {
            if (onEndListener.isSuccess) {
                if (shouldRemoveTask) {
-                   removeTask(taskView.getTask(), onEndListener);
+                   removeTask(taskView.getTask(), onEndListener, true);
                }
                int pageToSnapTo = mCurrentPage;
                if (draggedIndex < pageToSnapTo) {
@@ -869,7 +845,7 @@
             if (onEndListener.isSuccess) {
                 while (getChildCount() != 0) {
                     TaskView taskView = getPageAt(getChildCount() - 1);
-                    removeTask(taskView.getTask(), onEndListener);
+                    removeTask(taskView.getTask(), onEndListener, false);
                     removeView(taskView);
                 }
                 onAllTasksRemoved();
@@ -1185,15 +1161,18 @@
             onTaskLaunched(result);
             tv.setVisibility(VISIBLE);
             getOverlay().remove(drawable);
-            if (!result) {
-                tv.notifyTaskLaunchFailed(TAG);
-            }
         };
 
         mPendingAnimation = new PendingAnimation(anim);
         mPendingAnimation.addEndListener((onEndListener) -> {
             if (onEndListener.isSuccess) {
-                tv.launchTask(false, onTaskLaunchFinish, getHandler());
+                Consumer<Boolean> onLaunchResult = (result) -> {
+                    onTaskLaunchFinish.accept(result);
+                    if (!result) {
+                        tv.notifyTaskLaunchFailed(TAG);
+                    }
+                };
+                tv.launchTask(false, onLaunchResult, getHandler());
                 Task task = tv.getTask();
                 if (task != null) {
                     mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index a7527a6..5fffb50 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -80,7 +80,7 @@
 
     private Task mTask;
     private TaskThumbnailView mSnapshotView;
-    private ImageView mIconView;
+    private IconView mIconView;
     private float mCurveScale;
     private float mCurveDimAlpha;
     private Animator mDimAlphaAnim;
@@ -133,7 +133,7 @@
         return mSnapshotView;
     }
 
-    public ImageView getIconView() {
+    public IconView getIconView() {
         return mIconView;
     }
 
@@ -163,7 +163,7 @@
     @Override
     public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
         mSnapshotView.setThumbnail(task, thumbnailData);
-        mIconView.setImageDrawable(task.icon);
+        mIconView.setDrawable(task.icon);
         mIconView.setOnClickListener(icon -> TaskMenuView.showForTask(this));
         mIconView.setOnLongClickListener(icon -> {
             requestDisallowInterceptTouchEvent(true);
@@ -174,7 +174,7 @@
     @Override
     public void onTaskDataUnloaded() {
         mSnapshotView.setThumbnail(null, null);
-        mIconView.setImageDrawable(null);
+        mIconView.setDrawable(null);
         mIconView.setOnLongClickListener(null);
     }
 
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index c35ab97..ed8c42d 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -45,6 +45,7 @@
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.Thunk;
 
@@ -375,5 +376,5 @@
         return !mText.equals(displayedText);
     }
 
-    public abstract int getControlTypeForLogging();
+    public abstract Target getDropTargetForLogging();
 }
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 28d1129..64a58fb 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -24,10 +24,14 @@
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
+import com.android.launcher3.logging.LoggerUtils;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 
 public class DeleteDropTarget extends ButtonDropTarget {
 
+    private int mControlType = ControlType.DEFAULT_CONTROLTYPE;
+
     public DeleteDropTarget(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -49,6 +53,7 @@
     public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
         super.onDragStart(dragObject, options);
         setTextBasedOnDragSource(dragObject.dragInfo);
+        setControlTypeBasedOnDragSource(dragObject.dragInfo);
     }
 
     /**
@@ -83,6 +88,14 @@
         }
     }
 
+    /**
+     * Set mControlType depending on the drag item.
+     */
+    private void setControlTypeBasedOnDragSource(ItemInfo item) {
+        mControlType = item.id != ItemInfo.NO_ID ? ControlType.REMOVE_TARGET
+                : ControlType.CANCEL_TARGET;
+    }
+
     @Override
     public void completeDrop(DragObject d) {
         ItemInfo item = d.dragInfo;
@@ -106,7 +119,9 @@
     }
 
     @Override
-    public int getControlTypeForLogging() {
-        return ControlType.REMOVE_TARGET;
+    public Target getDropTargetForLogging() {
+        Target t = LoggerUtils.newTarget(Target.Type.CONTROL);
+        t.controlType = mControlType;
+        return t;
     }
 }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index af4faa8..9a9e001 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -283,6 +283,7 @@
         mDragController = new DragController(this);
         mAllAppsController = new AllAppsTransitionController(this);
         mStateManager = new LauncherStateManager(this);
+        UiFactory.onCreate(this);
 
         mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
 
@@ -1154,12 +1155,6 @@
         }
     }
 
-    public void onQuickstepGestureStarted(boolean isVisible) {
-        if (mLauncherCallbacks != null) {
-            mLauncherCallbacks.onQuickstepGestureStarted(isVisible);
-        }
-    }
-
     public AllAppsTransitionController getAllAppsController() {
         return mAllAppsController;
     }
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 6aef658..34bdb3c 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -18,7 +18,6 @@
 
 import android.content.Intent;
 import android.os.Bundle;
-import android.view.Menu;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -70,12 +69,4 @@
      * Extensions points for adding / replacing some other aspects of the Launcher experience.
      */
     boolean hasSettings();
-
-    /**
-     * Called when launcher integrated quickstep and some quickstep gesture started. It can be
-     * called multiple times for a single gesture an UI or background thread.
-     *
-     * @param isVisible if Launcher was visible when the gesture started.
-     */
-    void onQuickstepGestureStarted(boolean isVisible);
 }
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 8311ab9..87ee076 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1171,11 +1171,19 @@
                     mNextPage = getPageNearestToCenterOfScreen(unscaledScrollX);
                     int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
                     int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
-                    if (mSettleOnPageInFreeScroll && unscaledScrollX > firstPageScroll
-                            && unscaledScrollX < lastPageScroll) {
-                        // Make sure we land directly on a page. If flinging past one of the ends,
-                        // don't change the velocity as it will get stopped at the end anyway.
-                        mScroller.setFinalX((int) (getScrollForPage(mNextPage) * getScaleX()));
+                    if (mSettleOnPageInFreeScroll && unscaledScrollX > 0
+                            && unscaledScrollX < mMaxScrollX) {
+                        // If scrolling ends in the half of the added space that is closer to the
+                        // end, settle to the end. Otherwise snap to the nearest page.
+                        // If flinging past one of the ends, don't change the velocity as it will
+                        // get stopped at the end anyway.
+                        final int finalX = unscaledScrollX < firstPageScroll / 2 ?
+                                0 :
+                                unscaledScrollX > (lastPageScroll + mMaxScrollX) / 2 ?
+                                        mMaxScrollX :
+                                        getScrollForPage(mNextPage);
+
+                        mScroller.setFinalX((int) (finalX * getScaleX()));
                         // Ensure the scroll/snap doesn't happen too fast;
                         int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
                                 - mScroller.getDuration();
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 7870af9..76e85e2 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -8,8 +8,6 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
 import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.RECONFIGURE;
 import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.UNINSTALL;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.SETTINGS_BUTTON;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.UNINSTALL_TARGET;
 
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
@@ -33,6 +31,8 @@
 import com.android.launcher3.Launcher.OnResumeCallback;
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.logging.LoggerUtils;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.Themes;
 
@@ -98,8 +98,11 @@
     }
 
     @Override
-    public int getControlTypeForLogging() {
-        return mCurrentAccessibilityAction == UNINSTALL ? UNINSTALL_TARGET : SETTINGS_BUTTON;
+    public Target getDropTargetForLogging() {
+        Target t = LoggerUtils.newTarget(Target.Type.CONTROL);
+        t.controlType = mCurrentAccessibilityAction == UNINSTALL ? ControlType.UNINSTALL_TARGET
+                : ControlType.SETTINGS_BUTTON;
+        return t;
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index f73916c..8f1c8df 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -42,7 +42,7 @@
  */
 public class DiscoveryBounce extends AbstractFloatingView {
 
-    private static final long DELAY_MS = 200;
+    private static final long DELAY_MS = 450;
 
     public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown";
     public static final String SHELF_BOUNCE_SEEN = "launcher.shelf_bounce_seen";
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 01b1424..9d97cb9 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -167,11 +167,10 @@
         if (!(v instanceof ButtonDropTarget)) {
             return newTarget(Target.Type.CONTAINER);
         }
-        Target t = newTarget(Target.Type.CONTROL);
         if (v instanceof ButtonDropTarget) {
-            t.controlType = ((ButtonDropTarget) v).getControlTypeForLogging();
+            return ((ButtonDropTarget) v).getDropTargetForLogging();
         }
-        return t;
+        return newTarget(Target.Type.CONTROL);
     }
 
     public static Target newTarget(int targetType, TargetExtension extension) {
@@ -186,6 +185,7 @@
         t.type = targetType;
         return t;
     }
+
     public static Target newContainerTarget(int containerType) {
         Target t = newTarget(Target.Type.CONTAINER);
         t.containerType = containerType;
@@ -197,11 +197,13 @@
         a.type = type;
         return a;
     }
+
     public static Action newCommandAction(int command) {
         Action a = newAction(Action.Type.COMMAND);
         a.command = command;
         return a;
     }
+
     public static Action newTouchAction(int touch) {
         Action a = newAction(Action.Type.TOUCH);
         a.touch = touch;
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index bf870cc..2c1eb32 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -285,7 +285,7 @@
      * Used primarily for swipe up and down when state changes when swipe up happens from the
      * navbar bezel, the {@param srcChildContainerType} is NAVBAR and
      * {@param srcParentContainerType} is either one of the two
-     * (1) WORKSPACE: if the launcher the foreground activity
+     * (1) WORKSPACE: if the launcher is the foreground activity
      * (2) APP: if another app was the foreground activity
      */
     public void logStateChangeAction(int action, int dir, int srcChildTargetType,
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index bd1a96e..b8cd035 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -40,6 +40,8 @@
 
     public static void onLauncherStateOrFocusChanged(Launcher launcher) { }
 
+    public static void onCreate(Launcher launcher) { }
+
     public static void onStart(Launcher launcher) { }
 
     public static void onLauncherStateOrResumeChanged(Launcher launcher) { }