Merge "Prediction icons in Taskbar were updating when dragging icon in the same place"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3984890..b459b2d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -58,6 +58,7 @@
             android:enabled="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.intent.action.SHOW_WORK_APPS" />
                 <category android:name="android.intent.category.HOME" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.MONKEY"/>
diff --git a/quickstep/protos_overrides/launcher_atom_extension.proto b/quickstep/protos_overrides/launcher_atom_extension.proto
index d2dc0cb..ff050ea 100644
--- a/quickstep/protos_overrides/launcher_atom_extension.proto
+++ b/quickstep/protos_overrides/launcher_atom_extension.proto
@@ -23,20 +23,24 @@
 // Message name should match with launcher_atom_extension.proto message at
 // the AOSP level.
 message ExtendedContainers {
+  reserved 2; // Deleted fields
 
   oneof Container{
     DeviceSearchResultContainer device_search_result_container = 1;
-    CorrectedDeviceSearchResultContainer corrected_device_search_result_container = 2;
   }
 }
 
 // Represents on-device search result container.
 message DeviceSearchResultContainer{
   optional int32 query_length = 1;
-}
+  optional SearchAttributes search_attributes = 2;
 
-// Represents on-device search result container with results from spell-corrected query.
-message CorrectedDeviceSearchResultContainer{
-  optional int32 query_length = 1;
-}
+  message SearchAttributes{
 
+    // True if results are based on spell corrected query
+    optional bool corrected_query = 1;
+
+    // True if the item's title/content is a direct match to the search query, false otherwise.
+    optional bool direct_match = 2;
+  }
+}
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index 4404ffb..3f29e43 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -23,6 +23,7 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
+import static com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_PREDICTION_PINNED;
@@ -293,10 +294,9 @@
             case SEARCH_RESULT_CONTAINER:
                 return "search-results";
             case EXTENDED_CONTAINERS: {
-                switch(ci.getExtendedContainers().getContainerCase()) {
-                    case DEVICE_SEARCH_RESULT_CONTAINER:
-                    case CORRECTED_DEVICE_SEARCH_RESULT_CONTAINER:
-                        return "search-results";
+                if (ci.getExtendedContainers().getContainerCase()
+                        == DEVICE_SEARCH_RESULT_CONTAINER) {
+                    return "search-results";
                 }
             }
             default: // fall out
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index bc06944..e218db1 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -249,6 +249,8 @@
     private RunningWindowAnim[] mRunningWindowAnim;
     // Possible second animation running at the same time as mRunningWindowAnim
     private Animator mParallelRunningAnim;
+    // Current running divider animation
+    private ValueAnimator mDividerAnimator;
     private boolean mIsMotionPaused;
     private boolean mHasMotionEverBeenPaused;
 
@@ -831,8 +833,8 @@
         // Notify when the animation starts
         flushOnRecentsAnimationAndLauncherBound();
 
-        TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
-                false /*shown*/, true /*animate*/);
+        // Start hiding the divider
+        setDividerShown(false /* shown */, false /* immediate */);
 
         // Only add the callback to enable the input consumer after we actually have the controller
         mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
@@ -849,8 +851,7 @@
         mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
 
         if (mRecentsAnimationTargets != null) {
-            TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
-                    true /*shown*/, true /*animate*/);
+            setDividerShown(true /* shown */, false /* immediate */);
         }
 
         // Defer clearing the controller and the targets until after we've updated the state
@@ -1000,8 +1001,7 @@
                     mStateCallback.setState(STATE_RESUME_LAST_TASK);
                 }
                 if (mRecentsAnimationTargets != null) {
-                    TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
-                            true /*shown*/, false /*animate*/);
+                    setDividerShown(true /* shown */, true /* immediate */);
                 }
                 break;
         }
@@ -1653,8 +1653,7 @@
         mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
 
         if (mRecentsAnimationTargets != null) {
-            TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
-                    true /*shown*/, false /*animate*/);
+            setDividerShown(true /* shown */, true /* immediate */);
         }
 
         // Leave the pending invisible flag, as it may be used by wallpaper open animation.
@@ -1920,8 +1919,7 @@
     @Override
     public void onRecentsAnimationFinished(RecentsAnimationController controller) {
         if (!controller.getFinishTargetIsLauncher()) {
-            TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
-                    true /*shown*/, true /*animate*/);
+            setDividerShown(true /* shown */, false /* immediate */);
         }
         mRecentsAnimationController = null;
         mRecentsAnimationTargets = null;
@@ -2026,6 +2024,19 @@
         return scaleProgress;
     }
 
+    private void setDividerShown(boolean shown, boolean immediate) {
+        if (mDividerAnimator != null) {
+            mDividerAnimator.cancel();
+        }
+        mDividerAnimator = TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
+                mRecentsAnimationTargets.nonApps, shown, (dividerAnimator) -> {
+                    dividerAnimator.start();
+                    if (immediate) {
+                        dividerAnimator.end();
+                    }
+                });
+    }
+
     /**
      * Used for winscope tracing, see launcher_trace.proto
      * @see com.android.systemui.shared.tracing.ProtoTraceable#writeToProto
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 5b69aeb..e67b0a5 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -88,6 +88,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Utility class for helpful methods related to {@link TaskView} objects and their tasks.
@@ -554,8 +555,16 @@
                 nonAppTargets, depthController, pa);
         if (launcherClosing) {
             // TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app"
-            TaskViewUtils.setSplitAuxiliarySurfacesShown(nonAppTargets,
-                    true /*shown*/, true /*animate*/, pa);
+            TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets, true /*shown*/,
+                    (dividerAnimator) -> {
+                        // If split apps are launching, we want to delay showing the divider bar
+                        // until the very end once the apps are mostly in place. This is because we
+                        // aren't moving the divider leash in the relative position with the
+                        // launching apps.
+                        dividerAnimator.setStartDelay(pa.getDuration()
+                                - SPLIT_DIVIDER_ANIM_DURATION);
+                        pa.add(dividerAnimator);
+                    });
         }
 
         Animator childStateAnimation = null;
@@ -610,16 +619,17 @@
         anim.addListener(windowAnimEndListener);
     }
 
-    public static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps,
-            boolean shown, boolean animate) {
-        setSplitAuxiliarySurfacesShown(nonApps, shown, animate,null);
-    }
-
-    private static void setSplitAuxiliarySurfacesShown(
-            @NonNull RemoteAnimationTargetCompat[] nonApps, boolean shown, boolean animate,
-            @Nullable PendingAnimation splitLaunchAnimation) {
+    /**
+     * Creates an animation to show/hide the auxiliary surfaces (aka. divider bar), only calling
+     * {@param animatorHandler} if there are valid surfaces to animate.
+     *
+     * @return the animator animating the surfaces
+     */
+    public static ValueAnimator createSplitAuxiliarySurfacesAnimator(
+            RemoteAnimationTargetCompat[] nonApps, boolean shown,
+            Consumer<ValueAnimator> animatorHandler) {
         if (nonApps == null || nonApps.length == 0) {
-            return;
+            return null;
         }
 
         SurfaceControl.Transaction t = new SurfaceControl.Transaction();
@@ -634,20 +644,7 @@
             }
         }
         if (!hasSurfaceToAnimate) {
-            return;
-        }
-
-        if (!animate) {
-            for (SurfaceControl leash : auxiliarySurfaces) {
-                t.setAlpha(leash, shown ? 1 : 0);
-                if (shown) {
-                    t.show(leash);
-                } else {
-                    t.hide(leash);
-                }
-            }
-            t.apply();
-            return;
+            return null;
         }
 
         ValueAnimator dockFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
@@ -684,15 +681,7 @@
             }
         });
         dockFadeAnimator.setDuration(SPLIT_DIVIDER_ANIM_DURATION);
-        if (splitLaunchAnimation != null) {
-            // If split apps are launching, we want to delay showing the divider bar until the very
-            // end once the apps are mostly in place. This is because we aren't moving the divider
-            // leash in the relative position with the launching apps.
-            dockFadeAnimator.setStartDelay(
-                    splitLaunchAnimation.getDuration() - SPLIT_DIVIDER_ANIM_DURATION);
-            splitLaunchAnimation.add(dockFadeAnimator);
-        } else {
-            dockFadeAnimator.start();
-        }
+        animatorHandler.accept(dockFadeAnimator);
+        return dockFadeAnimator;
     }
 }
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 676161e..ad52a66 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -48,6 +48,7 @@
 import com.android.launcher3.logger.LauncherAtom.FromState;
 import com.android.launcher3.logger.LauncherAtom.ToState;
 import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer;
+import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer.SearchAttributes;
 import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
@@ -89,6 +90,12 @@
     private static final int EXTENDED_CONTAINERS_HIERARCHY_OFFSET = 300;
     private static final int ATTRIBUTE_MULTIPLIER = 100;
 
+    /**
+     * Flags for converting SearchAttribute to integer value.
+     */
+    private static final int SEARCH_ATTRIBUTES_CORRECTED_QUERY = 1;
+    private static final int SEARCH_ATTRIBUTES_DIRECT_MATCH = 1 << 1;
+
     public static final CopyOnWriteArrayList<StatsLogConsumer> LOGS_CONSUMER =
             new CopyOnWriteArrayList<>();
 
@@ -405,7 +412,10 @@
                     atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */,
                     atomInfo.getFolderIcon().getLabelInfo() /* edittext */,
                     getCardinality(atomInfo) /* cardinality */,
-                    getFeatures(atomInfo) /* features */);
+                    getFeatures(atomInfo) /* features */
+                    // TODO(b/217753033) : Add SearchAttributes field after necessary approval
+                    // getSearchAttributes(atomInfo) /* searchAttributes */
+            );
         }
     }
 
@@ -561,6 +571,25 @@
         return 0;
     }
 
+    private static int getSearchAttributes(LauncherAtom.ItemInfo info) {
+        if (info.getContainerInfo().getExtendedContainers().getDeviceSearchResultContainer()
+                .hasSearchAttributes()) {
+            return searchAttributesToInt(info.getContainerInfo().getExtendedContainers()
+                    .getDeviceSearchResultContainer().getSearchAttributes());
+        }
+        return 0;
+    }
+
+    private static int searchAttributesToInt(SearchAttributes searchAttributes) {
+        int response = 0;
+        if (searchAttributes.getCorrectedQuery()) {
+            response = response | SEARCH_ATTRIBUTES_CORRECTED_QUERY;
+        }
+        if (searchAttributes.getDirectMatch()) {
+            response = response | SEARCH_ATTRIBUTES_DIRECT_MATCH;
+        }
+        return response;
+    }
 
     /**
      * Interface to get stats log while it is dispatched to the system
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 1d14bad..2a2d1dd 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -4297,9 +4297,12 @@
             if (isSuccess) {
                 if (tv.getTaskIds()[1] != -1) {
                     // TODO(b/194414938): make this part of the animations instead.
-                    TaskViewUtils.setSplitAuxiliarySurfacesShown(mRemoteTargetHandles[0]
-                            .getTransformParams().getTargetSet().nonApps,
-                            true /*shown*/, false /*animate*/);
+                    TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
+                            mRemoteTargetHandles[0].getTransformParams().getTargetSet().nonApps,
+                            true /*shown*/, (dividerAnimator) -> {
+                                dividerAnimator.start();
+                                dividerAnimator.end();
+                            });
                 }
                 if (ENABLE_QUICKSTEP_LIVE_TILE.get() && tv.isRunningTask()) {
                     finishRecentsAnimation(false /* toRecents */, null);
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 7f9f63e..6df6212 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -33,7 +33,6 @@
         android:id="@+id/all_apps_header"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_below="@id/search_container_all_apps"
         android:clipToPadding="false"
         android:paddingTop="@dimen/all_apps_header_top_padding"
         android:paddingBottom="@dimen/all_apps_header_bottom_padding"
diff --git a/res/layout/all_apps_content_layout.xml b/res/layout/all_apps_content_layout.xml
deleted file mode 100644
index 5698977..0000000
--- a/res/layout/all_apps_content_layout.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2020 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.
-  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/apps_list_view_override"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_below="@id/search_container_all_apps"
-    android:clipToPadding="false"
-    android:descendantFocusability="afterDescendants"
-    android:focusable="true"
-    android:layout_marginTop="@dimen/all_apps_header_top_padding"
-    android:orientation="vertical">
-</LinearLayout>
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
index 5537bc6..f6a6156 100644
--- a/res/layout/all_apps_fast_scroller.xml
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -21,7 +21,7 @@
         android:id="@+id/fast_scroller_popup"
         style="@style/FastScrollerPopup"
         android:layout_alignParentEnd="true"
-        android:layout_below="@+id/search_container_all_apps"
+        android:layout_alignTop="@+id/all_apps_header"
         android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
 
     <com.android.launcher3.views.RecyclerViewFastScroller
@@ -30,7 +30,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
         android:layout_alignParentEnd="true"
-        android:layout_below="@+id/search_container_all_apps"
+        android:layout_alignTop="@+id/all_apps_header"
         android:layout_marginEnd="@dimen/fastscroll_end_margin"
         launcher:canThumbDetach="true" />
 
diff --git a/res/layout/all_apps_rv_layout.xml b/res/layout/all_apps_rv_layout.xml
index c353b36..26d8ecc 100644
--- a/res/layout/all_apps_rv_layout.xml
+++ b/res/layout/all_apps_rv_layout.xml
@@ -19,7 +19,6 @@
     android:id="@+id/apps_list_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_below="@id/search_container_all_apps"
     android:clipToPadding="false"
     android:descendantFocusability="afterDescendants"
     android:focusable="true" />
diff --git a/res/layout/all_apps_tabs.xml b/res/layout/all_apps_tabs.xml
index de4a69d..cf68f51 100644
--- a/res/layout/all_apps_tabs.xml
+++ b/res/layout/all_apps_tabs.xml
@@ -20,7 +20,6 @@
     android:id="@+id/all_apps_tabs_view_pager"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_below="@id/search_container_all_apps"
     android:layout_gravity="center_horizontal|top"
     android:layout_marginTop="@dimen/all_apps_header_pill_height"
     android:clipChildren="true"
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 59c40cc..661aa00 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -41,6 +41,7 @@
 import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
 import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
+import static com.android.launcher3.logging.StatsLogManager.EventEnum;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ENTRY;
@@ -124,6 +125,7 @@
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsStore;
 import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.allapps.BaseAllAppsContainerView;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.anim.PropertyListBuilder;
@@ -141,6 +143,8 @@
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
+import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.InstanceIdSequence;
@@ -1103,14 +1107,23 @@
                 && mAllAppsSessionLogId == null) {
             // creates new instance ID since new all apps session is started.
             mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId();
-            getStatsLogManager()
-                    .logger()
-                    .log(FeatureFlags.ENABLE_DEVICE_SEARCH.get()
-                            ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
-                            : LAUNCHER_ALLAPPS_ENTRY);
+            getStatsLogManager().logger().withContainerInfo(
+                    ContainerInfo.newBuilder().setWorkspace(
+                            WorkspaceContainer.newBuilder().setPageIndex(
+                                    getWorkspace().getCurrentPage())).build())
+                    .log(getAllAppsEntryEvent());
         }
     }
 
+    /**
+     * Returns {@link EventEnum} that should be logged when Launcher enters into AllApps state.
+     */
+    protected EventEnum getAllAppsEntryEvent() {
+        return FeatureFlags.ENABLE_DEVICE_SEARCH.get()
+                ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
+                : LAUNCHER_ALLAPPS_ENTRY;
+    }
+
     @Override
     public void onStateSetEnd(LauncherState state) {
         super.onStateSetEnd(state);
@@ -1567,6 +1580,7 @@
         boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction());
         boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this);
         hideKeyboard();
+
         if (isActionMain) {
             if (!internalStateHandled) {
                 // In all these cases, only animate if we're already on home
@@ -1595,6 +1609,8 @@
             handleGestureContract(intent);
         } else if (Intent.ACTION_ALL_APPS.equals(intent.getAction())) {
             showAllAppsFromIntent(alreadyOnHome);
+        } else if (Intent.ACTION_SHOW_WORK_APPS.equals(intent.getAction())) {
+            showAllAppsWorkTabFromIntent(alreadyOnHome);
         }
 
         TraceHelper.INSTANCE.endSection(traceToken);
@@ -1605,6 +1621,11 @@
         getStateManager().goToState(ALL_APPS, alreadyOnHome);
     }
 
+    private void showAllAppsWorkTabFromIntent(boolean alreadyOnHome) {
+        showAllAppsFromIntent(alreadyOnHome);
+        mAppsView.switchToTab(BaseAllAppsContainerView.AdapterHolder.WORK);
+    }
+
     /**
      * Handles gesture nav contract
      */
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 070b98e..fb87f88 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -21,6 +21,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.widget.RelativeLayout;
 
 import androidx.core.graphics.ColorUtils;
 import androidx.recyclerview.widget.RecyclerView;
@@ -177,6 +178,28 @@
     }
 
     @Override
+    protected View replaceRVContainer(boolean showTabs) {
+        View rvContainer = super.replaceRVContainer(showTabs);
+        if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+            alignParentTop(rvContainer);
+            layoutAboveSearchContainer(rvContainer);
+        } else {
+            layoutBelowSearchContainer(rvContainer);
+        }
+        return rvContainer;
+    }
+
+    @Override
+    void setupHeader() {
+        super.setupHeader();
+        if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+            alignParentTop(mHeader);
+        } else {
+            layoutBelowSearchContainer(mHeader);
+        }
+    }
+
+    @Override
     protected void updateHeaderScroll(int scrolledOffset) {
         super.updateHeaderScroll(scrolledOffset);
         if (mSearchUiManager.getEditText() == null) {
@@ -202,6 +225,36 @@
 
     @Override
     protected int getHeaderBottom() {
+        if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+            return super.getHeaderBottom();
+        }
         return super.getHeaderBottom() + mSearchContainer.getBottom();
     }
+
+    private void layoutBelowSearchContainer(View v) {
+        if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
+            return;
+        }
+        RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
+        layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
+        layoutParams.removeRule(RelativeLayout.ABOVE);
+        layoutParams.addRule(RelativeLayout.BELOW, R.id.search_container_all_apps);
+    }
+
+    private void layoutAboveSearchContainer(View v) {
+        if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
+            return;
+        }
+        RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
+        layoutParams.addRule(RelativeLayout.ABOVE, R.id.search_container_all_apps);
+    }
+
+    private void alignParentTop(View v) {
+        if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
+            return;
+        }
+        RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
+        layoutParams.removeRule(RelativeLayout.BELOW);
+        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+    }
 }
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index b257407..2b2c7c5 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -331,6 +331,16 @@
         return mViewPager.getNextPage() == 0;
     }
 
+    /**
+     * Switches the current page to the provided {@code tab} if tabs are supported, otherwise does
+     * nothing.
+     */
+    public void switchToTab(int tab) {
+        if (mUsingTabs) {
+            mViewPager.setCurrentPage(tab);
+        }
+    }
+
     public LayoutInflater getLayoutInflater() {
         return LayoutInflater.from(getContext());
     }
@@ -368,8 +378,7 @@
     }
 
     @Override
-    public void onDropCompleted(View target, DragObject d, boolean success) {
-    }
+    public void onDropCompleted(View target, DragObject d, boolean success) {}
 
     @Override
     public void setInsets(Rect insets) {
@@ -478,7 +487,7 @@
         return mHasWorkApps;
     }
 
-    private void replaceRVContainer(boolean showTabs) {
+    protected View replaceRVContainer(boolean showTabs) {
         for (AdapterHolder adapterHolder : mAH) {
             if (adapterHolder.mRecyclerView != null) {
                 adapterHolder.mRecyclerView.setLayoutManager(null);
@@ -503,6 +512,7 @@
             mWorkManager.detachWorkModeSwitch();
             mViewPager = null;
         }
+        return newView;
     }
 
     public View getRecyclerViewContainer() {
@@ -634,7 +644,9 @@
 
     @Override
     public void drawOnScrim(Canvas canvas) {
-        if (!mHeader.isHeaderProtectionSupported()) return;
+        if (!mHeader.isHeaderProtectionSupported()) {
+            return;
+        }
         mHeaderPaint.setColor(mHeaderColor);
         mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor)));
         if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) {
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 9d1b04e..bcb0d14 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -26,12 +26,14 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
+import android.view.ViewGroup;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 
 import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
 
@@ -138,6 +140,15 @@
             mWorkModeSwitch = (WorkModeSwitch) mAllApps.getLayoutInflater().inflate(
                     R.layout.work_mode_fab, mAllApps, false);
         }
+        int workFabMarginBottom =
+                mWorkModeSwitch.getResources().getDimensionPixelSize(R.dimen.work_fab_margin);
+        if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+            workFabMarginBottom <<= 1;  // Double margin to add space above search bar.
+            workFabMarginBottom +=
+                    mWorkModeSwitch.getResources().getDimensionPixelSize(R.dimen.qsb_widget_height);
+        }
+        ((ViewGroup.MarginLayoutParams) mWorkModeSwitch.getLayoutParams()).bottomMargin =
+                workFabMarginBottom;
         if (mWorkModeSwitch.getParent() != mAllApps) {
             mAllApps.addView(mWorkModeSwitch);
         }
@@ -158,7 +169,6 @@
         mWorkModeSwitch = null;
     }
 
-
     public WorkAdapterProvider getAdapterProvider() {
         return mAdapterProvider;
     }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 6e985f5..99c9bb9 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -92,6 +92,10 @@
     public static final BooleanFlag ENABLE_ONE_SEARCH = new DeviceFlag("ENABLE_ONE_SEARCH", false,
             "Use homescreen search box to complete allApps searches");
 
+    public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR =
+            getDebugFlag("ENABLE_FLOATING_SEARCH_BAR", false,
+                    "Keep All Apps search bar at the bottom (but above keyboard if open)");
+
     public static final BooleanFlag COLLECT_SEARCH_HISTORY = new DeviceFlag(
             "COLLECT_SEARCH_HISTORY", false, "Allow launcher to collect search history for log");
 
@@ -249,7 +253,7 @@
             "Enables accessing All Apps from the system Taskbar.");
 
     public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE = getDebugFlag(
-            "ENABLE_SPLIT_FROM_WORKSPACE", false,
+            "ENABLE_SPLIT_FROM_WORKSPACE", true,
             "Enable initiating split screen from workspace.");
 
     public static void initialize(Context context) {
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index f0b4ba0..53c772f 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -16,12 +16,16 @@
 
 package com.android.launcher3.widget;
 
+import android.annotation.TargetApi;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.view.MotionEvent;
@@ -52,6 +56,8 @@
         implements TouchCompleteListener, View.OnLongClickListener,
         LocalColorExtractor.Listener {
 
+    private static final String TAG = "LauncherAppWidgetHostView";
+
     // Related to the auto-advancing of widgets
     private static final long ADVANCE_INTERVAL = 20000;
     private static final long ADVANCE_STAGGER = 250;
@@ -61,6 +67,8 @@
     // Maximum duration for which updates can be deferred.
     private static final long UPDATE_LOCK_TIMEOUT_MILLIS = 1000;
 
+    private static final String TRACE_METHOD_NAME = "appwidget load-widget ";
+
     private final Rect mTempRect = new Rect();
     private final CheckLongPressHelper mLongPressHelper;
     protected final Launcher mLauncher;
@@ -88,6 +96,8 @@
     /** The drag content height which is only set when the drag content scale is not 1f. */
     private int mDragContentHeight = 0;
 
+    private boolean mTrackingWidgetUpdate = false;
+
     public LauncherAppWidgetHostView(Context context) {
         super(context);
         mLauncher = Launcher.getLauncher(context);
@@ -121,7 +131,25 @@
     }
 
     @Override
+    @TargetApi(Build.VERSION_CODES.Q)
+    public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
+        super.setAppWidget(appWidgetId, info);
+        if (!mTrackingWidgetUpdate && Utilities.ATLEAST_Q) {
+            mTrackingWidgetUpdate = true;
+            Trace.beginAsyncSection(TRACE_METHOD_NAME + info.provider, appWidgetId);
+            Log.i(TAG, "App widget created with id: " + appWidgetId);
+        }
+    }
+
+    @Override
+    @TargetApi(Build.VERSION_CODES.Q)
     public void updateAppWidget(RemoteViews remoteViews) {
+        if (mTrackingWidgetUpdate && remoteViews != null && Utilities.ATLEAST_Q) {
+            Log.i(TAG, "App widget with id: " + getAppWidgetId() + " loaded");
+            Trace.endAsyncSection(
+                    TRACE_METHOD_NAME + getAppWidgetInfo().provider, getAppWidgetId());
+            mTrackingWidgetUpdate = false;
+        }
         if (isDeferringUpdates()) {
             mDeferredRemoteViews = remoteViews;
             return;
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 5511770..c22b4da 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -98,7 +98,7 @@
 public final class LauncherInstrumentation {
 
     private static final String TAG = "Tapl";
-    private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20;
+    private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 15;
     private static final int GESTURE_STEP_MS = 16;
     private static final long FORCE_PAUSE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2);