Merge "Only draw transient taskbar background for transient taskbar" into tm-qpr-dev
diff --git a/Android.bp b/Android.bp
index 6267e9f..0bbb3d2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -153,6 +153,7 @@
         "androidx.cardview_cardview",
         "com.google.android.material_material",
         "iconloader_base",
+        "view_capture"
     ],
     manifest: "AndroidManifest-common.xml",
     sdk_version: "current",
diff --git a/protos/view_capture.proto b/protos/view_capture.proto
deleted file mode 100644
index f363f36..0000000
--- a/protos/view_capture.proto
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-syntax = "proto2";
-
-package com.android.launcher3.view;
-
-option java_outer_classname = "ViewCaptureData";
-
-message ExportedData {
-
-  repeated FrameData frameData = 1;
-  repeated string classname = 2;
-}
-
-message FrameData {
-  optional int64 timestamp = 1;
-  optional ViewNode node = 2;
-}
-
-message ViewNode {
-  optional int32 classname_index = 1;
-  optional int32 hashcode = 2;
-
-  repeated ViewNode children = 3;
-
-  optional string id = 4;
-  optional int32 left = 5;
-  optional int32 top = 6;
-  optional int32 width = 7;
-  optional int32 height = 8;
-  optional int32 scrollX = 9;
-  optional int32 scrollY = 10;
-
-  optional float translationX = 11;
-  optional float translationY = 12;
-  optional float scaleX = 13 [default = 1];
-  optional float scaleY = 14 [default = 1];
-  optional float alpha = 15 [default = 1];
-
-  optional bool willNotDraw = 16;
-  optional bool clipChildren = 17;
-  optional int32 visibility = 18;
-
-  optional float elevation = 19;
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index df39111..eaf577b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -58,6 +58,7 @@
 import android.content.res.Configuration;
 import android.hardware.SensorManager;
 import android.hardware.devicestate.DeviceStateManager;
+import android.media.permission.SafeCloseable;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.IBinder;
@@ -71,10 +72,12 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.app.viewcapture.ViewCapture;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherWidgetHolder;
 import com.android.launcher3.QuickstepAccessibilityDelegate;
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.R;
@@ -119,10 +122,8 @@
 import com.android.launcher3.util.PendingRequestArgs;
 import com.android.launcher3.util.PendingSplitSelectInfo;
 import com.android.launcher3.util.RunnableList;
-import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.TouchController;
-import com.android.launcher3.widget.LauncherAppWidgetHost;
 import com.android.quickstep.OverviewCommandHelper;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.SystemUiProxy;
@@ -135,7 +136,6 @@
 import com.android.quickstep.util.RemoteFadeOutAnimationListener;
 import com.android.quickstep.util.SplitSelectStateController;
 import com.android.quickstep.util.TISBindHelper;
-import com.android.quickstep.util.ViewCapture;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -402,7 +402,7 @@
 
         super.onDestroy();
         mHotseatPredictionController.destroy();
-        mViewCapture.close();
+        if (mViewCapture != null) mViewCapture.close();
     }
 
     @Override
@@ -487,11 +487,11 @@
         return new QuickstepAtomicAnimationFactory(this);
     }
 
-    protected LauncherAppWidgetHost createAppWidgetHost() {
-        LauncherAppWidgetHost appWidgetHost = super.createAppWidgetHost();
-        ApiWrapper.setHostInteractionHandler(appWidgetHost,
-                new QuickstepInteractionHandler(this));
-        return appWidgetHost;
+    @Override
+    protected LauncherWidgetHolder createAppWidgetHolder() {
+        LauncherWidgetHolder appWidgetHolder = super.createAppWidgetHolder();
+        appWidgetHolder.setInteractionHandler(new QuickstepInteractionHandler(this));
+        return appWidgetHolder;
     }
 
     @Override
@@ -503,7 +503,9 @@
         }
         addMultiWindowModeChangedListener(mDepthController);
         initUnfoldTransitionProgressProvider();
-        mViewCapture = ViewCapture.INSTANCE.get(this).startCapture(getWindow());
+        if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
+            mViewCapture = ViewCapture.getInstance().startCapture(getWindow());
+        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index d4b713b..ff7c668 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1892,11 +1892,13 @@
     }
 
     private void finishCurrentTransitionToRecents() {
-        if (mRecentsAnimationController != null
+        if (mRecentsView != null
                 && mActivityInterface.getDesktopVisibilityController() != null
                 && mActivityInterface.getDesktopVisibilityController().areFreeformTasksVisible()) {
-            mRecentsAnimationController.finish(true /* toRecents */,
-                    () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
+            mRecentsView.switchToScreenshot(() -> {
+                mRecentsView.finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
+                        () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
+            });
         } else {
             mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
             if (mRecentsAnimationController != null) {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 80db362..e9f9d80 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -67,6 +67,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
+import com.android.app.viewcapture.ViewCapture;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -103,7 +104,6 @@
 import com.android.quickstep.util.ProtoTracer;
 import com.android.quickstep.util.ProxyScreenStatusProvider;
 import com.android.quickstep.util.SplitScreenBounds;
-import com.android.quickstep.util.ViewCapture;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -1238,7 +1238,9 @@
             }
             mTaskbarManager.dumpLogs("", pw);
 
-            ViewCapture.INSTANCE.get(this).dump(pw, fd);
+            if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
+                ViewCapture.getInstance().dump(pw, fd, this);
+            }
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/ViewCapture.java b/quickstep/src/com/android/quickstep/util/ViewCapture.java
deleted file mode 100644
index ba7d7f5..0000000
--- a/quickstep/src/com/android/quickstep/util/ViewCapture.java
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright (C) 2022 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.util;
-
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.launcher3.util.Executors.createAndStartNewLooper;
-
-import static java.util.stream.Collectors.toList;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.Looper;
-import android.os.Process;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.text.TextUtils;
-import android.util.Base64;
-import android.util.Base64OutputStream;
-import android.util.Log;
-import android.util.Pair;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.View.OnAttachStateChangeListener;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver.OnDrawListener;
-import android.view.Window;
-
-import androidx.annotation.UiThread;
-import androidx.annotation.WorkerThread;
-
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.LooperExecutor;
-import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.launcher3.util.SafeCloseable;
-import com.android.launcher3.view.ViewCaptureData.ExportedData;
-import com.android.launcher3.view.ViewCaptureData.FrameData;
-import com.android.launcher3.view.ViewCaptureData.ViewNode;
-
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.FutureTask;
-import java.util.function.Consumer;
-import java.util.zip.GZIPOutputStream;
-
-/**
- * Utility class for capturing view data every frame
- */
-public class ViewCapture {
-
-    private static final String TAG = "ViewCapture";
-
-    // These flags are copies of two private flags in the View class.
-    private static final int PFLAG_INVALIDATED = 0x80000000;
-    private static final int PFLAG_DIRTY_MASK = 0x00200000;
-
-    // Number of frames to keep in memory
-    private static final int MEMORY_SIZE = 2000;
-    // Initial size of the reference pool. This is at least be 5 * total number of views in
-    // Launcher. This allows the first free frames avoid object allocation during view capture.
-    private static final int INIT_POOL_SIZE = 300;
-
-    public static final MainThreadInitializedObject<ViewCapture> INSTANCE =
-            new MainThreadInitializedObject<>(ViewCapture::new);
-
-    private final List<WindowListener> mListeners = new ArrayList<>();
-
-    private final Context mContext;
-    private final Executor mExecutor;
-
-    // Pool used for capturing view tree on the UI thread.
-    private ViewRef mPool = new ViewRef();
-
-    private ViewCapture(Context context) {
-        mContext = context;
-        if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
-            Looper looper = createAndStartNewLooper("ViewCapture",
-                    Process.THREAD_PRIORITY_FOREGROUND);
-            mExecutor = new LooperExecutor(looper);
-            mExecutor.execute(this::initPool);
-        } else {
-            mExecutor = UI_HELPER_EXECUTOR;
-        }
-    }
-
-    @UiThread
-    private void addToPool(ViewRef start, ViewRef end) {
-        end.next = mPool;
-        mPool = start;
-    }
-
-    @WorkerThread
-    private void initPool() {
-        ViewRef start = new ViewRef();
-        ViewRef current = start;
-
-        for (int i = 0; i < INIT_POOL_SIZE; i++) {
-            current.next = new ViewRef();
-            current = current.next;
-        }
-
-        ViewRef finalCurrent = current;
-        MAIN_EXECUTOR.execute(() -> addToPool(start, finalCurrent));
-    }
-
-    /**
-     * Attaches the ViewCapture to the provided window and returns a handle to detach the listener
-     */
-    public SafeCloseable startCapture(Window window) {
-        String title = window.getAttributes().getTitle().toString();
-        String name = TextUtils.isEmpty(title) ? window.toString() : title;
-        return startCapture(window.getDecorView(), name);
-    }
-
-    /**
-     * Attaches the ViewCapture to the provided window and returns a handle to detach the listener
-     */
-    public SafeCloseable startCapture(View view, String name) {
-        if (!FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
-            return () -> { };
-        }
-
-        WindowListener listener = new WindowListener(view, name);
-        mExecutor.execute(() -> MAIN_EXECUTOR.execute(listener::attachToRoot));
-        mListeners.add(listener);
-        return () -> {
-            mListeners.remove(listener);
-            listener.destroy();
-        };
-    }
-
-    /**
-     * Dumps all the active view captures
-     */
-    public void dump(PrintWriter writer, FileDescriptor out) {
-        if (!FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
-            return;
-        }
-        ViewIdProvider idProvider = new ViewIdProvider(mContext.getResources());
-
-        // Collect all the tasks first so that all the tasks are posted on the executor
-        List<Pair<String, FutureTask<ExportedData>>> tasks = mListeners.stream()
-                .map(l -> {
-                    FutureTask<ExportedData> task =
-                            new FutureTask<ExportedData>(() -> l.dumpToProto(idProvider));
-                    mExecutor.execute(task);
-                    return Pair.create(l.name, task);
-                })
-                .collect(toList());
-
-        tasks.forEach(pair -> {
-            writer.println();
-            writer.println(" ContinuousViewCapture:");
-            writer.println(" window " + pair.first + ":");
-            writer.println("  pkg:" + mContext.getPackageName());
-            writer.print("  data:");
-            writer.flush();
-            try (OutputStream os = new FileOutputStream(out)) {
-                ExportedData data = pair.second.get();
-                OutputStream encodedOS = new GZIPOutputStream(new Base64OutputStream(os,
-                        Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP));
-                data.writeTo(encodedOS);
-                encodedOS.close();
-                os.flush();
-            } catch (Exception e) {
-                Log.e(TAG, "Error capturing proto", e);
-            }
-            writer.println();
-            writer.println("--end--");
-        });
-    }
-
-    private class WindowListener implements OnDrawListener {
-
-        private final View mRoot;
-        public final String name;
-
-        private final ViewRef mViewRef = new ViewRef();
-
-        private int mFrameIndexBg = -1;
-        private boolean mIsFirstFrame = true;
-        private final long[] mFrameTimesBg = new long[MEMORY_SIZE];
-        private final ViewPropertyRef[] mNodesBg = new ViewPropertyRef[MEMORY_SIZE];
-
-        private boolean mDestroyed = false;
-        private final Consumer<ViewRef> mCaptureCallback = this::captureViewPropertiesBg;
-
-        WindowListener(View view, String name) {
-            mRoot = view;
-            this.name = name;
-        }
-
-        @Override
-        public void onDraw() {
-            Trace.beginSection("view_capture");
-            captureViewTree(mRoot, mViewRef);
-            ViewRef captured = mViewRef.next;
-            if (captured != null) {
-                captured.callback = mCaptureCallback;
-                captured.creationTime = SystemClock.uptimeMillis();
-                mExecutor.execute(captured);
-            }
-            mIsFirstFrame = false;
-            Trace.endSection();
-        }
-
-        /**
-         * Captures the View property on the background thread, and transfer all the ViewRef objects
-         * back to the pool
-         */
-        @WorkerThread
-        private void captureViewPropertiesBg(ViewRef viewRefStart) {
-            long time = viewRefStart.creationTime;
-            mFrameIndexBg++;
-            if (mFrameIndexBg >= MEMORY_SIZE) {
-                mFrameIndexBg = 0;
-            }
-            mFrameTimesBg[mFrameIndexBg] = time;
-
-            ViewPropertyRef recycle = mNodesBg[mFrameIndexBg];
-
-            ViewPropertyRef resultStart = null;
-            ViewPropertyRef resultEnd = null;
-
-            ViewRef viewRefEnd = viewRefStart;
-            while (viewRefEnd != null) {
-                ViewPropertyRef propertyRef = recycle;
-                if (propertyRef == null) {
-                    propertyRef = new ViewPropertyRef();
-                } else {
-                    recycle = recycle.next;
-                    propertyRef.next = null;
-                }
-
-                ViewPropertyRef copy = null;
-                if (viewRefEnd.childCount < 0) {
-                    copy = findInLastFrame(viewRefEnd.view.hashCode());
-                    viewRefEnd.childCount = (copy != null) ? copy.childCount : 0;
-                }
-                viewRefEnd.transferTo(propertyRef);
-
-                if (resultStart == null) {
-                    resultStart = propertyRef;
-                    resultEnd = resultStart;
-                } else {
-                    resultEnd.next = propertyRef;
-                    resultEnd = resultEnd.next;
-                }
-
-                if (copy != null) {
-                    int pending = copy.childCount;
-                    while (pending > 0) {
-                        copy = copy.next;
-                        pending = pending - 1 + copy.childCount;
-
-                        propertyRef = recycle;
-                        if (propertyRef == null) {
-                            propertyRef = new ViewPropertyRef();
-                        } else {
-                            recycle = recycle.next;
-                            propertyRef.next = null;
-                        }
-
-                        copy.transferTo(propertyRef);
-
-                        resultEnd.next = propertyRef;
-                        resultEnd = resultEnd.next;
-                    }
-                }
-
-                if (viewRefEnd.next == null) {
-                    // The compiler will complain about using a non-final variable from
-                    // an outer class in a lambda if we pass in viewRefEnd directly.
-                    final ViewRef finalViewRefEnd = viewRefEnd;
-                    MAIN_EXECUTOR.execute(() -> addToPool(viewRefStart, finalViewRefEnd));
-                    break;
-                }
-                viewRefEnd = viewRefEnd.next;
-            }
-            mNodesBg[mFrameIndexBg] = resultStart;
-        }
-
-        private ViewPropertyRef findInLastFrame(int hashCode) {
-            int lastFrameIndex = (mFrameIndexBg == 0) ? MEMORY_SIZE - 1 : mFrameIndexBg - 1;
-            ViewPropertyRef viewPropertyRef = mNodesBg[lastFrameIndex];
-            while (viewPropertyRef != null && viewPropertyRef.hashCode != hashCode) {
-                viewPropertyRef = viewPropertyRef.next;
-            }
-            return viewPropertyRef;
-        }
-
-        void attachToRoot() {
-            if (mRoot.isAttachedToWindow()) {
-                mRoot.getViewTreeObserver().addOnDrawListener(this);
-            } else {
-                mRoot.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
-                    @Override
-                    public void onViewAttachedToWindow(View v) {
-                        if (!mDestroyed) {
-                            mRoot.getViewTreeObserver().addOnDrawListener(WindowListener.this);
-                        }
-                        mRoot.removeOnAttachStateChangeListener(this);
-                    }
-
-                    @Override
-                    public void onViewDetachedFromWindow(View v) { }
-                });
-            }
-        }
-
-        void destroy() {
-            mRoot.getViewTreeObserver().removeOnDrawListener(this);
-            mDestroyed = true;
-        }
-
-        @WorkerThread
-        private ExportedData dumpToProto(ViewIdProvider idProvider) {
-            ExportedData.Builder dataBuilder = ExportedData.newBuilder();
-            ArrayList<Class> classList = new ArrayList<>();
-
-            int size = (mNodesBg[MEMORY_SIZE - 1] == null) ? mFrameIndexBg + 1 : MEMORY_SIZE;
-            for (int i = size - 1; i >= 0; i--) {
-                int index = (MEMORY_SIZE + mFrameIndexBg - i) % MEMORY_SIZE;
-                ViewNode.Builder nodeBuilder = ViewNode.newBuilder();
-                mNodesBg[index].toProto(idProvider, classList, nodeBuilder);
-                dataBuilder.addFrameData(FrameData.newBuilder()
-                        .setNode(nodeBuilder)
-                        .setTimestamp(mFrameTimesBg[index]));
-            }
-            return dataBuilder
-                    .addAllClassname(classList.stream().map(Class::getName).collect(toList()))
-                    .build();
-        }
-
-        private ViewRef captureViewTree(View view, ViewRef start) {
-            ViewRef ref;
-            if (mPool != null) {
-                ref = mPool;
-                mPool = mPool.next;
-                ref.next = null;
-            } else {
-                ref = new ViewRef();
-            }
-            ref.view = view;
-            start.next = ref;
-            if (view instanceof ViewGroup) {
-                ViewGroup parent = (ViewGroup) view;
-                // If a view has not changed since the last frame, we will copy
-                // its children from the last processed frame's data.
-                if ((view.mPrivateFlags & (PFLAG_INVALIDATED | PFLAG_DIRTY_MASK)) == 0
-                        && !mIsFirstFrame) {
-                    // A negative child count is the signal to copy this view from the last frame.
-                    ref.childCount = -parent.getChildCount();
-                    return ref;
-                }
-                ViewRef result = ref;
-                int childCount = ref.childCount = parent.getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    result = captureViewTree(parent.getChildAt(i), result);
-                }
-                return result;
-            } else {
-                ref.childCount = 0;
-                return ref;
-            }
-        }
-    }
-
-    private static class ViewPropertyRef {
-        // We store reference in memory to avoid generating and storing too many strings
-        public Class clazz;
-        public int hashCode;
-        public int childCount = 0;
-
-        public int id;
-        public int left, top, right, bottom;
-        public int scrollX, scrollY;
-
-        public float translateX, translateY;
-        public float scaleX, scaleY;
-        public float alpha;
-        public float elevation;
-
-        public int visibility;
-        public boolean willNotDraw;
-        public boolean clipChildren;
-
-        public ViewPropertyRef next;
-
-        public void transferTo(ViewPropertyRef out) {
-            out.clazz = this.clazz;
-            out.hashCode = this.hashCode;
-            out.childCount = this.childCount;
-            out.id = this.id;
-            out.left = this.left;
-            out.top = this.top;
-            out.right = this.right;
-            out.bottom = this.bottom;
-            out.scrollX = this.scrollX;
-            out.scrollY = this.scrollY;
-            out.scaleX = this.scaleX;
-            out.scaleY = this.scaleY;
-            out.translateX = this.translateX;
-            out.translateY = this.translateY;
-            out.alpha = this.alpha;
-            out.visibility = this.visibility;
-            out.willNotDraw = this.willNotDraw;
-            out.clipChildren = this.clipChildren;
-            out.elevation = this.elevation;
-        }
-
-        /**
-         * Converts the data to the proto representation and returns the next property ref
-         * at the end of the iteration.
-         * @return
-         */
-        public ViewPropertyRef toProto(ViewIdProvider idProvider, ArrayList<Class> classList,
-                ViewNode.Builder outBuilder) {
-            int classnameIndex = classList.indexOf(clazz);
-            if (classnameIndex < 0) {
-                classnameIndex = classList.size();
-                classList.add(clazz);
-            }
-            outBuilder
-                    .setClassnameIndex(classnameIndex)
-                    .setHashcode(hashCode)
-                    .setId(idProvider.getName(id))
-                    .setLeft(left)
-                    .setTop(top)
-                    .setWidth(right - left)
-                    .setHeight(bottom - top)
-                    .setTranslationX(translateX)
-                    .setTranslationY(translateY)
-                    .setScaleX(scaleX)
-                    .setScaleY(scaleY)
-                    .setAlpha(alpha)
-                    .setVisibility(visibility)
-                    .setWillNotDraw(willNotDraw)
-                    .setElevation(elevation)
-                    .setClipChildren(clipChildren);
-
-            ViewPropertyRef result = next;
-            for (int i = 0; (i < childCount) && (result != null); i++) {
-                ViewNode.Builder childBuilder = ViewNode.newBuilder();
-                result = result.toProto(idProvider, classList, childBuilder);
-                outBuilder.addChildren(childBuilder);
-            }
-            return result;
-        }
-    }
-
-    private static class ViewRef implements Runnable {
-        public View view;
-        public int childCount = 0;
-        public ViewRef next;
-
-        public Consumer<ViewRef> callback = null;
-        public long creationTime = 0;
-
-        public void transferTo(ViewPropertyRef out) {
-            out.childCount = this.childCount;
-
-            View view = this.view;
-            this.view = null;
-
-            out.clazz = view.getClass();
-            out.hashCode = view.hashCode();
-            out.id = view.getId();
-            out.left = view.getLeft();
-            out.top = view.getTop();
-            out.right = view.getRight();
-            out.bottom = view.getBottom();
-            out.scrollX = view.getScrollX();
-            out.scrollY = view.getScrollY();
-
-            out.translateX = view.getTranslationX();
-            out.translateY = view.getTranslationY();
-            out.scaleX = view.getScaleX();
-            out.scaleY = view.getScaleY();
-            out.alpha = view.getAlpha();
-            out.elevation = view.getElevation();
-
-            out.visibility = view.getVisibility();
-            out.willNotDraw = view.willNotDraw();
-        }
-
-        @Override
-        public void run() {
-            Consumer<ViewRef> oldCallback = callback;
-            callback = null;
-            if (oldCallback != null) {
-                oldCallback.accept(this);
-            }
-        }
-    }
-
-    private static final class ViewIdProvider {
-
-        private final SparseArray<String> mNames = new SparseArray<>();
-        private final Resources mRes;
-
-        ViewIdProvider(Resources res) {
-            mRes = res;
-        }
-
-        String getName(int id) {
-            String name = mNames.get(id);
-            if (name == null) {
-                if (id >= 0) {
-                    try {
-                        name = mRes.getResourceTypeName(id) + '/' + mRes.getResourceEntryName(id);
-                    } catch (Resources.NotFoundException e) {
-                        name = "id/" + "0x" + Integer.toHexString(id).toUpperCase();
-                    }
-                } else {
-                    name = "NO_ID";
-                }
-                mNames.put(id, name);
-            }
-            return name;
-        }
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 8385afe..5167bd7 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -286,31 +286,23 @@
 
     @Override
     public RunnableList launchTasks() {
-        showDesktopApps();
-        getRecentsView().onTaskLaunchedInLiveTileMode();
+        SystemUiProxy.INSTANCE.get(getContext()).showDesktopApps();
+        getRecentsView().startHome();
         return new RunnableList();
     }
 
     @Nullable
     @Override
     public RunnableList launchTaskAnimated() {
-        RunnableList endCallback = new RunnableList();
-        showDesktopApps();
-        RecentsView<?, ?> recentsView = getRecentsView();
-        recentsView.addSideTaskLaunchCallback(endCallback);
-        return endCallback;
+        return launchTasks();
     }
 
     @Override
     public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
-        showDesktopApps();
+        launchTasks();
         callback.accept(true);
     }
 
-    private void showDesktopApps() {
-        SystemUiProxy.INSTANCE.get(getContext()).showDesktopApps();
-    }
-
     @Override
     void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
         // Sets new thumbnails based on the incoming data and refreshes the rest.
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 555fbb4..76a91c0 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -249,11 +249,11 @@
                                 /* widgetHandler= */ null,
                                 (ItemInfo) mWidgetView.getTag()));
                 mLauncher
-                    .getAppWidgetHost()
-                    .startConfigActivity(
-                            mLauncher,
-                            mWidgetView.getAppWidgetId(),
-                            Launcher.REQUEST_RECONFIGURE_APPWIDGET);
+                        .getAppWidgetHolder()
+                        .startConfigActivity(
+                                mLauncher,
+                                mWidgetView.getAppWidgetId(),
+                                Launcher.REQUEST_RECONFIGURE_APPWIDGET);
             });
             if (!hasSeenReconfigurableWidgetEducationTip()) {
                 post(() -> {
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 6a262c3..a8d371e 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -1027,7 +1027,7 @@
                     R.styleable.ProfileDisplayOption_allAppsIconSize, iconSizes[INDEX_DEFAULT]);
             allAppsIconSizes[INDEX_LANDSCAPE] = a.getFloat(
                     R.styleable.ProfileDisplayOption_allAppsIconSizeLandscape,
-                    iconSizes[INDEX_DEFAULT]);
+                    allAppsIconSizes[INDEX_DEFAULT]);
             allAppsIconSizes[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat(
                     R.styleable.ProfileDisplayOption_allAppsIconSizeTwoPanelPortrait,
                     allAppsIconSizes[INDEX_DEFAULT]);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 07d0f55..7269d14 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -131,6 +131,7 @@
 import com.android.launcher3.allapps.AllAppsStore;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.allapps.BaseAllAppsContainerView;
+import com.android.launcher3.allapps.BaseSearchConfig;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.PropertyListBuilder;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -204,7 +205,6 @@
 import com.android.launcher3.views.FloatingSurfaceView;
 import com.android.launcher3.views.OptionsPopupView;
 import com.android.launcher3.views.ScrimView;
-import com.android.launcher3.widget.LauncherAppWidgetHost;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -316,7 +316,7 @@
     DragLayer mDragLayer;
 
     private WidgetManagerHelper mAppWidgetManager;
-    private LauncherAppWidgetHost mAppWidgetHost;
+    private LauncherWidgetHolder mAppWidgetHolder;
 
     private final int[] mTmpAddItemCellCoordinates = new int[2];
 
@@ -395,6 +395,7 @@
     private LauncherState mPrevLauncherState;
 
     private StringCache mStringCache;
+    private BaseSearchConfig mBaseSearchConfig;
 
     @Override
     @TargetApi(Build.VERSION_CODES.S)
@@ -480,8 +481,8 @@
         mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);
 
         mAppWidgetManager = new WidgetManagerHelper(this);
-        mAppWidgetHost = createAppWidgetHost();
-        mAppWidgetHost.startListening();
+        mAppWidgetHolder = createAppWidgetHolder();
+        mAppWidgetHolder.startListening();
 
         setupViews();
         crossFadeWithPreviousAppearance();
@@ -545,6 +546,9 @@
             getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
         }
         setTitle(R.string.home_screen);
+
+        // TODO: move the SearchConfig to SearchState when new LauncherState is created.
+        mBaseSearchConfig = new BaseSearchConfig();
     }
 
     protected LauncherOverlayManager getDefaultOverlay() {
@@ -958,7 +962,7 @@
         AppWidgetHostView boundWidget = null;
         if (resultCode == RESULT_OK) {
             animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
-            final AppWidgetHostView layout = mAppWidgetHost.createView(this, appWidgetId,
+            final AppWidgetHostView layout = mAppWidgetHolder.createView(this, appWidgetId,
                     requestArgs.getWidgetHandler().getProviderInfo(this));
             boundWidget = layout;
             onCompleteRunnable = new Runnable() {
@@ -969,7 +973,7 @@
                 }
             };
         } else if (resultCode == RESULT_CANCELED) {
-            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+            mAppWidgetHolder.deleteAppWidgetId(appWidgetId);
             animationType = Workspace.CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION;
         }
         if (mDragLayer.getAnimatedView() != null) {
@@ -992,7 +996,7 @@
         }
         hideKeyboard();
         logStopAndResume(false /* isResume */);
-        mAppWidgetHost.setActivityStarted(false);
+        mAppWidgetHolder.setActivityStarted(false);
         NotificationListener.removeNotificationsChangedListener(getPopupDataProvider());
     }
 
@@ -1005,7 +1009,7 @@
             mOverlayManager.onActivityStarted(this);
         }
 
-        mAppWidgetHost.setActivityStarted(true);
+        mAppWidgetHolder.setActivityStarted(true);
         TraceHelper.INSTANCE.endSection(traceToken);
     }
 
@@ -1025,7 +1029,7 @@
         NotificationListener.addNotificationsChangedListener(mPopupDataProvider);
 
         DiscoveryBounce.showForHomeIfNeeded(this);
-        mAppWidgetHost.setActivityResumed(true);
+        mAppWidgetHolder.setActivityResumed(true);
     }
 
     private void logStopAndResume(boolean isResume) {
@@ -1140,7 +1144,7 @@
     @Override
     public void onStateSetEnd(LauncherState state) {
         super.onStateSetEnd(state);
-        getAppWidgetHost().setStateIsNormal(state == LauncherState.NORMAL);
+        getAppWidgetHolder().setStateIsNormal(state == LauncherState.NORMAL);
         getWorkspace().setClipChildren(!state.hasFlag(FLAG_MULTI_PAGE));
 
         finishAutoCancelActionMode();
@@ -1205,7 +1209,7 @@
         if (!mDeferOverlayCallbacks) {
             mOverlayManager.onActivityPaused(this);
         }
-        mAppWidgetHost.setActivityResumed(false);
+        mAppWidgetHolder.setActivityResumed(false);
     }
 
     /**
@@ -1430,7 +1434,7 @@
 
         if (hostView == null) {
             // Perform actual inflation because we're live
-            hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
+            hostView = mAppWidgetHolder.createView(this, appWidgetId, appWidgetInfo);
         }
 
         LauncherAppWidgetInfo launcherInfo;
@@ -1561,12 +1565,12 @@
         return mScrimView;
     }
 
-    public LauncherAppWidgetHost getAppWidgetHost() {
-        return mAppWidgetHost;
+    public LauncherWidgetHolder getAppWidgetHolder() {
+        return mAppWidgetHolder;
     }
 
-    protected LauncherAppWidgetHost createAppWidgetHost() {
-        return new LauncherAppWidgetHost(this,
+    protected LauncherWidgetHolder createAppWidgetHolder() {
+        return new LauncherWidgetHolder(this,
                 appWidgetId -> getWorkspace().removeWidget(appWidgetId));
     }
 
@@ -1592,12 +1596,8 @@
         return mOldConfig.orientation;
     }
 
-    /**
-     * Whether keyboard sync is enabled for transitions between Home and All Apps.
-     * TODO(b/251387263): move this method inside an All Apps specific config class.
-     */
-    public boolean isKeyboardSyncEnabled() {
-        return false;
+    public BaseSearchConfig getSearchConfig() {
+        return mBaseSearchConfig;
     }
 
     @Override
@@ -1732,7 +1732,7 @@
         mRotationHelper.destroy();
 
         try {
-            mAppWidgetHost.stopListening();
+            mAppWidgetHolder.stopListening();
         } catch (NullPointerException ex) {
             Log.w(TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex);
         }
@@ -1907,7 +1907,7 @@
                 appWidgetId = CustomWidgetManager.INSTANCE.get(this).getWidgetIdForCustomProvider(
                         info.componentName);
             } else {
-                appWidgetId = getAppWidgetHost().allocateAppWidgetId();
+                appWidgetId = getAppWidgetHolder().allocateAppWidgetId();
             }
             Bundle options = info.bindOptions;
 
@@ -2021,7 +2021,7 @@
             final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo;
             mWorkspace.removeWorkspaceItem(v);
             if (deleteFromDb) {
-                getModelWriter().deleteWidgetInfo(widgetInfo, getAppWidgetHost(), reason);
+                getModelWriter().deleteWidgetInfo(widgetInfo, getAppWidgetHolder(), reason);
             }
         } else {
             return false;
@@ -2279,7 +2279,7 @@
 
         mWorkspace.clearDropTargets();
         mWorkspace.removeAllWorkspaceScreens();
-        mAppWidgetHost.clearViews();
+        mAppWidgetHolder.clearViews();
 
         if (mHotseat != null) {
             mHotseat.resetLayout(getDeviceProfile().isVerticalBarLayout());
@@ -2586,7 +2586,7 @@
                 if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
                     if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
                         // Id has not been allocated yet. Allocate a new id.
-                        item.appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+                        item.appWidgetId = mAppWidgetHolder.allocateAppWidgetId();
                         item.restoreStatus |= LauncherAppWidgetInfo.FLAG_ID_ALLOCATED;
 
                         // Also try to bind the widget. If the bind fails, the user will be shown
@@ -2648,18 +2648,18 @@
                 // Verify that we own the widget
                 if (appWidgetInfo == null) {
                     FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId);
-                    getModelWriter().deleteWidgetInfo(item, getAppWidgetHost(), removalReason);
+                    getModelWriter().deleteWidgetInfo(item, getAppWidgetHolder(), removalReason);
                     return null;
                 }
 
                 item.minSpanX = appWidgetInfo.minSpanX;
                 item.minSpanY = appWidgetInfo.minSpanY;
-                view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
+                view = mAppWidgetHolder.createView(this, item.appWidgetId, appWidgetInfo);
             } else if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)
                     && appWidgetInfo != null) {
-                mAppWidgetHost.addPendingView(item.appWidgetId,
+                mAppWidgetHolder.addPendingView(item.appWidgetId,
                         new PendingAppWidgetHostView(this, item, mIconCache, false));
-                view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
+                view = mAppWidgetHolder.createView(this, item.appWidgetId, appWidgetInfo);
             } else {
                 view = new PendingAppWidgetHostView(this, item, mIconCache, false);
             }
@@ -3017,7 +3017,8 @@
         writer.println(prefix + "\tmPendingRequestArgs=" + mPendingRequestArgs
                 + " mPendingActivityResult=" + mPendingActivityResult);
         writer.println(prefix + "\tmRotationHelper: " + mRotationHelper);
-        writer.println(prefix + "\tmAppWidgetHost.isListening: " + mAppWidgetHost.isListening());
+        writer.println(prefix + "\tmAppWidgetHolder.isListening: "
+                + mAppWidgetHolder.isListening());
 
         // Extra logging for general debugging
         mDragLayer.dump(prefix, writer);
diff --git a/src/com/android/launcher3/LauncherWidgetHolder.java b/src/com/android/launcher3/LauncherWidgetHolder.java
new file mode 100644
index 0000000..5fcd46f
--- /dev/null
+++ b/src/com/android/launcher3/LauncherWidgetHolder.java
@@ -0,0 +1,187 @@
+/**
+ * Copyright (C) 2022 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;
+
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.widget.LauncherAppWidgetHost;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
+
+import java.util.function.IntConsumer;
+
+/**
+ * A wrapper for LauncherAppWidgetHost. This class is created so the AppWidgetHost could run in
+ * background.
+ */
+public class LauncherWidgetHolder {
+    @NonNull
+    private final LauncherAppWidgetHost mWidgetHost;
+
+    public LauncherWidgetHolder(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public LauncherWidgetHolder(@NonNull Context context,
+            @Nullable IntConsumer appWidgetRemovedCallback) {
+        mWidgetHost = new LauncherAppWidgetHost(context, appWidgetRemovedCallback);
+    }
+
+    /**
+     * Starts listening to the widget updates from the server side
+     */
+    public void startListening() {
+        mWidgetHost.startListening();
+    }
+
+    /**
+     * Set the STARTED state of the widget host
+     * @param isStarted True if setting the host as started, false otherwise
+     */
+    public void setActivityStarted(boolean isStarted) {
+        mWidgetHost.setActivityStarted(isStarted);
+    }
+
+    /**
+     * Set the RESUMED state of the widget host
+     * @param isResumed True if setting the host as resumed, false otherwise
+     */
+    public void setActivityResumed(boolean isResumed) {
+        mWidgetHost.setActivityResumed(isResumed);
+    }
+
+    /**
+     * Set the NORMAL state of the widget host
+     * @param isNormal True if setting the host to be in normal state, false otherwise
+     */
+    public void setStateIsNormal(boolean isNormal) {
+        mWidgetHost.setStateIsNormal(isNormal);
+    }
+
+    /**
+     * Delete the specified app widget from the host
+     * @param appWidgetId The ID of the app widget to be deleted
+     */
+    public void deleteAppWidgetId(int appWidgetId) {
+        mWidgetHost.deleteAppWidgetId(appWidgetId);
+    }
+
+    /**
+     * Add the pending view to the host for complete configuration in further steps
+     * @param appWidgetId The ID of the specified app widget
+     * @param view The {@link PendingAppWidgetHostView} of the app widget
+     */
+    public void addPendingView(int appWidgetId, @NonNull PendingAppWidgetHostView view) {
+        mWidgetHost.addPendingView(appWidgetId, view);
+    }
+
+    /**
+     * @return True if the host is listening to the widget updates, false otherwise
+     */
+    public boolean isListening() {
+        return mWidgetHost.isListening();
+    }
+
+    /**
+     * @return The allocated app widget id if allocation is successful, returns -1 otherwise
+     */
+    public int allocateAppWidgetId() {
+        return mWidgetHost.allocateAppWidgetId();
+    }
+
+    /**
+     * Add a listener that is triggered when the providers of the widgets are changed
+     * @param listener The listener that notifies when the providers changed
+     */
+    public void addProviderChangeListener(
+            @NonNull LauncherAppWidgetHost.ProviderChangedListener listener) {
+        mWidgetHost.addProviderChangeListener(listener);
+    }
+
+    /**
+     * Remove the specified listener from the host
+     * @param listener The listener that is to be removed from the host
+     */
+    public void removeProviderChangeListener(
+            LauncherAppWidgetHost.ProviderChangedListener listener) {
+        mWidgetHost.removeProviderChangeListener(listener);
+    }
+
+    /**
+     * Starts the configuration activity for the widget
+     * @param activity The activity in which to start the configuration page
+     * @param widgetId The ID of the widget
+     * @param requestCode The request code
+     */
+    public void startConfigActivity(@NonNull BaseDraggingActivity activity, int widgetId,
+            int requestCode) {
+        mWidgetHost.startConfigActivity(activity, widgetId, requestCode);
+    }
+
+    /**
+     * Starts the binding flow for the widget
+     * @param activity The activity for which to bind the widget
+     * @param appWidgetId The ID of the widget
+     * @param info The {@link AppWidgetProviderInfo} of the widget
+     * @param requestCode The request code
+     */
+    public void startBindFlow(@NonNull BaseActivity activity,
+            int appWidgetId, @NonNull AppWidgetProviderInfo info, int requestCode) {
+        mWidgetHost.startBindFlow(activity, appWidgetId, info, requestCode);
+    }
+
+    /**
+     * Stop the host from listening to the widget updates
+     */
+    public void stopListening() {
+        mWidgetHost.stopListening();
+    }
+
+    /**
+     * Create a view for the specified app widget
+     * @param context The activity context for which the view is created
+     * @param appWidgetId The ID of the widget
+     * @param info The {@link LauncherAppWidgetProviderInfo} of the widget
+     * @return A view for the widget
+     */
+    @NonNull
+    public AppWidgetHostView createView(@NonNull Context context, int appWidgetId,
+            @NonNull LauncherAppWidgetProviderInfo info) {
+        return mWidgetHost.createView(context, appWidgetId, info);
+    }
+
+    /**
+     * Set the interaction handler for the widget host
+     * @param handler The interaction handler
+     */
+    public void setInteractionHandler(
+            @Nullable LauncherAppWidgetHost.LauncherWidgetInteractionHandler handler) {
+        ApiWrapper.setHostInteractionHandler(mWidgetHost, handler);
+    }
+
+    /**
+     * Clears all the views from the host
+     */
+    public void clearViews() {
+        mWidgetHost.clearViews();
+    }
+}
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 0ee7aae..791cfff 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -288,7 +288,7 @@
             if (widgetId != INVALID_APPWIDGET_ID) {
                 mLauncher.setWaitingForResult(
                         PendingRequestArgs.forWidgetInfo(widgetId, null, info));
-                mLauncher.getAppWidgetHost().startConfigActivity(mLauncher, widgetId,
+                mLauncher.getAppWidgetHolder().startConfigActivity(mLauncher, widgetId,
                         REQUEST_RECONFIGURE_APPWIDGET);
             }
             return null;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index fe8b364..f834cce 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -109,7 +109,6 @@
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.WallpaperOffsetInterpolator;
-import com.android.launcher3.widget.LauncherAppWidgetHost;
 import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.NavigableAppWidgetHostView;
@@ -3391,7 +3390,7 @@
     public void widgetsRestored(final ArrayList<LauncherAppWidgetInfo> changedInfo) {
         if (!changedInfo.isEmpty()) {
             DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,
-                    mLauncher.getAppWidgetHost());
+                    mLauncher.getAppWidgetHolder());
 
             LauncherAppWidgetInfo item = changedInfo.get(0);
             final AppWidgetProviderInfo widgetInfo;
@@ -3517,19 +3516,19 @@
      */
     private class DeferredWidgetRefresh implements Runnable, ProviderChangedListener {
         private final ArrayList<LauncherAppWidgetInfo> mInfos;
-        private final LauncherAppWidgetHost mHost;
+        private final LauncherWidgetHolder mWidgetHolder;
         private final Handler mHandler;
 
         private boolean mRefreshPending;
 
         DeferredWidgetRefresh(ArrayList<LauncherAppWidgetInfo> infos,
-            LauncherAppWidgetHost host) {
+                LauncherWidgetHolder holder) {
             mInfos = infos;
-            mHost = host;
+            mWidgetHolder = holder;
             mHandler = mLauncher.mHandler;
             mRefreshPending = true;
 
-            mHost.addProviderChangeListener(this);
+            mWidgetHolder.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.
             Message msg = Message.obtain(mHandler, this);
@@ -3539,7 +3538,7 @@
 
         @Override
         public void run() {
-            mHost.removeProviderChangeListener(this);
+            mWidgetHolder.removeProviderChangeListener(this);
             mHandler.removeCallbacks(this);
 
             if (!mRefreshPending) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 624cfc2..fa2c6e9 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -76,6 +76,8 @@
                 }
             };
 
+    private static final float ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT = 0f;
+
     public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_TRANSLATION =
             new FloatProperty<AllAppsTransitionController>("allAppsPullBackTranslation") {
 
@@ -92,12 +94,18 @@
                 public void setValue(AllAppsTransitionController controller, float translation) {
                     if (controller.mIsTablet) {
                         controller.mAppsView.getActiveRecyclerView().setTranslationY(translation);
+                        controller.getAppsViewPullbackTranslationY().setValue(
+                                ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT);
                     } else {
                         controller.getAppsViewPullbackTranslationY().setValue(translation);
+                        controller.mAppsView.getActiveRecyclerView().setTranslationY(
+                                ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT);
                     }
                 }
             };
 
+    private static final float ALL_APPS_PULL_BACK_ALPHA_DEFAULT = 1f;
+
     public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_ALPHA =
             new FloatProperty<AllAppsTransitionController>("allAppsPullBackAlpha") {
 
@@ -114,8 +122,12 @@
                 public void setValue(AllAppsTransitionController controller, float alpha) {
                     if (controller.mIsTablet) {
                         controller.mAppsView.getActiveRecyclerView().setAlpha(alpha);
+                        controller.getAppsViewPullbackAlpha().setValue(
+                                ALL_APPS_PULL_BACK_ALPHA_DEFAULT);
                     } else {
                         controller.getAppsViewPullbackAlpha().setValue(alpha);
+                        controller.mAppsView.getActiveRecyclerView().setAlpha(
+                                ALL_APPS_PULL_BACK_ALPHA_DEFAULT);
                     }
                 }
             };
@@ -226,14 +238,14 @@
             StateAnimationConfig config, PendingAnimation builder) {
         if (mLauncher.isInState(ALL_APPS) && !ALL_APPS.equals(toState)) {
             // For atomic animations, we close the keyboard immediately.
-            if (!config.userControlled && !mLauncher.isKeyboardSyncEnabled()) {
+            if (!config.userControlled && !mLauncher.getSearchConfig().isKeyboardSyncEnabled()) {
                 mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard();
             }
 
             builder.addEndListener(success -> {
                 // Reset pull back progress and alpha after switching states.
-                ALL_APPS_PULL_BACK_TRANSLATION.set(this, 0f);
-                ALL_APPS_PULL_BACK_ALPHA.set(this, 1f);
+                ALL_APPS_PULL_BACK_TRANSLATION.set(this, ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT);
+                ALL_APPS_PULL_BACK_ALPHA.set(this, ALL_APPS_PULL_BACK_ALPHA_DEFAULT);
 
                 // We only want to close the keyboard if the animation has completed successfully.
                 // The reason is that with keyboard sync, if the user swipes down from All Apps with
diff --git a/src/com/android/launcher3/allapps/BaseSearchConfig.java b/src/com/android/launcher3/allapps/BaseSearchConfig.java
new file mode 100644
index 0000000..9f47e8d
--- /dev/null
+++ b/src/com/android/launcher3/allapps/BaseSearchConfig.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 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.allapps;
+
+/** Base config values for search. */
+public class BaseSearchConfig {
+    public BaseSearchConfig() {}
+
+    /**
+     * Returns whether to enable the synchronized keyboard transition between Home and All Apps.
+     */
+    public boolean isKeyboardSyncEnabled() {
+        return false;
+    }
+}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 3accf84..037a77e 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -156,6 +156,11 @@
             "ENABLE_SMARTSPACE_DISMISS", true,
             "Adds a menu option to dismiss the current Enhanced Smartspace card.");
 
+    public static final BooleanFlag ENABLE_OVERLAY_CONNECTION_OPTIM = getDebugFlag(
+            "ENABLE_OVERLAY_CONNECTION_OPTIM",
+            false,
+            "Enable optimizing overlay service connection");
+
     /**
      * Enables region sampling for text color: Needs system health assessment before turning on
      */
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 0a68d4a..514e7b2 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -36,6 +36,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.LauncherSettings.Settings;
+import com.android.launcher3.LauncherWidgetHolder;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.FileLog;
@@ -48,7 +49,6 @@
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LooperExecutor;
-import com.android.launcher3.widget.LauncherAppWidgetHost;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -333,13 +333,13 @@
     /**
      * Deletes the widget info and the widget id.
      */
-    public void deleteWidgetInfo(final LauncherAppWidgetInfo info, LauncherAppWidgetHost host,
+    public void deleteWidgetInfo(final LauncherAppWidgetInfo info, LauncherWidgetHolder holder,
             @Nullable final String reason) {
         notifyDelete(Collections.singleton(info));
-        if (host != null && !info.isCustomWidget() && info.isWidgetIdAllocated()) {
+        if (holder != null && !info.isCustomWidget() && info.isWidgetIdAllocated()) {
             // Deleting an app widget ID is a void call but writes to disk before returning
             // to the caller...
-            enqueueDeleteRunnable(() -> host.deleteAppWidgetId(info.appWidgetId));
+            enqueueDeleteRunnable(() -> holder.deleteAppWidgetId(info.appWidgetId));
         }
         deleteItemFromDatabase(info, reason);
     }
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 77992a2..8ff6888 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -270,12 +270,6 @@
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
-        if (ev.getActionIndex() > 0) {
-            // This means there is multiple touch inputs, ignore it, we could also cancel the
-            // previous touch but the user might cancel the drag by accident.
-            return true;
-        }
-
         switch (ev.getAction()) {
             case ACTION_DOWN: {
                 if ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0) {
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index fc1e880..bc3889f 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -92,10 +92,6 @@
 
     // The following member variables are only used during drag-n-drop.
     private boolean mIsInDragMode = false;
-    /** The drag content width which is only set when the drag content scale is not 1f. */
-    private int mDragContentWidth = 0;
-    /** The drag content height which is only set when the drag content scale is not 1f. */
-    private int mDragContentHeight = 0;
 
     private boolean mTrackingWidgetUpdate = false;
 
@@ -314,27 +310,9 @@
         }
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        if (mIsInDragMode && mDragContentWidth > 0 && mDragContentHeight > 0
-                && getChildCount() == 1) {
-            measureChild(getChildAt(0), MeasureSpec.getSize(mDragContentWidth),
-                    MeasureSpec.getSize(mDragContentHeight));
-        }
-    }
-
     /** Starts the drag mode. */
     public void startDrag() {
         mIsInDragMode = true;
-        // In the case of dragging a scaled preview from widgets picker, we should reuse the
-        // previously measured dimension from WidgetCell#measureAndComputeWidgetPreviewScale, which
-        // measures the dimension of a widget preview without its parent's bound before scaling
-        // down.
-        if ((getScaleX() != 1f || getScaleY() != 1f) && getChildCount() == 1) {
-            mDragContentWidth = getChildAt(0).getMeasuredWidth();
-            mDragContentHeight = getChildAt(0).getMeasuredHeight();
-        }
     }
 
     /** Handles a drag event occurred on a workspace page corresponding to the {@code screenId}. */
@@ -347,8 +325,6 @@
     /** Ends the drag mode. */
     public void endDrag() {
         mIsInDragMode = false;
-        mDragContentWidth = 0;
-        mDragContentHeight = 0;
         requestLayout();
     }
 
diff --git a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
index 9313266..9319a9c 100644
--- a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
+++ b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
@@ -55,7 +55,7 @@
 
     public void startBindFlow(Launcher launcher, int appWidgetId, ItemInfo info, int requestCode) {
         launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info));
-        launcher.getAppWidgetHost()
+        launcher.getAppWidgetHolder()
                 .startBindFlow(launcher, appWidgetId, mProviderInfo, requestCode);
     }
 
@@ -77,7 +77,7 @@
             return false;
         }
         launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info));
-        launcher.getAppWidgetHost().startConfigActivity(launcher, appWidgetId, requestCode);
+        launcher.getAppWidgetHolder().startConfigActivity(launcher, appWidgetId, requestCode);
         return true;
     }
 
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 2796721..ce47d70 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -284,6 +284,40 @@
         ensurePreviewWithCallback(callback, cachedPreview);
     }
 
+    private static class ScaledAppWidgetHostView extends LauncherAppWidgetHostView {
+        private boolean mKeepOrigForDragging = true;
+
+        ScaledAppWidgetHostView(Context context) {
+            super(context);
+        }
+
+        /**
+         * Set if the view will keep its original scale when dragged
+         * @param isKeepOrig True if keep original scale when dragged, false otherwise
+         */
+        public void setKeepOrigForDragging(boolean isKeepOrig) {
+            mKeepOrigForDragging = isKeepOrig;
+        }
+
+        /**
+         * @return True if the view is set to preserve original scale when dragged, false otherwise
+         */
+        public boolean isKeepOrigForDragging() {
+            return mKeepOrigForDragging;
+        }
+
+        @Override
+        public void startDrag() {
+            super.startDrag();
+            if (!isKeepOrigForDragging()) {
+                // restore to original scale when being dragged, if set to do so
+                setScaleToFit(1.0f);
+            }
+            // When the drag start, translations need to be set to zero to center the view
+            setTranslationForCentering(0f, 0f);
+        }
+    }
+
     private void applyPreviewOnAppWidgetHostView(WidgetItem item) {
         if (mRemoteViewsPreview != null) {
             mAppWidgetHostViewPreview = createAppWidgetHostView(getContext());
@@ -299,7 +333,7 @@
         // a preview during drag & drop. And thus, we should use LauncherAppWidgetHostView, which
         // supports applying local color extraction during drag & drop.
         mAppWidgetHostViewPreview = isLauncherContext(context)
-                ? new LauncherAppWidgetHostView(context)
+                ? new ScaledAppWidgetHostView(context)
                 : createAppWidgetHostView(context);
         LauncherAppWidgetProviderInfo launcherAppWidgetProviderInfo =
                 LauncherAppWidgetProviderInfo.fromProviderInfo(context, item.widgetInfo.clone());
@@ -398,23 +432,41 @@
             int containerWidth = (int) (mTargetPreviewWidth * mPreviewContainerScale);
             int containerHeight = (int) (mTargetPreviewHeight * mPreviewContainerScale);
             setContainerSize(containerWidth, containerHeight);
+            boolean shouldMeasureAndScale = false;
             if (mAppWidgetHostViewPreview.getChildCount() == 1) {
                 View widgetContent = mAppWidgetHostViewPreview.getChildAt(0);
                 ViewGroup.LayoutParams layoutParams = widgetContent.getLayoutParams();
                 // We only scale preview if both the width & height of the outermost view group are
                 // not set to MATCH_PARENT.
-                boolean shouldScale =
+                shouldMeasureAndScale =
                         layoutParams.width != MATCH_PARENT && layoutParams.height != MATCH_PARENT;
-                if (shouldScale) {
+                if (shouldMeasureAndScale) {
                     setNoClip(mWidgetImageContainer);
                     setNoClip(mAppWidgetHostViewPreview);
                     mAppWidgetHostViewScale = measureAndComputeWidgetPreviewScale();
-                    mAppWidgetHostViewPreview.setScaleToFit(mAppWidgetHostViewScale);
                 }
             }
+
             FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
-                    containerWidth, containerHeight, Gravity.FILL);
+                    mTargetPreviewWidth, mTargetPreviewHeight, Gravity.FILL);
             mAppWidgetHostViewPreview.setLayoutParams(params);
+
+            if (!shouldMeasureAndScale
+                    && mAppWidgetHostViewPreview instanceof ScaledAppWidgetHostView) {
+                // If the view is not measured & scaled, at least one side will match the grid size,
+                // so it should be safe to restore the original scale once it is dragged.
+                ScaledAppWidgetHostView tempView =
+                        (ScaledAppWidgetHostView) mAppWidgetHostViewPreview;
+                tempView.setKeepOrigForDragging(false);
+                tempView.setScaleToFit(mPreviewContainerScale);
+            } else if (!shouldMeasureAndScale) {
+                mAppWidgetHostViewPreview.setScaleToFit(mPreviewContainerScale);
+            } else {
+                mAppWidgetHostViewPreview.setScaleToFit(mAppWidgetHostViewScale);
+            }
+            mAppWidgetHostViewPreview.setTranslationForCentering(
+                    -(params.width - (params.width * mPreviewContainerScale)) / 2.0f,
+                    -(params.height - (params.height * mPreviewContainerScale)) / 2.0f);
             mWidgetImageContainer.addView(mAppWidgetHostViewPreview, /* index= */ 0);
             mWidgetImage.setVisibility(View.GONE);
             applyPreview(null);
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index 46141e0..b18cd47 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -59,7 +59,7 @@
 
         // Cleanup widget id
         if (mWidgetLoadingId != -1) {
-            mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+            mLauncher.getAppWidgetHolder().deleteAppWidgetId(mWidgetLoadingId);
             mWidgetLoadingId = -1;
         }
 
@@ -69,7 +69,7 @@
                 Log.d(TAG, "...removing widget from drag layer");
             }
             mLauncher.getDragLayer().removeView(mInfo.boundWidget);
-            mLauncher.getAppWidgetHost().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId());
+            mLauncher.getAppWidgetHolder().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId());
             mInfo.boundWidget = null;
         }
     }
@@ -94,7 +94,7 @@
         mBindWidgetRunnable = new Runnable() {
             @Override
             public void run() {
-                mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
+                mWidgetLoadingId = mLauncher.getAppWidgetHolder().allocateAppWidgetId();
                 if (LOGD) {
                     Log.d(TAG, "Binding widget, id: " + mWidgetLoadingId);
                 }
@@ -116,7 +116,7 @@
                 if (mWidgetLoadingId == -1) {
                     return;
                 }
-                AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
+                AppWidgetHostView hostView = mLauncher.getAppWidgetHolder().createView(
                         (Context) mLauncher, mWidgetLoadingId, pInfo);
                 mInfo.boundWidget = hostView;
 
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index da8e25c..21b2647 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -321,7 +321,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mActivityContext.getAppWidgetHost().addProviderChangeListener(this);
+        mActivityContext.getAppWidgetHolder().addProviderChangeListener(this);
         notifyWidgetProvidersChanged();
         onRecommendedWidgetsBound();
     }
@@ -329,7 +329,7 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mActivityContext.getAppWidgetHost().removeProviderChangeListener(this);
+        mActivityContext.getAppWidgetHolder().removeProviderChangeListener(this);
         mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView
                 .removeOnAttachStateChangeListener(mBindScrollbarInSearchMode);
         if (mHasWorkProfile) {
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index fa39ce0..0f861eb 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -190,7 +190,7 @@
         waitForLauncherCondition("App widget options did not update",
                 l -> appWidgetManager.getAppWidgetOptions(appWidgetId).getBoolean(
                         WidgetManagerHelper.WIDGET_OPTION_RESTORE_COMPLETED));
-        executeOnLauncher(l -> l.getAppWidgetHost().startListening());
+        executeOnLauncher(l -> l.getAppWidgetHolder().startListening());
         verifyWidgetPresent(info);
         assertNull(mLauncher.getWorkspace().tryGetPendingWidget(100));
     }