Merge "[Live Tile] Place the target app back above Launcher when swipe up end target is home" into ub-launcher3-master
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index f07aff8..5267760 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -1765,6 +1765,7 @@
         // animation.
         if (mActivity.isInState(OVERVIEW_MODAL_TASK)) {
             mActivity.getStateManager().goToState(LauncherState.OVERVIEW, false);
+            resetModalVisuals();
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index 969fa50..b862936 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -15,12 +15,13 @@
  */
 package com.android.quickstep.util;
 
-import static com.android.launcher3.config.FeatureFlags.ENABLE_LSQ_VELOCITY_PROVIDER;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SYSTEM_VELOCITY_PROVIDER;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.Log;
 import android.view.MotionEvent;
+import android.view.VelocityTracker;
 
 import com.android.launcher3.Alarm;
 import com.android.launcher3.R;
@@ -92,8 +93,8 @@
         mForcePauseTimeout = new Alarm();
         mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
         mMakePauseHarderToTrigger = makePauseHarderToTrigger;
-        mVelocityProvider = ENABLE_LSQ_VELOCITY_PROVIDER.get()
-                ? new LSqVelocityProvider(axis) : new LinearVelocityProvider(axis);
+        mVelocityProvider = ENABLE_SYSTEM_VELOCITY_PROVIDER.get()
+                ? new SystemVelocityProvider(axis) : new LinearVelocityProvider(axis);
     }
 
     /**
@@ -264,141 +265,28 @@
         }
     }
 
-    /**
-     * Java implementation of {@link android.view.VelocityTracker} using the Least Square (deg 2)
-     * algorithm.
-     */
-    private static class LSqVelocityProvider implements VelocityProvider {
+    private static class SystemVelocityProvider implements VelocityProvider {
 
-        // Maximum age of a motion event to be considered when calculating the velocity.
-        private static final long HORIZON_MS = 100;
-        // Number of samples to keep.
-        private static final int HISTORY_SIZE = 20;
-
-        // Position history are stored in a circular array
-        private final float[] mHistoricTimes = new float[HISTORY_SIZE];
-        private final float[] mHistoricPos = new float[HISTORY_SIZE];
-        private int mHistoryCount = 0;
-        private int mHistoryStart = 0;
-
+        private final VelocityTracker mVelocityTracker;
         private final int mAxis;
 
-        LSqVelocityProvider(int axis) {
+        SystemVelocityProvider(int axis) {
+            mVelocityTracker = VelocityTracker.obtain();
             mAxis = axis;
         }
 
         @Override
-        public void clear() {
-            mHistoryCount = mHistoryStart = 0;
-        }
-
-        private void addPositionAndTime(float eventTime, float eventPosition) {
-            mHistoricTimes[mHistoryStart] = eventTime;
-            mHistoricPos[mHistoryStart] = eventPosition;
-            mHistoryStart++;
-            if (mHistoryStart >= HISTORY_SIZE) {
-                mHistoryStart = 0;
-            }
-            mHistoryCount = Math.min(HISTORY_SIZE, mHistoryCount + 1);
+        public Float addMotionEvent(MotionEvent ev, int pointer) {
+            mVelocityTracker.addMovement(ev);
+            mVelocityTracker.computeCurrentVelocity(1); // px / ms
+            return mAxis == MotionEvent.AXIS_X
+                    ? mVelocityTracker.getXVelocity(pointer)
+                    : mVelocityTracker.getYVelocity(pointer);
         }
 
         @Override
-        public Float addMotionEvent(MotionEvent ev, int pointer) {
-            // Add all historic points
-            int historyCount = ev.getHistorySize();
-            for (int i = 0; i < historyCount; i++) {
-                addPositionAndTime(
-                        ev.getHistoricalEventTime(i), ev.getHistoricalAxisValue(mAxis, pointer, i));
-            }
-
-            // Start index for the last position (about to be added)
-            int eventStartIndex = mHistoryStart;
-            addPositionAndTime(ev.getEventTime(), ev.getAxisValue(mAxis, pointer));
-            return solveUnweightedLeastSquaresDeg2(eventStartIndex);
-        }
-
-        /**
-         * Solves the instantaneous velocity.
-         * Based on solveUnweightedLeastSquaresDeg2 in VelocityTracker.cpp
-         */
-        private Float solveUnweightedLeastSquaresDeg2(final int pointPos) {
-            final float eventTime = mHistoricTimes[pointPos];
-
-            float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
-            int count = 0;
-            for (int i = 0; i < mHistoryCount; i++) {
-                int index = pointPos - i;
-                if (index < 0) {
-                    index += HISTORY_SIZE;
-                }
-
-                float time = mHistoricTimes[index];
-                float age = eventTime - time;
-                if (age > HORIZON_MS) {
-                    break;
-                }
-                count++;
-                float xi = -age;
-
-                float yi = mHistoricPos[index];
-                float xi2 = xi * xi;
-                float xi3 = xi2 * xi;
-                float xi4 = xi3 * xi;
-                float xiyi = xi * yi;
-                float xi2yi = xi2 * yi;
-
-                sxi += xi;
-                sxi2 += xi2;
-                sxiyi += xiyi;
-                sxi2yi += xi2yi;
-                syi += yi;
-                sxi3 += xi3;
-                sxi4 += xi4;
-            }
-
-            if (count < 3) {
-                // Too few samples
-                switch (count) {
-                    case 2: {
-                        int endPos = pointPos - 1;
-                        if (endPos < 0) {
-                            endPos += HISTORY_SIZE;
-                        }
-                        float denominator = eventTime - mHistoricTimes[endPos];
-                        if (denominator != 0) {
-                            return (mHistoricPos[pointPos] - mHistoricPos[endPos]) / denominator;
-                        }
-                    }
-                    // fall through
-                    case 1:
-                        return 0f;
-                    default:
-                        return null;
-                }
-            }
-
-            float Sxx = sxi2 - sxi * sxi / count;
-            float Sxy = sxiyi - sxi * syi / count;
-            float Sxx2 = sxi3 - sxi * sxi2 / count;
-            float Sx2y = sxi2yi - sxi2 * syi / count;
-            float Sx2x2 = sxi4 - sxi2 * sxi2 / count;
-
-            float denominator = Sxx * Sx2x2 - Sxx2 * Sxx2;
-            if (denominator == 0) {
-                // division by 0 when computing velocity
-                return null;
-            }
-            // Compute a
-            // float numerator = Sx2y*Sxx - Sxy*Sxx2;
-
-            // Compute b
-            float numerator = Sxy * Sx2x2 - Sx2y * Sxx2;
-            float b = numerator / denominator;
-
-            // Compute c
-            // float c = syi/count - b * sxi/count - a * sxi2/count;
-
-            return b;
+        public void clear() {
+            mVelocityTracker.clear();
         }
     }
 }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 0ab74af..e624dd3 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -92,7 +92,7 @@
 
     // Keep as DeviceFlag to allow remote disable in emergency.
     public static final BooleanFlag ENABLE_SUGGESTED_ACTIONS_OVERVIEW = new DeviceFlag(
-            "ENABLE_SUGGESTED_ACTIONS_OVERVIEW", false, "Show chip hints on the overview screen");
+            "ENABLE_SUGGESTED_ACTIONS_OVERVIEW", true, "Show chip hints on the overview screen");
 
 
     public static final BooleanFlag ENABLE_DEVICE_SEARCH = getDebugFlag(
@@ -161,9 +161,9 @@
             "ENABLE_UNIVERSAL_SMARTSPACE", false,
             "Replace Smartspace with a version rendered by System UI.");
 
-    public static final BooleanFlag ENABLE_LSQ_VELOCITY_PROVIDER = getDebugFlag(
-            "ENABLE_LSQ_VELOCITY_PROVIDER", true,
-            "Use Least Square algorithm for motion pause detection.");
+    public static final BooleanFlag ENABLE_SYSTEM_VELOCITY_PROVIDER = getDebugFlag(
+            "ENABLE_SYSTEM_VELOCITY_PROVIDER", true,
+            "Use system VelocityTracker's algorithm for motion pause detection.");
 
     public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS =
             getDebugFlag(
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index d8eb838..cca9836 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -117,7 +117,8 @@
  *   4) Measure and draw the view on a canvas
  */
 @TargetApi(Build.VERSION_CODES.O)
-public class LauncherPreviewRenderer {
+public class LauncherPreviewRenderer extends ContextThemeWrapper
+        implements ActivityContext, WorkspaceLayoutManager, LayoutInflater.Factory2 {
 
     private static final String TAG = "LauncherPreviewRenderer";
 
@@ -211,10 +212,14 @@
     private final DeviceProfile mDp;
     private final boolean mMigrated;
     private final Rect mInsets;
-
     private final WorkspaceItemInfo mWorkspaceItemInfo;
+    private final LayoutInflater mHomeElementInflater;
+    private final InsettableFrameLayout mRootView;
+    private final Hotseat mHotseat;
+    private final CellLayout mWorkspace;
 
     public LauncherPreviewRenderer(Context context, InvariantDeviceProfile idp, boolean migrated) {
+        super(context, R.style.AppTheme);
         mUiHandler = new Handler(Looper.getMainLooper());
         mContext = context;
         mIdp = idp;
@@ -239,291 +244,286 @@
         mWorkspaceItemInfo.intent = new Intent();
         mWorkspaceItemInfo.contentDescription = mWorkspaceItemInfo.title =
                 context.getString(R.string.label_application);
+
+        mHomeElementInflater = LayoutInflater.from(
+                new ContextThemeWrapper(this, R.style.HomeScreenElementTheme));
+        mHomeElementInflater.setFactory2(this);
+
+        mRootView = (InsettableFrameLayout) mHomeElementInflater.inflate(
+                R.layout.launcher_preview_layout, null, false);
+        mRootView.setInsets(mInsets);
+        measureView(mRootView, mDp.widthPx, mDp.heightPx);
+
+        mHotseat = mRootView.findViewById(R.id.hotseat);
+        mHotseat.resetLayout(false);
+
+        mWorkspace = mRootView.findViewById(R.id.workspace);
+        mWorkspace.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingLeftRightPx,
+                mDp.workspacePadding.top,
+                mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
+                mDp.workspacePadding.bottom);
     }
 
     /** Populate preview and render it. */
     public View getRenderedView() {
-        MainThreadRenderer renderer = new MainThreadRenderer(mContext);
-        renderer.populate();
-        return renderer.mRootView;
+        populate();
+        return mRootView;
     }
 
-    private class MainThreadRenderer extends ContextThemeWrapper
-            implements ActivityContext, WorkspaceLayoutManager, LayoutInflater.Factory2 {
+    public boolean shouldShowRealLauncherPreview() {
+        return ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get();
+    }
 
-        private final LayoutInflater mHomeElementInflater;
-        private final InsettableFrameLayout mRootView;
+    public boolean shouldShowQsb() {
+        return FeatureFlags.QSB_ON_FIRST_SCREEN;
+    }
 
-        private final Hotseat mHotseat;
-        private final CellLayout mWorkspace;
+    @Override
+    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+        if ("TextClock".equals(name)) {
+            // Workaround for TextClock accessing handler for unregistering ticker.
+            return new TextClock(context, attrs) {
 
-        MainThreadRenderer(Context context) {
-            super(context, R.style.AppTheme);
-
-            mHomeElementInflater = LayoutInflater.from(
-                    new ContextThemeWrapper(this, R.style.HomeScreenElementTheme));
-            mHomeElementInflater.setFactory2(this);
-
-            mRootView = (InsettableFrameLayout) mHomeElementInflater.inflate(
-                    R.layout.launcher_preview_layout, null, false);
-            mRootView.setInsets(mInsets);
-            measureView(mRootView, mDp.widthPx, mDp.heightPx);
-
-            mHotseat = mRootView.findViewById(R.id.hotseat);
-            mHotseat.resetLayout(false);
-
-            mWorkspace = mRootView.findViewById(R.id.workspace);
-            mWorkspace.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingLeftRightPx,
-                    mDp.workspacePadding.top,
-                    mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
-                    mDp.workspacePadding.bottom);
+                @Override
+                public Handler getHandler() {
+                    return mUiHandler;
+                }
+            };
+        } else if (!"fragment".equals(name)) {
+            return null;
         }
 
-        @Override
-        public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
-            if ("TextClock".equals(name)) {
-                // Workaround for TextClock accessing handler for unregistering ticker.
-                return new TextClock(context, attrs) {
+        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PreviewFragment);
+        FragmentWithPreview f = (FragmentWithPreview) Fragment.instantiate(
+                context, ta.getString(R.styleable.PreviewFragment_android_name));
+        f.enterPreviewMode(context);
+        f.onInit(null);
 
-                    @Override
-                    public Handler getHandler() {
-                        return mUiHandler;
-                    }
-                };
-            } else if (!"fragment".equals(name)) {
-                return null;
-            }
+        View view = f.onCreateView(LayoutInflater.from(context), (ViewGroup) parent, null);
+        view.setId(ta.getInt(R.styleable.PreviewFragment_android_id, View.NO_ID));
+        return view;
+    }
 
-            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PreviewFragment);
-            FragmentWithPreview f = (FragmentWithPreview) Fragment.instantiate(
-                    context, ta.getString(R.styleable.PreviewFragment_android_name));
-            f.enterPreviewMode(context);
-            f.onInit(null);
+    @Override
+    public View onCreateView(String name, Context context, AttributeSet attrs) {
+        return onCreateView(null, name, context, attrs);
+    }
 
-            View view = f.onCreateView(LayoutInflater.from(context), (ViewGroup) parent, null);
-            view.setId(ta.getInt(R.styleable.PreviewFragment_android_id, View.NO_ID));
-            return view;
+    @Override
+    public BaseDragLayer getDragLayer() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DeviceProfile getDeviceProfile() {
+        return mDp;
+    }
+
+    @Override
+    public Hotseat getHotseat() {
+        return mHotseat;
+    }
+
+    @Override
+    public CellLayout getScreenWithId(int screenId) {
+        return mWorkspace;
+    }
+
+    private void inflateAndAddIcon(WorkspaceItemInfo info) {
+        BubbleTextView icon = (BubbleTextView) mHomeElementInflater.inflate(
+                R.layout.app_icon, mWorkspace, false);
+        icon.applyFromWorkspaceItem(info);
+        addInScreenFromBind(icon, info);
+    }
+
+    private void inflateAndAddFolder(FolderInfo info) {
+        FolderIcon folderIcon = FolderIcon.inflateIcon(R.layout.folder_icon, this, mWorkspace,
+                info);
+        addInScreenFromBind(folderIcon, info);
+    }
+
+    private void inflateAndAddWidgets(
+            LauncherAppWidgetInfo info,
+            Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap) {
+        if (widgetProviderInfoMap == null) {
+            return;
         }
-
-        @Override
-        public View onCreateView(String name, Context context, AttributeSet attrs) {
-            return onCreateView(null, name, context, attrs);
+        AppWidgetProviderInfo providerInfo = widgetProviderInfoMap.get(
+                new ComponentKey(info.providerName, info.user));
+        if (providerInfo == null) {
+            return;
         }
+        inflateAndAddWidgets(info, LauncherAppWidgetProviderInfo.fromProviderInfo(
+                getApplicationContext(), providerInfo));
+    }
 
-        @Override
-        public BaseDragLayer getDragLayer() {
-            throw new UnsupportedOperationException();
+    private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
+        WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
+                info.providerName);
+        if (widgetItem == null) {
+            return;
         }
+        inflateAndAddWidgets(info, widgetItem.widgetInfo);
+    }
 
-        @Override
-        public DeviceProfile getDeviceProfile() {
-            return mDp;
-        }
+    private void inflateAndAddWidgets(
+            LauncherAppWidgetInfo info, LauncherAppWidgetProviderInfo providerInfo) {
+        AppWidgetHostView view = new AppWidgetHostView(mContext);
+        view.setAppWidget(-1, providerInfo);
+        view.updateAppWidget(null);
+        view.setTag(info);
+        addInScreenFromBind(view, info);
+    }
 
-        @Override
-        public Hotseat getHotseat() {
-            return mHotseat;
-        }
-
-        @Override
-        public CellLayout getScreenWithId(int screenId) {
-            return mWorkspace;
-        }
-
-        private void inflateAndAddIcon(WorkspaceItemInfo info) {
-            BubbleTextView icon = (BubbleTextView) mHomeElementInflater.inflate(
-                    R.layout.app_icon, mWorkspace, false);
-            icon.applyFromWorkspaceItem(info);
-            addInScreenFromBind(icon, info);
-        }
-
-        private void inflateAndAddFolder(FolderInfo info) {
-            FolderIcon folderIcon = FolderIcon.inflateIcon(R.layout.folder_icon, this, mWorkspace,
-                    info);
-            addInScreenFromBind(folderIcon, info);
-        }
-
-        private void inflateAndAddWidgets(LauncherAppWidgetInfo info,
-                Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap) {
-            if (widgetProviderInfoMap == null) {
-                return;
-            }
-            AppWidgetProviderInfo providerInfo = widgetProviderInfoMap.get(
-                    new ComponentKey(info.providerName, info.user));
-            if (providerInfo == null) {
-                return;
-            }
-            inflateAndAddWidgets(info, LauncherAppWidgetProviderInfo.fromProviderInfo(
-                    getApplicationContext(), providerInfo));
-        }
-
-        private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
-            WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
-                    info.providerName);
-            if (widgetItem == null) {
-                return;
-            }
-            inflateAndAddWidgets(info, widgetItem.widgetInfo);
-        }
-
-        private void inflateAndAddWidgets(LauncherAppWidgetInfo info,
-                LauncherAppWidgetProviderInfo providerInfo) {
-            AppWidgetHostView view = new AppWidgetHostView(mContext);
-            view.setAppWidget(-1, providerInfo);
-            view.updateAppWidget(null);
-            view.setTag(info);
+    private void inflateAndAddPredictedIcon(WorkspaceItemInfo info) {
+        View view = PredictedAppIconInflater.inflate(mHomeElementInflater, mWorkspace, info);
+        if (view != null) {
             addInScreenFromBind(view, info);
         }
+    }
 
-        private void inflateAndAddPredictedIcon(WorkspaceItemInfo info) {
-            View view = PredictedAppIconInflater.inflate(mHomeElementInflater, mWorkspace, info);
-            if (view != null) {
-                addInScreenFromBind(view, info);
-            }
+    private void dispatchVisibilityAggregated(View view, boolean isVisible) {
+        // Similar to View.dispatchVisibilityAggregated implementation.
+        final boolean thisVisible = view.getVisibility() == VISIBLE;
+        if (thisVisible || !isVisible) {
+            view.onVisibilityAggregated(isVisible);
         }
 
-        private void dispatchVisibilityAggregated(View view, boolean isVisible) {
-            // Similar to View.dispatchVisibilityAggregated implementation.
-            final boolean thisVisible = view.getVisibility() == VISIBLE;
-            if (thisVisible || !isVisible) {
-                view.onVisibilityAggregated(isVisible);
-            }
+        if (view instanceof ViewGroup) {
+            isVisible = thisVisible && isVisible;
+            ViewGroup vg = (ViewGroup) view;
+            int count = vg.getChildCount();
 
-            if (view instanceof ViewGroup) {
-                isVisible = thisVisible && isVisible;
-                ViewGroup vg = (ViewGroup) view;
-                int count = vg.getChildCount();
-
-                for (int i = 0; i < count; i++) {
-                    dispatchVisibilityAggregated(vg.getChildAt(i), isVisible);
-                }
+            for (int i = 0; i < count; i++) {
+                dispatchVisibilityAggregated(vg.getChildAt(i), isVisible);
             }
         }
+    }
 
-        private void populate() {
-            if (ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get()) {
-                WorkspaceFetcher fetcher;
-                PreviewContext previewContext = null;
-                if (mMigrated) {
-                    previewContext = new PreviewContext(mContext, mIdp);
-                    LauncherAppState appForPreview = new LauncherAppState(
-                            previewContext, null /* iconCacheFileName */);
-                    fetcher = new WorkspaceItemsInfoFromPreviewFetcher(appForPreview);
-                    MODEL_EXECUTOR.execute(fetcher);
-                } else {
-                    fetcher = new WorkspaceItemsInfoFetcher();
-                    LauncherAppState.getInstance(mContext).getModel().enqueueModelUpdateTask(
-                            (LauncherModel.ModelUpdateTask) fetcher);
-                }
-                WorkspaceResult workspaceResult = fetcher.get();
-                if (previewContext != null) {
-                    previewContext.onDestroy();
-                }
-
-                if (workspaceResult == null) {
-                    return;
-                }
-
-                // Separate the items that are on the current screen, and all the other remaining
-                // items
-                ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
-                ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>();
-                ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>();
-                ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>();
-
-                filterCurrentWorkspaceItems(0 /* currentScreenId */,
-                        workspaceResult.mWorkspaceItems, currentWorkspaceItems,
-                        otherWorkspaceItems);
-                filterCurrentWorkspaceItems(0 /* currentScreenId */, workspaceResult.mAppWidgets,
-                        currentAppWidgets, otherAppWidgets);
-                sortWorkspaceItemsSpatially(mIdp, currentWorkspaceItems);
-
-                for (ItemInfo itemInfo : currentWorkspaceItems) {
-                    switch (itemInfo.itemType) {
-                        case Favorites.ITEM_TYPE_APPLICATION:
-                        case Favorites.ITEM_TYPE_SHORTCUT:
-                        case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
-                            inflateAndAddIcon((WorkspaceItemInfo) itemInfo);
-                            break;
-                        case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
-                            inflateAndAddFolder((FolderInfo) itemInfo);
-                            break;
-                        default:
-                            break;
-                    }
-                }
-                for (ItemInfo itemInfo : currentAppWidgets) {
-                    switch (itemInfo.itemType) {
-                        case Favorites.ITEM_TYPE_APPWIDGET:
-                        case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
-                            if (mMigrated) {
-                                inflateAndAddWidgets((LauncherAppWidgetInfo) itemInfo,
-                                        workspaceResult.mWidgetProvidersMap);
-                            } else {
-                                inflateAndAddWidgets((LauncherAppWidgetInfo) itemInfo,
-                                        workspaceResult.mWidgetsModel);
-                            }
-                            break;
-                        default:
-                            break;
-                    }
-                }
-
-                IntArray ranks = getMissingHotseatRanks(currentWorkspaceItems,
-                        mIdp.numHotseatIcons);
-                int count = Math.min(ranks.size(), workspaceResult.mCachedPredictedItems.size());
-                for (int i = 0; i < count; i++) {
-                    AppInfo appInfo = workspaceResult.mCachedPredictedItems.get(i);
-                    int rank = ranks.get(i);
-                    WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(appInfo);
-                    itemInfo.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
-                    itemInfo.rank = rank;
-                    itemInfo.cellX = mHotseat.getCellXFromOrder(rank);
-                    itemInfo.cellY = mHotseat.getCellYFromOrder(rank);
-                    itemInfo.screenId = rank;
-                    inflateAndAddPredictedIcon(itemInfo);
-                }
+    private void populate() {
+        if (shouldShowRealLauncherPreview()) {
+            WorkspaceFetcher fetcher;
+            PreviewContext previewContext = null;
+            if (mMigrated) {
+                previewContext = new PreviewContext(mContext, mIdp);
+                LauncherAppState appForPreview = new LauncherAppState(
+                        previewContext, null /* iconCacheFileName */);
+                fetcher = new WorkspaceItemsInfoFromPreviewFetcher(appForPreview);
+                MODEL_EXECUTOR.execute(fetcher);
             } else {
-                // Add hotseat icons
-                for (int i = 0; i < mIdp.numHotseatIcons; i++) {
-                    WorkspaceItemInfo info = new WorkspaceItemInfo(mWorkspaceItemInfo);
-                    info.container = Favorites.CONTAINER_HOTSEAT;
-                    info.screenId = i;
-                    inflateAndAddIcon(info);
-                }
-                // Add workspace icons
-                for (int i = 0; i < mIdp.numColumns; i++) {
-                    WorkspaceItemInfo info = new WorkspaceItemInfo(mWorkspaceItemInfo);
-                    info.container = Favorites.CONTAINER_DESKTOP;
-                    info.screenId = 0;
-                    info.cellX = i;
-                    info.cellY = mIdp.numRows - 1;
-                    inflateAndAddIcon(info);
-                }
+                fetcher = new WorkspaceItemsInfoFetcher();
+                LauncherAppState.getInstance(mContext).getModel().enqueueModelUpdateTask(
+                        (LauncherModel.ModelUpdateTask) fetcher);
+            }
+            WorkspaceResult workspaceResult = fetcher.get();
+            if (previewContext != null) {
+                previewContext.onDestroy();
             }
 
-            // Add first page QSB
-            if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
-                View qsb = mHomeElementInflater.inflate(
-                        R.layout.search_container_workspace, mWorkspace, false);
-                CellLayout.LayoutParams lp =
-                        new CellLayout.LayoutParams(0, 0, mWorkspace.getCountX(), 1);
-                lp.canReorder = false;
-                mWorkspace.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true);
+            if (workspaceResult == null) {
+                return;
             }
 
-            // Setup search view
-            SearchUiManager searchUiManager =
-                    mRootView.findViewById(R.id.search_container_all_apps);
-            mRootView.findViewById(R.id.apps_view).setTranslationY(
-                    mDp.heightPx - searchUiManager.getScrollRangeDelta(mInsets));
-
-            measureView(mRootView, mDp.widthPx, mDp.heightPx);
-            dispatchVisibilityAggregated(mRootView, true);
-            measureView(mRootView, mDp.widthPx, mDp.heightPx);
-            // Additional measure for views which use auto text size API
-            measureView(mRootView, mDp.widthPx, mDp.heightPx);
+            // Separate the items that are on the current screen, and the other remaining items.
+            ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
+            ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>();
+            ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>();
+            ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>();
+            filterCurrentWorkspaceItems(0 /* currentScreenId */,
+                    workspaceResult.mWorkspaceItems, currentWorkspaceItems,
+                    otherWorkspaceItems);
+            filterCurrentWorkspaceItems(0 /* currentScreenId */, workspaceResult.mAppWidgets,
+                    currentAppWidgets, otherAppWidgets);
+            sortWorkspaceItemsSpatially(mIdp, currentWorkspaceItems);
+            for (ItemInfo itemInfo : currentWorkspaceItems) {
+                switch (itemInfo.itemType) {
+                    case Favorites.ITEM_TYPE_APPLICATION:
+                    case Favorites.ITEM_TYPE_SHORTCUT:
+                    case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+                        inflateAndAddIcon((WorkspaceItemInfo) itemInfo);
+                        break;
+                    case Favorites.ITEM_TYPE_FOLDER:
+                        inflateAndAddFolder((FolderInfo) itemInfo);
+                        break;
+                    default:
+                        break;
+                }
+            }
+            for (ItemInfo itemInfo : currentAppWidgets) {
+                switch (itemInfo.itemType) {
+                    case Favorites.ITEM_TYPE_APPWIDGET:
+                    case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
+                        if (mMigrated) {
+                            inflateAndAddWidgets((LauncherAppWidgetInfo) itemInfo,
+                                    workspaceResult.mWidgetProvidersMap);
+                        } else {
+                            inflateAndAddWidgets((LauncherAppWidgetInfo) itemInfo,
+                                    workspaceResult.mWidgetsModel);
+                        }
+                        break;
+                    default:
+                        break;
+                }
+            }
+            IntArray ranks = getMissingHotseatRanks(currentWorkspaceItems,
+                    mIdp.numHotseatIcons);
+            int count = Math.min(ranks.size(), workspaceResult.mCachedPredictedItems.size());
+            for (int i = 0; i < count; i++) {
+                AppInfo appInfo = workspaceResult.mCachedPredictedItems.get(i);
+                int rank = ranks.get(i);
+                WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(appInfo);
+                itemInfo.container = Favorites.CONTAINER_HOTSEAT_PREDICTION;
+                itemInfo.rank = rank;
+                itemInfo.cellX = mHotseat.getCellXFromOrder(rank);
+                itemInfo.cellY = mHotseat.getCellYFromOrder(rank);
+                itemInfo.screenId = rank;
+                inflateAndAddPredictedIcon(itemInfo);
+            }
+        } else {
+            // Add hotseat icons
+            for (int i = 0; i < mIdp.numHotseatIcons; i++) {
+                WorkspaceItemInfo info = new WorkspaceItemInfo(mWorkspaceItemInfo);
+                info.container = Favorites.CONTAINER_HOTSEAT;
+                info.screenId = i;
+                inflateAndAddIcon(info);
+            }
+            // Add workspace icons
+            for (int i = 0; i < mIdp.numColumns; i++) {
+                WorkspaceItemInfo info = new WorkspaceItemInfo(mWorkspaceItemInfo);
+                info.container = Favorites.CONTAINER_DESKTOP;
+                info.screenId = 0;
+                info.cellX = i;
+                info.cellY = mIdp.numRows - 1;
+                inflateAndAddIcon(info);
+            }
         }
+
+        // Add first page QSB
+        if (shouldShowQsb()) {
+            View qsb = mHomeElementInflater.inflate(
+                    R.layout.search_container_workspace, mWorkspace, false);
+            CellLayout.LayoutParams lp =
+                    new CellLayout.LayoutParams(0, 0, mWorkspace.getCountX(), 1);
+            lp.canReorder = false;
+            mWorkspace.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true);
+        }
+
+        // Setup search view
+        SearchUiManager searchUiManager =
+                mRootView.findViewById(R.id.search_container_all_apps);
+        mRootView.findViewById(R.id.apps_view).setTranslationY(
+                mDp.heightPx - searchUiManager.getScrollRangeDelta(mInsets));
+        ViewGroup searchView = (ViewGroup) searchUiManager;
+        searchView.setEnabled(false);
+        for (int i = 0; i < searchView.getChildCount(); i++) {
+            searchView.getChildAt(i).setEnabled(false);
+        }
+
+        measureView(mRootView, mDp.widthPx, mDp.heightPx);
+        dispatchVisibilityAggregated(mRootView, true);
+        measureView(mRootView, mDp.widthPx, mDp.heightPx);
+        // Additional measure for views which use auto text size API
+        measureView(mRootView, mDp.widthPx, mDp.heightPx);
     }
 
     private static void measureView(View view, int width, int height) {