Merge "Using edgeEffect for overscroll in all-apps and widget tray" into sc-dev
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index 872f168..350e0d1 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -20,25 +20,17 @@
 import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
 
 import android.annotation.SuppressLint;
-import android.app.ActivityTaskManager;
-import android.app.IAssistDataReceiver;
 import android.app.assist.AssistContent;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Bitmap;
 import android.graphics.Matrix;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.text.TextUtils;
-import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.R;
+import com.android.quickstep.util.AssistContentRequester;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.TaskThumbnailView;
 import com.android.systemui.shared.recents.model.Task;
@@ -53,7 +45,6 @@
     public static final String ACTION_SEARCH = "com.android.quickstep.ACTION_SEARCH";
     public static final String ELAPSED_NANOS = "niu_actions_elapsed_realtime_nanos";
     public static final String ACTIONS_URL = "niu_actions_app_url";
-    private static final String ASSIST_KEY_CONTENT = "content";
     private static final String TAG = "TaskOverlayFactoryGo";
 
     // Empty constructor required for ResourceBasedOverride
@@ -72,13 +63,10 @@
      */
     public static final class TaskOverlayGo<T extends OverviewActionsView> extends TaskOverlay {
         private String mNIUPackageName;
-        private int mTaskId;
-        private Bundle mAssistData;
-        private final Handler mMainThreadHandler;
+        private String mWebUrl;
 
         private TaskOverlayGo(TaskThumbnailView taskThumbnailView) {
             super(taskThumbnailView);
-            mMainThreadHandler = new Handler(Looper.getMainLooper());
         }
 
         /**
@@ -99,28 +87,23 @@
             boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot();
             getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task));
 
-            mTaskId = task.key.id;
-            AssistDataReceiverImpl receiver = new AssistDataReceiverImpl();
-            receiver.setOverlay(this);
-
-            try {
-                ActivityTaskManager.getService().requestAssistDataForTask(receiver, mTaskId,
-                        mApplicationContext.getPackageName());
-            } catch (RemoteException e) {
-                Log.e(TAG, "Unable to request AssistData");
-            }
+            int taskId = task.key.id;
+            AssistContentRequester contentRequester =
+                    new AssistContentRequester(mApplicationContext);
+            contentRequester.requestAssistContent(taskId, this::onAssistContentReceived);
         }
 
-        /**
-         * Called when AssistDataReceiverImpl receives data from ActivityTaskManagerService's
-         * AssistDataRequester
-         */
-        public void onAssistDataReceived(Bundle data) {
-            mMainThreadHandler.post(() -> {
-                if (data != null) {
-                    mAssistData = data;
-                }
-            });
+        /** Provide Assist Content to the overlay. */
+        @VisibleForTesting
+        public void onAssistContentReceived(AssistContent assistContent) {
+            mWebUrl = assistContent.getWebUri() != null
+                    ? assistContent.getWebUri().toString() : null;
+        }
+
+        @Override
+        public void reset() {
+            super.reset();
+            mWebUrl = null;
         }
 
         /**
@@ -139,12 +122,8 @@
                     .setPackage(mNIUPackageName)
                     .putExtra(ELAPSED_NANOS, SystemClock.elapsedRealtimeNanos());
 
-            if (mAssistData != null) {
-                final AssistContent content = mAssistData.getParcelable(ASSIST_KEY_CONTENT);
-                Uri webUri = (content == null) ? null : content.getWebUri();
-                if (webUri != null) {
-                    intent.putExtra(ACTIONS_URL, webUri.toString());
-                }
+            if (mWebUrl != null) {
+                intent.putExtra(ACTIONS_URL, mWebUrl);
             }
 
             return intent;
@@ -191,26 +170,6 @@
     }
 
     /**
-     * Basic AssistDataReceiver. This is passed to ActivityTaskManagerService, which then requests
-     * the data.
-     */
-    private static final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub {
-        private TaskOverlayGo mOverlay;
-
-        public void setOverlay(TaskOverlayGo overlay) {
-            mOverlay = overlay;
-        }
-
-        @Override
-        public void onHandleAssistData(Bundle data) {
-            mOverlay.onAssistDataReceived(data);
-        }
-
-        @Override
-        public void onHandleAssistScreenshot(Bitmap screenshot) {}
-    }
-
-    /**
      * Callbacks the Ui can generate. This is the only way for a Ui to call methods on the
      * controller.
      */
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java b/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java
index 36c0e34..1417995 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java
@@ -102,9 +102,11 @@
     private void notifyChange() {
         // Create a new array to avoid concurrent modification when the activity destroys itself.
         mTempListeners = mListeners.toArray(mTempListeners);
-        for (OnChangeListener listener : mTempListeners) {
+        for (int i = mTempListeners.length - 1; i >= 0; --i) {
+            final OnChangeListener listener = mTempListeners[i];
             if (listener != null) {
                 listener.onExtractedColorsChanged(this);
+                mTempListeners[i] = null;
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/util/AssistContentRequester.java b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
new file mode 100644
index 0000000..3730284
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2021 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 android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.IAssistDataReceiver;
+import android.app.assist.AssistContent;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.launcher3.util.Executors;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Can be used to request the AssistContent from a provided task id, useful for getting the web uri
+ * if provided from the task.
+ */
+public class AssistContentRequester {
+    private static final String TAG = "AssistContentRequester";
+    private static final String ASSIST_KEY_CONTENT = "content";
+
+    /** For receiving content, called on the main thread. */
+    public interface Callback {
+        /**
+         * Called when the {@link android.app.assist.AssistContent} of the requested task is
+         * available.
+         **/
+        void onAssistContentAvailable(AssistContent assistContent);
+    }
+
+    private final IActivityTaskManager mActivityTaskManager;
+    private final String mPackageName;
+    private final Executor mCallbackExecutor;
+
+    public AssistContentRequester(Context context) {
+        mActivityTaskManager = ActivityTaskManager.getService();
+        mPackageName = context.getApplicationContext().getPackageName();
+        mCallbackExecutor = Executors.MAIN_EXECUTOR;
+    }
+
+    /**
+     * Request the {@link AssistContent} from the task with the provided id.
+     *
+     * @param taskId to query for the content.
+     * @param callback to call when the content is available, called on the main thread.
+     */
+    public void requestAssistContent(int taskId, Callback callback) {
+        try {
+            mActivityTaskManager.requestAssistDataForTask(
+                    new AssistDataReceiver(callback, mCallbackExecutor), taskId, mPackageName);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Requesting assist content failed for task: " + taskId, e);
+        }
+    }
+
+    private static final class AssistDataReceiver extends IAssistDataReceiver.Stub {
+
+        private final Executor mExecutor;
+        private final Callback mCallback;
+
+        AssistDataReceiver(Callback callback, Executor callbackExecutor) {
+            mCallback = callback;
+            mExecutor = callbackExecutor;
+        }
+
+        @Override
+        public void onHandleAssistData(Bundle data) {
+            if (data == null) {
+                return;
+            }
+
+            final AssistContent content = data.getParcelable(ASSIST_KEY_CONTENT);
+            if (content == null) {
+                Log.e(TAG, "Received AssistData, but no AssistContent found");
+                return;
+            }
+
+            mExecutor.execute(() -> mCallback.onAssistContentAvailable(content));
+        }
+
+        @Override
+        public void onHandleAssistScreenshot(Bitmap screenshot) {}
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 7693440..a35580f 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -355,6 +355,8 @@
     // The GestureEndTarget that is still in progress.
     private GestureState.GestureEndTarget mCurrentGestureEndTarget;
 
+    IntSet mTopIdSet = new IntSet();
+
     /**
      * TODO: Call reloadIdNeeded in onTaskStackChanged.
      */
@@ -1201,7 +1203,7 @@
                     fullscreenTranslations[i] - fullscreenTranslations[firstNonHomeTaskIndex]);
         }
 
-        updateGridProperties();
+        updateGridProperties(false);
     }
 
     public void getTaskSize(Rect outRect) {
@@ -1674,7 +1676,7 @@
      * This method only calculates the potential position and depends on {@link #setGridProgress} to
      * apply the actual scaling and translation.
      */
-    private void updateGridProperties() {
+    private void updateGridProperties(boolean isTaskDismissal) {
         int taskCount = getTaskViewCount();
         if (taskCount == 0) {
             return;
@@ -1690,6 +1692,10 @@
         IntSet bottomSet = new IntSet();
         float[] gridTranslations = new float[taskCount];
         int firstNonHomeTaskIndex = 0;
+
+        if (!isTaskDismissal) {
+            mTopIdSet.clear();
+        }
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = getTaskViewAt(i);
             if (isHomeTask(taskView)) {
@@ -1699,10 +1705,14 @@
                 continue;
             }
 
-            if (topRowWidth <= bottomRowWidth) {
+            // Evenly distribute tasks between rows unless rearranging due to task dismissal, in
+            // which case keep tasks in their respective rows.
+            if ((!isTaskDismissal && topRowWidth <= bottomRowWidth) || (isTaskDismissal && mTopIdSet
+                    .contains(taskView.getTask().key.id))) {
                 gridTranslations[i] += topAccumulatedTranslationX;
                 topRowWidth += taskView.getLayoutParams().width + mPageSpacing;
                 topSet.add(i);
+                mTopIdSet.add(taskView.getTask().key.id);
 
                 taskView.setGridTranslationY(0);
 
@@ -2066,7 +2076,7 @@
                     } else {
                         snapToPageImmediately(pageToSnapTo);
                         // Grid got messed up, reapply.
-                        updateGridProperties();
+                        updateGridProperties(true);
                     }
                     // Update the layout synchronously so that the position of next view is
                     // immediately available.
diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml
index 09bdaaf..d50115b 100644
--- a/res/values-sw600dp/config.xml
+++ b/res/values-sw600dp/config.xml
@@ -1,3 +1,6 @@
 <resources>
     <bool name="allow_rotation">true</bool>
+
+    <!-- Hotseat -->
+    <bool name="hotseat_transpose_layout_with_orientation">false</bool>
 </resources>
diff --git a/res/values-sw720dp/config.xml b/res/values-sw720dp/config.xml
index ec07591..33fc553 100644
--- a/res/values-sw720dp/config.xml
+++ b/res/values-sw720dp/config.xml
@@ -3,7 +3,4 @@
 <!-- All Apps & Widgets -->
     <!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
     <integer name="config_workspaceSpringLoadShrinkPercentage">90</integer>
-
-<!-- Hotseat -->
-    <bool name="hotseat_transpose_layout_with_orientation">false</bool>
 </resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index fc2b4bc..99f6c75 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -132,6 +132,9 @@
         <attr name="isScalable" format="boolean" />
         <attr name="devicePaddingId" format="reference" />
 
+        <!-- whether the grid option is shown to the user -->
+        <attr name="visible" format="boolean" />
+
     </declare-styleable>
 
     <declare-styleable name="DevicePadding">
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index e38ab74..9b350a1 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -329,6 +329,6 @@
      * views
      */
     public SearchAdapterProvider createSearchAdapterProvider(AllAppsContainerView allapps) {
-        return new DefaultSearchAdapterProvider(this);
+        return new DefaultSearchAdapterProvider(this, allapps);
     }
 }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 9df8d44..7ece72e 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -19,7 +19,6 @@
 import static android.animation.ValueAnimator.areAnimatorsEnabled;
 
 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_FOUR_COLUMNS;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -602,7 +601,7 @@
         if (child instanceof BubbleTextView) {
             BubbleTextView bubbleChild = (BubbleTextView) child;
             bubbleChild.setTextVisibility(mContainerType != HOTSEAT);
-            if (ENABLE_FOUR_COLUMNS.get()) {
+            if (mActivity.getDeviceProfile().isScalableGrid) {
                 bubbleChild.setCenterVertically(mContainerType != HOTSEAT);
             }
         }
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index b0c3bb4..754e988 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -626,6 +626,8 @@
         private final boolean isScalable;
         private final int devicePaddingId;
 
+        public final boolean visible;
+
         private final SparseArray<TypedValue> extraAttrs;
 
         public GridOption(Context context, AttributeSet attrs) {
@@ -652,6 +654,8 @@
             devicePaddingId = a.getResourceId(
                     R.styleable.GridDisplayOption_devicePaddingId, 0);
 
+            visible = a.getBoolean(R.styleable.GridDisplayOption_visible, true);
+
             a.recycle();
 
             extraAttrs = Themes.createValueMap(context, attrs,
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8785fbc..5eba399 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1781,9 +1781,7 @@
     @Override
     public Rect getFolderBoundingBox() {
         // We need to bound the folder to the currently visible workspace area
-        Rect folderBoundingBox = new Rect();
-        getWorkspace().getPageAreaRelativeToDragLayer(folderBoundingBox);
-        return folderBoundingBox;
+        return getWorkspace().getPageAreaRelativeToDragLayer();
     }
 
     @Override
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 57d7600..ccc023a 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -17,8 +17,11 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
-import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
+import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_HOTSEAT_COUNT;
+import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_WORKSPACE_SIZE;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_FOUR_COLUMNS;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -37,10 +40,10 @@
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.pm.InstallSessionTracker;
 import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.util.SettingsCache;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.SafeCloseable;
+import com.android.launcher3.util.SettingsCache;
 import com.android.launcher3.util.SimpleBroadcastReceiver;
 import com.android.launcher3.widget.custom.CustomWidgetManager;
 
@@ -122,6 +125,34 @@
         mContext = context;
 
         mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
+
+        // b/175329686 Temporary logic to gracefully migrate group of users to the new 4x5 grid.
+        String gridName = InvariantDeviceProfile.getCurrentGridName(context);
+        if (ENABLE_FOUR_COLUMNS.get()
+                || "reasonable".equals(gridName)
+                || ENABLE_FOUR_COLUMNS.key.equals(gridName)) {
+            // Reset flag and remove it from developer options to prevent it from being enabled
+            // again.
+            ENABLE_FOUR_COLUMNS.reset(context);
+            FeatureFlags.removeFlag(ENABLE_FOUR_COLUMNS);
+
+            // Force migration code to run
+            Utilities.getPrefs(context).edit()
+                    .remove(KEY_MIGRATION_SRC_HOTSEAT_COUNT)
+                    .remove(KEY_MIGRATION_SRC_WORKSPACE_SIZE)
+                    .apply();
+
+            // We make an empty call here to ensure the database is created with the old IDP grid,
+            // so that when we set the new grid the migration can proceeds as expected.
+            LauncherSettings.Settings.call(context.getContentResolver(), "");
+
+            String newGridName = "practical";
+            Utilities.getPrefs(mContext).edit().putString("idp_grid_name", newGridName).commit();
+            mInvariantDeviceProfile.setCurrentGrid(context, "practical");
+        } else {
+            FeatureFlags.removeFlag(ENABLE_FOUR_COLUMNS);
+        }
+
         mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName);
         mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
         mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext));
diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java
index 25afb55..6c0daa4 100644
--- a/src/com/android/launcher3/LauncherFiles.java
+++ b/src/com/android/launcher3/LauncherFiles.java
@@ -15,6 +15,7 @@
     private static final String XML = ".xml";
 
     public static final String LAUNCHER_DB = "launcher.db";
+    public static final String LAUNCHER_4_BY_5_DB = "launcher_4_by_5.db";
     public static final String LAUNCHER_4_BY_4_DB = "launcher_4_by_4.db";
     public static final String LAUNCHER_3_BY_3_DB = "launcher_3_by_3.db";
     public static final String LAUNCHER_2_BY_2_DB = "launcher_2_by_2.db";
@@ -30,6 +31,7 @@
 
     public static final List<String> ALL_FILES = Collections.unmodifiableList(Arrays.asList(
             LAUNCHER_DB,
+            LAUNCHER_4_BY_5_DB,
             LAUNCHER_4_BY_4_DB,
             LAUNCHER_3_BY_3_DB,
             LAUNCHER_2_BY_2_DB,
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index bd17348..48638f5 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2000,16 +2000,26 @@
     }
 
     /**
-     * Computes the area relative to dragLayer which is used to display a page.
+     * Computes and returns the area relative to dragLayer which is used to display a page.
+     * In case we have multiple pages displayed at the same time, we return the union of the areas.
      */
-    public void getPageAreaRelativeToDragLayer(Rect outArea) {
-        CellLayout child = (CellLayout) getChildAt(getNextPage());
-        if (child == null) {
-            return;
+    public Rect getPageAreaRelativeToDragLayer() {
+        Rect area = new Rect();
+        int nextPage = getNextPage();
+        int panelCount = getPanelCount();
+        for (int page = nextPage; page < nextPage + panelCount; page++) {
+            CellLayout child = (CellLayout) getChildAt(page);
+            if (child == null) {
+                break;
+            }
+
+            ShortcutAndWidgetContainer boundingLayout = child.getShortcutsAndWidgets();
+            Rect tmpRect = new Rect();
+            mLauncher.getDragLayer().getDescendantRectRelativeToSelf(boundingLayout, tmpRect);
+            area.union(tmpRect);
         }
 
-        ShortcutAndWidgetContainer boundingLayout = child.getShortcutsAndWidgets();
-        mLauncher.getDragLayer().getDescendantRectRelativeToSelf(boundingLayout, outArea);
+        return area;
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 60dd774..225e1c1 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -167,6 +167,7 @@
     @Override
     public void onDeviceProfileChanged(DeviceProfile dp) {
         for (AdapterHolder holder : mAH) {
+            holder.adapter.setAppsPerRow(dp.inv.numAllAppsColumns);
             if (holder.recyclerView != null) {
                 // Remove all views and clear the pool, while keeping the data same. After this
                 // call, all the viewHolders will be recreated.
@@ -677,8 +678,7 @@
             applyPadding();
             setupOverlay();
             if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
-                recyclerView.addItemDecoration(new AllAppsSectionDecorator(
-                        AllAppsContainerView.this));
+                recyclerView.addItemDecoration(mSearchAdapterProvider.getDecorator());
             }
         }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index bb175ea..5b4c4c5 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -42,7 +42,6 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
-import com.android.launcher3.allapps.search.SectionDecorationInfo;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.util.PackageManagerHelper;
 
@@ -108,7 +107,7 @@
         // The index of this app not including sections
         public int appIndex = -1;
         // Search section associated to result
-        public SectionDecorationInfo sectionDecorationInfo = null;
+        public DecorationInfo decorationInfo = null;
 
         /**
          * Factory method for AppIcon AdapterItem
diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
deleted file mode 100644
index 0bd2f44..0000000
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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.
- */
-package com.android.launcher3.allapps;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.view.View;
-
-import androidx.annotation.Nullable;
-import androidx.core.graphics.ColorUtils;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.launcher3.R;
-import com.android.launcher3.allapps.search.SearchAdapterProvider;
-import com.android.launcher3.allapps.search.SectionDecorationInfo;
-import com.android.launcher3.util.Themes;
-
-import java.util.List;
-
-/**
- * ItemDecoration class that groups items in {@link AllAppsRecyclerView}
- */
-public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration {
-
-    private final AllAppsContainerView mAppsView;
-
-    AllAppsSectionDecorator(AllAppsContainerView appsContainerView) {
-        mAppsView = appsContainerView;
-    }
-
-    @Override
-    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
-        List<AllAppsGridAdapter.AdapterItem> adapterItems = mAppsView.getApps().getAdapterItems();
-        SearchAdapterProvider adapterProvider = mAppsView.getSearchAdapterProvider();
-        for (int i = 0; i < parent.getChildCount(); i++) {
-            View view = parent.getChildAt(i);
-            int position = parent.getChildAdapterPosition(view);
-            AllAppsGridAdapter.AdapterItem adapterItem = adapterItems.get(position);
-            if (adapterItem.sectionDecorationInfo != null) {
-                SectionDecorationInfo sectionInfo = adapterItem.sectionDecorationInfo;
-                SectionDecorationHandler decorationHandler = sectionInfo.getDecorationHandler();
-                if (decorationHandler != null) {
-                    if (view.equals(adapterProvider.getHighlightedItem())) {
-                        decorationHandler.onFocusDraw(c, view);
-                    } else {
-                        decorationHandler.onGroupDraw(c, view);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Handles grouping and drawing of items in the same all apps sections.
-     */
-    public static class SectionDecorationHandler {
-        protected RectF mBounds = new RectF();
-        private final boolean mIsFullWidth;
-        private final float mRadius;
-
-        protected final int mFocusColor; // main focused item color
-        protected final int mFillcolor; // grouping color
-
-        private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        private final boolean mIsTopRound;
-        private final boolean mIsBottomRound;
-        private float[] mCorners;
-        private float mFillSpacing;
-
-        public SectionDecorationHandler(Context context, boolean isFullWidth, int fillAlpha,
-                boolean isTopRound, boolean isBottomRound) {
-
-            mIsFullWidth = isFullWidth;
-            int endScrim = Themes.getColorBackground(context);
-            mFillcolor = ColorUtils.setAlphaComponent(endScrim, fillAlpha);
-            mFocusColor = endScrim;
-
-            mIsTopRound = isTopRound;
-            mIsBottomRound = isBottomRound;
-
-            mRadius = context.getResources().getDimensionPixelSize(
-                    R.dimen.search_decoration_corner_radius);
-            mFillSpacing = context.getResources().getDimensionPixelSize(
-                    R.dimen.search_decoration_padding);
-            mCorners = new float[]{
-                    mIsTopRound ? mRadius : 0, mIsTopRound ? mRadius : 0, // Top left radius in px
-                    mIsTopRound ? mRadius : 0, mIsTopRound ? mRadius : 0, // Top right radius in px
-                    mIsBottomRound ? mRadius : 0, mIsBottomRound ? mRadius : 0, // Bottom right
-                    mIsBottomRound ? mRadius : 0, mIsBottomRound ? mRadius : 0  // Bottom left
-            };
-
-        }
-
-        /**
-         * Draw bounds onto canvas.
-         */
-        public void onGroupDraw(Canvas canvas, View view) {
-            if (view == null) return;
-            mPaint.setColor(mFillcolor);
-            mBounds.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
-            onDraw(canvas);
-        }
-
-        /**
-         * Draw the bound of the view to the canvas.
-         */
-        public void onFocusDraw(Canvas canvas, @Nullable View view) {
-            if (view == null) {
-                return;
-            }
-            mPaint.setColor(mFocusColor);
-            mBounds.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
-            onDraw(canvas);
-        }
-
-
-        private void onDraw(Canvas canvas) {
-            final Path path = new Path();
-            RectF finalBounds = new RectF(mBounds.left + mFillSpacing,
-                    mBounds.top + mFillSpacing,
-                    mBounds.right - mFillSpacing,
-                    mBounds.bottom - mFillSpacing);
-            path.addRoundRect(finalBounds, mCorners, Path.Direction.CW);
-            canvas.drawPath(path, mPaint);
-        }
-
-        /**
-         * Reset view bounds to empty.
-         */
-        public void reset() {
-            mBounds.setEmpty();
-        }
-    }
-}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index fefd97a..6957850 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -20,7 +20,6 @@
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
-import com.android.launcher3.allapps.search.SectionDecorationInfo;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.util.ItemInfoMatcher;
@@ -288,11 +287,6 @@
         mFastScrollerSections.clear();
         mAdapterItems.clear();
 
-        SectionDecorationInfo appSection = new SectionDecorationInfo();
-        appSection.setDecorationHandler(
-                new AllAppsSectionDecorator.SectionDecorationHandler(mLauncher, true,
-                        0, false, false));
-
         // Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
         // ordered set of sections
 
@@ -313,9 +307,7 @@
                 if (lastFastScrollerSectionInfo.fastScrollToItem == null) {
                     lastFastScrollerSectionInfo.fastScrollToItem = appItem;
                 }
-                if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
-                    appItem.sectionDecorationInfo = appSection;
-                }
+
                 mAdapterItems.add(appItem);
             }
         } else {
diff --git a/src/com/android/launcher3/allapps/DecorationInfo.java b/src/com/android/launcher3/allapps/DecorationInfo.java
new file mode 100644
index 0000000..50b250c
--- /dev/null
+++ b/src/com/android/launcher3/allapps/DecorationInfo.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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;
+
+public class DecorationInfo {
+}
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java
index 34895ed..42ee4b7 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java
@@ -20,7 +20,6 @@
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
-import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler;
 import com.android.launcher3.model.AllAppsList;
 import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.BgDataModel;
@@ -38,14 +37,10 @@
 
     private static final int MAX_RESULTS_COUNT = 5;
 
-    private final SectionDecorationInfo mSearchSectionInfo;
     private final LauncherAppState mLauncherAppState;
 
     public AppsSearchPipeline(Context context, LauncherAppState launcherAppState) {
         mLauncherAppState = launcherAppState;
-        mSearchSectionInfo = new SectionDecorationInfo();
-        mSearchSectionInfo.setDecorationHandler(
-                new SectionDecorationHandler(context, true, 0, true, true));
     }
 
     @Override
@@ -82,7 +77,6 @@
         ArrayList<AdapterItem> items = new ArrayList<>();
         for (int i = 0; i < matchingApps.size() && i < MAX_RESULTS_COUNT; i++) {
             AdapterItem appItem = AdapterItem.asApp(i, "", matchingApps.get(i), i);
-            appItem.sectionDecorationInfo = mSearchSectionInfo;
             items.add(appItem);
         }
 
diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
index ba895ed..ef62da4 100644
--- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
@@ -15,12 +15,17 @@
  */
 package com.android.launcher3.allapps.search;
 
+import android.graphics.Canvas;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsGridAdapter;
 import com.android.launcher3.model.data.ItemInfo;
 
@@ -29,10 +34,19 @@
  */
 public class DefaultSearchAdapterProvider extends SearchAdapterProvider {
 
+    private final RecyclerView.ItemDecoration mDecoration;
     private View mHighlightedView;
 
-    public DefaultSearchAdapterProvider(BaseDraggingActivity launcher) {
-        super(launcher);
+    public DefaultSearchAdapterProvider(BaseDraggingActivity launcher,
+            AllAppsContainerView appsContainerView) {
+        super(launcher, appsContainerView);
+        mDecoration = new RecyclerView.ItemDecoration() {
+            @Override
+            public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent,
+                    @NonNull RecyclerView.State state) {
+                super.onDraw(c, parent, state);
+            }
+        };
     }
 
     @Override
@@ -67,4 +81,9 @@
     public View getHighlightedItem() {
         return mHighlightedView;
     }
+
+    @Override
+    public RecyclerView.ItemDecoration getDecorator() {
+        return mDecoration;
+    }
 }
diff --git a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
index a650a7d..cefb8cb 100644
--- a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
@@ -21,7 +21,10 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.recyclerview.widget.RecyclerView;
+
 import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsGridAdapter;
 
 /**
@@ -31,7 +34,7 @@
 
     protected final BaseDraggingActivity mLauncher;
 
-    public SearchAdapterProvider(BaseDraggingActivity launcher) {
+    public SearchAdapterProvider(BaseDraggingActivity launcher, AllAppsContainerView appsView) {
         mLauncher = launcher;
     }
 
@@ -72,7 +75,7 @@
     }
 
     /**
-     * handles selection event on search adapter item. Returns false if provider can not handle
+     * Handles selection event on search adapter item. Returns false if provider can not handle
      * event
      */
     public abstract boolean launchHighlightedItem();
@@ -82,5 +85,8 @@
      */
     public abstract View getHighlightedItem();
 
-
+    /**
+     * Returns the item decorator.
+     */
+    public abstract RecyclerView.ItemDecoration getDecorator();
 }
diff --git a/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java b/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java
deleted file mode 100644
index 56dd63c..0000000
--- a/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.
- */
-package com.android.launcher3.allapps.search;
-
-import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler;
-
-/**
- * Info class for a search section that is primarily used for decoration.
- */
-public class SectionDecorationInfo {
-    public static final int GROUPING = 1 << 1;
-
-    private String mSectionId;
-    private SectionDecorationHandler mDecorationHandler;
-
-    public SectionDecorationInfo() {
-        this(null);
-    }
-
-    public SectionDecorationInfo(String sectionId) {
-        mSectionId = sectionId;
-    }
-
-    public void setDecorationHandler(SectionDecorationHandler sectionDecorationHandler) {
-        mDecorationHandler = sectionDecorationHandler;
-    }
-
-    public SectionDecorationHandler getDecorationHandler() {
-        return mDecorationHandler;
-    }
-
-    /**
-     * Returns the section's ID
-     */
-    public String getSectionId() {
-        return mSectionId == null ? "" : mSectionId;
-    }
-}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 7f76d27..c7f0133 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -85,7 +85,7 @@
             "ADAPTIVE_ICON_WINDOW_ANIM", true, "Use adaptive icons for window animations.");
 
     public static final BooleanFlag ENABLE_QUICKSTEP_LIVE_TILE = getDebugFlag(
-            "ENABLE_QUICKSTEP_LIVE_TILE", false, "Enable live tile in Quickstep overview");
+            "ENABLE_QUICKSTEP_LIVE_TILE", true, "Enable live tile in Quickstep overview");
 
     // Keep as DeviceFlag to allow remote disable in emergency.
     public static final BooleanFlag ENABLE_SUGGESTED_ACTIONS_OVERVIEW = new DeviceFlag(
@@ -93,7 +93,7 @@
 
 
     public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag(
-            "ENABLE_DEVICE_SEARCH", false, "Allows on device search in all apps");
+            "ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
 
     public static final BooleanFlag FOLDER_NAME_SUGGEST = new DeviceFlag(
             "FOLDER_NAME_SUGGEST", true,
@@ -187,7 +187,7 @@
             "EXPANDED_SMARTSPACE", false, "Expands smartspace height to two rows. "
               + "Any apps occupying the first row will be removed from workspace.");
 
-    public static final BooleanFlag ENABLE_FOUR_COLUMNS = new DeviceFlag(
+    public static final DeviceFlag ENABLE_FOUR_COLUMNS = new DeviceFlag(
             "ENABLE_FOUR_COLUMNS", false, "Uses 4 columns in launcher grid."
             + "Warning: This will permanently alter your home screen items and is not reversible.");
 
@@ -227,6 +227,12 @@
         }
     }
 
+    public static void removeFlag(DebugFlag flag) {
+        synchronized (sDebugFlags) {
+            sDebugFlags.remove(flag);
+        }
+    }
+
     static List<DebugFlag> getDebugFlags() {
         synchronized (sDebugFlags) {
             return new ArrayList<>(sDebugFlags);
@@ -304,6 +310,15 @@
                     .getBoolean(key, defaultValue);
         }
 
+        /**
+         * Resets value to default value.
+         */
+        public void reset(Context context) {
+            mCurrentValue = defaultValue;
+            context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE)
+                    .edit().putBoolean(key, defaultValue).apply();
+        }
+
         @Override
         protected StringBuilder appendProps(StringBuilder src) {
             return super.appendProps(src).append(", mCurrentValue=").append(mCurrentValue);
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index cb42e7a..911f8c3 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -90,7 +90,10 @@
                     parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
                 if ((type == XmlPullParser.START_TAG)
                         && GridOption.TAG_NAME.equals(parser.getName())) {
-                    result.add(new GridOption(getContext(), Xml.asAttributeSet(parser)));
+                    GridOption option = new GridOption(getContext(), Xml.asAttributeSet(parser));
+                    if (option.visible) {
+                        result.add(option);
+                    }
                 }
             }
         } catch (IOException | XmlPullParserException e) {
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 8f4381b..919c89f 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -42,7 +42,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.List;
@@ -90,7 +89,7 @@
         });
     }
 
-    @Test
+//    @Test
     public void workTabExists() {
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -102,7 +101,7 @@
                 launcher -> launcher.getAppsView().isWorkTabVisible(), 60000);
     }
 
-    @Test
+//    @Test
     public void toggleWorks() {
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -133,7 +132,7 @@
                 l -> l.getSystemService(UserManager.class).isQuietModeEnabled(workProfile));
     }
 
-    @Test
+//    @Test
     public void testWorkEduFlow() {
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -176,7 +175,7 @@
         });
     }
 
-    @Test
+//    @Test
     public void testWorkEduIntermittent() {
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);