Merge "Adds fling gesture suppression to Launcher" into ub-launcher3-master
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
index f2e8f96..3ab0f19 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
@@ -70,7 +70,7 @@
         setContentView(R.layout.fallback_recents_activity);
         mRecentsRootView = findViewById(R.id.drag_layer);
         mFallbackRecentsView = findViewById(R.id.overview_panel);
-        mRecentsRootView.setup();
+        mRecentsRootView.recreateControllers();
     }
 
     @Override
@@ -108,7 +108,7 @@
     @Override
     protected void onHandleConfigChanged() {
         super.onHandleConfigChanged();
-        mRecentsRootView.setup();
+        mRecentsRootView.recreateControllers();
     }
 
     @Override
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 2a14504..25a3078 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -50,8 +50,6 @@
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.PagedView;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.config.FeatureFlags;
@@ -351,17 +349,6 @@
                 OverscrollPlugin.class, false /* allowMultiple */);
     }
 
-    private void onDeferredActivityLaunch() {
-        if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
-            mOverviewComponentObserver.getActivityInterface().switchRunningTaskViewToScreenshot(
-                    null, () -> {
-                        mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
-                    });
-        } else {
-            mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
-        }
-    }
-
     private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
         if (!mDeviceState.isUserUnlocked() || mDeviceState.isButtonNavMode()) {
             // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
@@ -562,15 +549,15 @@
             return;
         }
         mDeviceState.enableMultipleRegions(baseInputConsumer instanceof OtherActivityInputConsumer);
-        Launcher l = (Launcher) mOverviewComponentObserver
-            .getActivityInterface().getCreatedActivity();
-        if (l == null || !(l.getOverviewPanel() instanceof RecentsView)) {
+        BaseDraggingActivity activity =
+                mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
+        if (activity == null || !(activity.getOverviewPanel() instanceof RecentsView)) {
             return;
         }
-        ((RecentsView)l.getOverviewPanel())
+        ((RecentsView) activity.getOverviewPanel())
             .setLayoutRotation(mDeviceState.getCurrentActiveRotation(),
                 mDeviceState.getDisplayRotation());
-        l.getDragLayer().recreateControllers();
+        activity.getDragLayer().recreateControllers();
     }
 
     private InputConsumer newBaseConsumer(GestureState previousGestureState,
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
index de5fd7c..2c5d631 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
@@ -21,7 +21,6 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 
-import com.android.launcher3.BaseActivity;
 import com.android.launcher3.R;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TouchController;
@@ -31,13 +30,11 @@
 public class RecentsRootView extends BaseDragLayer<RecentsActivity> {
 
     private static final int MIN_SIZE = 10;
-    private final RecentsActivity mActivity;
 
     private final Point mLastKnownSize = new Point(MIN_SIZE, MIN_SIZE);
 
     public RecentsRootView(Context context, AttributeSet attrs) {
         super(context, attrs, 1 /* alphaChannelCount */);
-        mActivity = BaseActivity.fromContext(context);
         setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                 | SYSTEM_UI_FLAG_LAYOUT_STABLE);
@@ -47,7 +44,8 @@
         return mLastKnownSize;
     }
 
-    public void setup() {
+    @Override
+    public void recreateControllers() {
         mControllers = new TouchController[] {
                 new RecentsTaskController(mActivity),
                 new FallbackNavBarTouchController(mActivity),
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 e674433..3ed7530 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
@@ -287,7 +287,8 @@
 
     @Override
     protected boolean supportsVerticalLandscape() {
-        return FeatureFlags.ENABLE_FIXED_ROTATION_TRANSFORM.get();
+        return FeatureFlags.ENABLE_FIXED_ROTATION_TRANSFORM.get()
+                && !mOrientationState.areMultipleLayoutOrientationsDisabled();
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 34d8adf..b5e6af4 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -169,7 +169,6 @@
                 }
             };
 
-    private final OrientationEventListener mOrientationListener;
     private int mPreviousRotation;
     protected RecentsAnimationController mRecentsAnimationController;
     protected RecentsAnimationTargets mRecentsAnimationTargets;
@@ -377,22 +376,6 @@
 
         // Initialize quickstep specific cache params here, as this is constructed only once
         mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
-        mOrientationListener = new OrientationEventListener(getContext()) {
-            @Override
-            public void onOrientationChanged(int i) {
-                int rotation = RotationHelper.getRotationFromDegrees(i);
-                if (mPreviousRotation != rotation) {
-                    animateRecentsRotationInPlace(rotation);
-                    if (rotation == 0) {
-                        showActionsView();
-                    } else {
-                        hideActionsView();
-                    }
-                    mPreviousRotation = rotation;
-                }
-            }
-        };
-
     }
 
     public OverScroller getScroller() {
@@ -521,13 +504,6 @@
     }
 
     public void setOverviewStateEnabled(boolean enabled) {
-        if (supportsVerticalLandscape() && mOrientationListener.canDetectOrientation()) {
-            if (enabled) {
-                mOrientationListener.enable();
-            } else {
-                mOrientationListener.disable();
-            }
-        }
         mOverviewStateEnabled = enabled;
         updateTaskStackListenerState();
         if (!enabled) {
@@ -968,35 +944,6 @@
         setSwipeDownShouldLaunchApp(true);
     }
 
-    private void animateRecentsRotationInPlace(int newRotation) {
-        if (!supportsVerticalLandscape()) {
-            return;
-        }
-
-        AnimatorSet pa = setRecentsChangedOrientation(true);
-        pa.addListener(AnimationSuccessListener.forRunnable(() -> {
-            updateLayoutRotation(newRotation);
-            ((DragLayer) mActivity.getDragLayer()).recreateControllers();
-            rotateAllChildTasks();
-            setRecentsChangedOrientation(false).start();
-        }));
-        pa.start();
-    }
-
-    public AnimatorSet setRecentsChangedOrientation(boolean fadeInChildren) {
-        getRunningTaskIndex();
-        int runningIndex = getCurrentPage();
-        AnimatorSet as = new AnimatorSet();
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            if (runningIndex == i) {
-                continue;
-            }
-            View taskView = getTaskViewAt(i);
-            as.play(ObjectAnimator.ofFloat(taskView, View.ALPHA, fadeInChildren ? 0 : 1));
-        }
-        return as;
-    }
-
     abstract protected boolean supportsVerticalLandscape();
 
     private void rotateAllChildTasks() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
index 43dc882..671aab0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
@@ -40,7 +40,7 @@
     @Override
     public void setStateWithAnimation(LauncherState toState,
             AnimatorSetBuilder builder, LauncherStateManager.AnimationConfig config) {
-        if (!config.playNonAtomicComponent()) {
+        if (config.onlyPlayAtomicComponent()) {
             return;
         }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BackgroundBlurController.java b/quickstep/src/com/android/launcher3/uioverrides/BackgroundBlurController.java
index 9e4ada7..022a5f7 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BackgroundBlurController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BackgroundBlurController.java
@@ -20,6 +20,7 @@
 
 import android.util.IntProperty;
 import android.view.View;
+
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.LauncherStateManager;
@@ -134,7 +135,7 @@
     @Override
     public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder,
             LauncherStateManager.AnimationConfig config) {
-        if (mSurface == null || !config.playNonAtomicComponent()) {
+        if (mSurface == null || config.onlyPlayAtomicComponent()) {
             return;
         }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index cb9e87a..94e67f0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -88,11 +88,11 @@
     @Override
     public final void setStateWithAnimation(@NonNull final LauncherState toState,
             @NonNull AnimatorSetBuilder builder, @NonNull AnimationConfig config) {
-        if (!config.hasAnimationComponent(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) {
+        if (!config.hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) {
             // The entire recents animation is played atomically.
             return;
         }
-        if (config.hasAnimationComponent(SKIP_OVERVIEW)) {
+        if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
             return;
         }
         setStateWithAnimationInternal(toState, builder, config);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index bc0e75f..1413a5c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -329,6 +329,16 @@
     private BackgroundBlurController mBackgroundBlurController =
             new BackgroundBlurController(this);
 
+    private final ViewTreeObserver.OnDrawListener mOnDrawListener =
+            new ViewTreeObserver.OnDrawListener() {
+                @Override
+                public void onDraw() {
+                    getBackgroundBlurController().setSurfaceToLauncher(mDragLayer);
+                    mDragLayer.post(() -> mDragLayer.getViewTreeObserver().removeOnDrawListener(
+                            this));
+                }
+            };
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         Object traceToken = TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT,
@@ -930,6 +940,8 @@
         final int origDragLayerChildCount = mDragLayer.getChildCount();
         super.onStop();
 
+        mDragLayer.getViewTreeObserver().removeOnDrawListener(mOnDrawListener);
+
         if (mDeferOverlayCallbacks) {
             checkIfOverlayStillDeferred();
         } else {
@@ -970,13 +982,7 @@
         if (!mDeferOverlayCallbacks) {
             mOverlayManager.onActivityStarted(this);
         }
-        mDragLayer.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
-            @Override
-            public void onDraw() {
-                getBackgroundBlurController().setSurfaceToLauncher(mDragLayer);
-                mDragLayer.post(() -> mDragLayer.getViewTreeObserver().removeOnDrawListener(this));
-            }
-        });
+        mDragLayer.getViewTreeObserver().addOnDrawListener(mOnDrawListener);
 
         mAppWidgetHost.setListenIfResumed(true);
         TraceHelper.INSTANCE.endSection(traceToken);
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 8233cdd..04134f2 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -313,10 +313,10 @@
     }
 
     public AnimatorSet createAtomicAnimation(LauncherState fromState, LauncherState toState,
-            AnimatorSetBuilder builder, @AnimationFlags int atomicComponent, long duration) {
+            AnimatorSetBuilder builder, @AnimationFlags int animFlags, long duration) {
         prepareForAtomicAnimation(fromState, toState, builder);
         AnimationConfig config = new AnimationConfig();
-        config.animComponents = atomicComponent;
+        config.mAnimFlags = animFlags;
         config.duration = duration;
         for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) {
             handler.setStateWithAnimation(toState, builder, config);
@@ -371,7 +371,7 @@
             @AnimationFlags int animComponents) {
         mConfig.reset();
         mConfig.userControlled = true;
-        mConfig.animComponents = animComponents;
+        mConfig.mAnimFlags = animComponents;
         mConfig.duration = duration;
         mConfig.playbackController = AnimatorPlaybackController.wrap(
                 createAnimationToNewWorkspaceInternal(state, builder, null), duration)
@@ -585,7 +585,7 @@
         public long duration;
         public boolean userControlled;
         public AnimatorPlaybackController playbackController;
-        public @AnimationFlags int animComponents = ANIM_ALL_COMPONENTS;
+        private @AnimationFlags int mAnimFlags = ANIM_ALL_COMPONENTS;
         private PropertySetter mPropertySetter;
 
         private AnimatorSet mCurrentAnimation;
@@ -599,7 +599,7 @@
         public void reset() {
             duration = 0;
             userControlled = false;
-            animComponents = ANIM_ALL_COMPONENTS;
+            mAnimFlags = ANIM_ALL_COMPONENTS;
             mPropertySetter = null;
             mTargetState = null;
 
@@ -640,19 +640,39 @@
             mCurrentAnimation.addListener(this);
         }
 
+        /**
+         * @return Whether Overview is scaling as part of this animation. If this is the only
+         * component (i.e. NON_ATOMIC_COMPONENT isn't included), then this scaling is happening
+         * atomically, rather than being part of a normal state animation. StateHandlers can use
+         * this to designate part of their animation that should scale with Overview.
+         */
         public boolean playAtomicOverviewScaleComponent() {
-            return hasAnimationComponent(PLAY_ATOMIC_OVERVIEW_SCALE);
+            return hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_SCALE);
         }
 
-        public boolean playNonAtomicComponent() {
-            return hasAnimationComponent(PLAY_NON_ATOMIC);
+        /**
+         * @return Whether this animation will play atomically at the same time as a different,
+         * user-controlled state transition. StateHandlers, which contribute to both animations, can
+         * use this to avoid animating the same properties in both animations, since they'd conflict
+         * with one another.
+         */
+        public boolean onlyPlayAtomicComponent() {
+            return getAnimComponents() == PLAY_ATOMIC_OVERVIEW_SCALE
+                    || getAnimComponents() == PLAY_ATOMIC_OVERVIEW_PEEK;
         }
 
         /**
          * Returns true if the config and any of the provided component flags
          */
-        public boolean hasAnimationComponent(@AnimationFlags int a) {
-            return (animComponents & a) != 0;
+        public boolean hasAnimationFlag(@AnimationFlags int a) {
+            return (mAnimFlags & a) != 0;
+        }
+
+        /**
+         * @return Only the flags that determine which animation components to play.
+         */
+        public @AnimationFlags int getAnimComponents() {
+            return mAnimFlags & ANIM_ALL_COMPONENTS;
         }
     }
 
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 388d074..6653426 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -120,7 +120,7 @@
                     hotseatIconsAlpha, fadeInterpolator);
         }
 
-        if (!config.playNonAtomicComponent()) {
+        if (config.onlyPlayAtomicComponent()) {
             // Only the alpha and scale, handled above, are included in the atomic animation.
             return;
         }
@@ -175,7 +175,8 @@
         float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
         int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0));
 
-        if (config.playNonAtomicComponent()) {
+        if (!config.onlyPlayAtomicComponent()) {
+            // Don't update the scrim during the atomic animation.
             propertySetter.setInt(cl.getScrimBackground(),
                     DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
         }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 0e60f5b..744f4eb 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -162,7 +162,7 @@
             return;
         }
 
-        if (!config.playNonAtomicComponent()) {
+        if (config.onlyPlayAtomicComponent()) {
             // There is no atomic component for the all apps transition, so just return early.
             return;
         }
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 92f35e2..369bf28 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -119,6 +119,7 @@
         recreateControllers();
     }
 
+    @Override
     public void recreateControllers() {
         mControllers = mActivity.createTouchControllers();
     }
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index 184dbb9..07161da 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -15,8 +15,10 @@
  */
 package com.android.launcher3.folder;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.os.Process;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -34,12 +36,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-import java.util.function.Predicate;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -101,27 +100,23 @@
         }
         // If all the icons are from work profile,
         // Then, suggest "Work" as the folder name
-        List<WorkspaceItemInfo> distinctItemInfos = workspaceItemInfos.stream()
-                .filter(distinctByKey(p -> p.user))
-                .collect(Collectors.toList());
-
-        if (distinctItemInfos.size() == 1
-                && !distinctItemInfos.get(0).user.equals(Process.myUserHandle())) {
-            // Place it as last viable suggestion
+        Set<UserHandle> users = workspaceItemInfos.stream().map(w -> w.user)
+                .collect(Collectors.toSet());
+        if (users.size() == 1 && !users.contains(Process.myUserHandle())) {
             setAsLastSuggestion(nameInfos,
                     context.getResources().getString(R.string.work_folder_name));
         }
 
         // If all the icons are from same package (e.g., main icon, shortcut, shortcut)
         // Then, suggest the package's title as the folder name
-        distinctItemInfos = workspaceItemInfos.stream()
-                .filter(distinctByKey(p -> p.getTargetComponent() != null
-                        ? p.getTargetComponent().getPackageName() : ""))
-                .collect(Collectors.toList());
+        Set<String> packageNames = workspaceItemInfos.stream()
+                .map(WorkspaceItemInfo::getTargetComponent)
+                .filter(Objects::nonNull)
+                .map(ComponentName::getPackageName)
+                .collect(Collectors.toSet());
 
-        if (distinctItemInfos.size() == 1) {
-            Optional<AppInfo> info = getAppInfoByPackageName(
-                    distinctItemInfos.get(0).getTargetComponent().getPackageName());
+        if (packageNames.size() == 1) {
+            Optional<AppInfo> info = getAppInfoByPackageName(packageNames.iterator().next());
             // Place it as first viable suggestion and shift everything else
             info.ifPresent(i -> setAsFirstSuggestion(nameInfos, i.title.toString()));
         }
@@ -135,6 +130,7 @@
             return Optional.empty();
         }
         return mAppInfos.stream()
+                .filter(info -> info.componentName != null)
                 .filter(info -> info.componentName.getPackageName().equals(packageName))
                 .findAny();
     }
@@ -174,12 +170,6 @@
                         label.toString()));
     }
 
-    // This method can be moved to some Utility class location.
-    private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
-        Map<Object, Boolean> map = new ConcurrentHashMap<>();
-        return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
-    }
-
     private class FolderNameWorker extends BaseModelUpdateTask {
         @Override
         public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 513bf62..3770d17 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -25,6 +25,9 @@
 import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
 import static com.android.launcher3.logging.LoggerUtils.newTarget;
 import static com.android.launcher3.logging.LoggerUtils.newTouchAction;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.TipType;
 
 import static java.util.Optional.ofNullable;
 
@@ -48,7 +51,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -57,8 +60,11 @@
 import com.android.launcher3.util.LogConfig;
 import com.android.launcher3.util.ResourceBasedOverride;
 
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+import com.google.protobuf.nano.MessageNano;
+
 import java.util.ArrayList;
-import java.util.Locale;
 import java.util.UUID;
 
 /**
@@ -162,7 +168,7 @@
             // Direction DOWN means the task was launched, UP means it was dismissed.
             event.action.dir = direction;
         }
-        event.srcTarget[0].itemType = LauncherLogProto.ItemType.TASK;
+        event.srcTarget[0].itemType = ItemType.TASK;
         event.srcTarget[0].pageIndex = taskIndex;
         fillComponentInfo(event.srcTarget[0], componentKey.componentName);
         dispatchUserEvent(event, null);
@@ -289,7 +295,7 @@
     public void logActionBounceTip(int containerType) {
         LauncherEvent event = newLauncherEvent(newAction(Action.Type.TIP),
                 newContainerTarget(containerType));
-        event.srcTarget[0].tipType = LauncherLogProto.TipType.BOUNCE;
+        event.srcTarget[0].tipType = TipType.BOUNCE;
         dispatchUserEvent(event, null);
     }
 
@@ -316,7 +322,7 @@
             int srcChildTargetType, int srcParentContainerType, int dstContainerType,
             int pageIndex) {
         LauncherEvent event;
-        if (srcChildTargetType == LauncherLogProto.ItemType.TASK) {
+        if (srcChildTargetType == ItemType.TASK) {
             event = newLauncherEvent(newTouchAction(action),
                     newItemTarget(srcChildTargetType),
                     newContainerTarget(srcParentContainerType));
@@ -374,10 +380,11 @@
                 .setElapsedContainerMillis(SystemClock.uptimeMillis() - mElapsedContainerMillis)
                 .setElapsedSessionMillis(
                         SystemClock.uptimeMillis() - mElapsedSessionMillis).build();
-        if (!IS_VERBOSE) {
-            return;
+        try {
+            dispatchUserEvent(LauncherEvent.parseFrom(launcherEvent.toByteArray()), null);
+        } catch (InvalidProtocolBufferNanoException e) {
+            throw new RuntimeException("Cannot convert LauncherEvent from Lite to Nano version.");
         }
-        Log.d(TAG, launcherEvent.toString());
     }
 
     public void logDeepShortcutsOpen(View icon) {
@@ -421,8 +428,8 @@
         action.command = Action.Command.BACK;
         action.dir = isButton ? Action.Direction.NONE :
                 gestureSwipeLeft ? Action.Direction.LEFT : Action.Direction.RIGHT;
-        Target target = newControlTarget(isButton ? LauncherLogProto.ControlType.BACK_BUTTON :
-                LauncherLogProto.ControlType.BACK_GESTURE);
+        Target target = newControlTarget(isButton ? ControlType.BACK_BUTTON :
+                ControlType.BACK_GESTURE);
         target.spanX = downX;
         target.spanY = downY;
         target.cardinality = completed ? 1 : 0;
@@ -471,36 +478,14 @@
         if (!IS_VERBOSE) {
             return;
         }
-        Log.d(TAG, generateLog(ev));
-    }
-
-    /**
-     * Returns a human-readable log for given user event.
-     */
-    public static String generateLog(LauncherEvent ev) {
-        String log = "\n-----------------------------------------------------"
-                + "\naction:" + LoggerUtils.getActionStr(ev.action);
-        if (ev.srcTarget != null && ev.srcTarget.length > 0) {
-            log += "\n Source " + getTargetsStr(ev.srcTarget);
+        LauncherLogProto.LauncherEvent liteLauncherEvent;
+        try {
+            liteLauncherEvent =
+                    LauncherLogProto.LauncherEvent.parseFrom(MessageNano.toByteArray(ev));
+        } catch (InvalidProtocolBufferException e) {
+            throw new RuntimeException("Cannot parse LauncherEvent from Nano to Lite version");
         }
-        if (ev.destTarget != null && ev.destTarget.length > 0) {
-            log += "\n Destination " + getTargetsStr(ev.destTarget);
-        }
-        log += String.format(Locale.US,
-                "\n Elapsed container %d ms, session %d ms, action %d ms",
-                ev.elapsedContainerMillis,
-                ev.elapsedSessionMillis,
-                ev.actionDurationMillis);
-        log += "\n\n";
-        return log;
-    }
-
-    private static String getTargetsStr(Target[] targets) {
-        String result = "child:" + LoggerUtils.getTargetStr(targets[0]);
-        for (int i = 1; i < targets.length; i++) {
-            result += "\tparent:" + LoggerUtils.getTargetStr(targets[i]);
-        }
-        return result;
+        Log.d(TAG, liteLauncherEvent.toString());
     }
 
     /**
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
index 8fffee8..936d377 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -54,6 +54,11 @@
 
     public SecondaryDragLayer(Context context, AttributeSet attrs) {
         super(context, attrs, 1 /* alphaChannelCount */);
+        recreateControllers();
+    }
+
+    @Override
+    public void recreateControllers() {
         mControllers = new TouchController[] {new CloseAllAppsTouchController()};
     }
 
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 254655c..25748ae 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -40,7 +40,6 @@
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.InsettableFrameLayout;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
@@ -116,6 +115,11 @@
     }
 
     /**
+     * Called to reinitialize touch controllers.
+     */
+    public abstract void recreateControllers();
+
+    /**
      * Same as {@link #isEventOverView(View, MotionEvent, View)} where evView == this drag layer.
      */
     public boolean isEventOverView(View view, MotionEvent ev) {