Merge "Fix launcher preview for two panel home" into sc-v2-dev
diff --git a/res/layout/launcher_preview_two_panel_layout.xml b/res/layout/launcher_preview_two_panel_layout.xml
new file mode 100644
index 0000000..7b227e0
--- /dev/null
+++ b/res/layout/launcher_preview_two_panel_layout.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<view class="com.android.launcher3.graphics.LauncherPreviewRenderer$LauncherPreviewLayout"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusable="false">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <com.android.launcher3.CellLayout
+            android:id="@+id/workspace_left"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:theme="@style/HomeScreenElementTheme"
+            launcher:containerType="workspace"
+            launcher:layout_constraintStart_toStartOf="parent"
+            launcher:layout_constraintTop_toTopOf="parent"
+            launcher:layout_constraintEnd_toStartOf="@id/workspace"
+            launcher:layout_constraintBottom_toBottomOf="parent"
+            launcher:pageIndicator="@+id/page_indicator" />
+
+        <com.android.launcher3.CellLayout
+            android:id="@+id/workspace"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:theme="@style/HomeScreenElementTheme"
+            launcher:containerType="workspace"
+            launcher:layout_constraintStart_toEndOf="@id/workspace_left"
+            launcher:layout_constraintTop_toTopOf="parent"
+            launcher:layout_constraintEnd_toEndOf="parent"
+            launcher:layout_constraintBottom_toBottomOf="parent"
+            launcher:pageIndicator="@+id/page_indicator" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <include
+        android:id="@+id/hotseat"
+        layout="@layout/hotseat" />
+
+</view>
\ No newline at end of file
diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
index 8e49fae..d2051e0 100644
--- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
+++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
@@ -131,7 +131,7 @@
                 mIdp.numDatabaseHotseatIcons);
         GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
                 destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
-        task.migrate();
+        task.migrate(mIdp);
 
         // Check hotseat items
         Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
@@ -211,7 +211,7 @@
                 mIdp.numDatabaseHotseatIcons);
         GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
                 destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
-        task.migrate();
+        task.migrate(mIdp);
 
         // Check hotseat items
         Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
@@ -259,7 +259,7 @@
                 mIdp.numDatabaseHotseatIcons);
         GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
                 destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
-        task.migrate();
+        task.migrate(mIdp);
 
         // Check hotseat items
         Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 1127ff9..1da8028 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -208,7 +208,7 @@
     private final LayoutInflater mHomeElementInflater;
     private final InsettableFrameLayout mRootView;
     private final Hotseat mHotseat;
-    private final CellLayout mWorkspace;
+    private final Map<Integer, CellLayout> mWorkspaceScreens = new HashMap<>();
     private final AppWidgetHost mAppWidgetHost;
     private final SparseIntArray mWallpaperColorResources;
 
@@ -254,19 +254,31 @@
                 new ContextThemeWrapper(this, R.style.HomeScreenElementTheme));
         mHomeElementInflater.setFactory2(this);
 
+        int layoutRes = mDp.isTwoPanels ? R.layout.launcher_preview_two_panel_layout
+                : R.layout.launcher_preview_layout;
         mRootView = (InsettableFrameLayout) mHomeElementInflater.inflate(
-                R.layout.launcher_preview_layout, null, false);
+                layoutRes, 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,
+        if (mDp.isTwoPanels) {
+            CellLayout leftPanel = mRootView.findViewById(R.id.workspace_left);
+            leftPanel.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingLeftRightPx,
+                    mDp.workspacePadding.top,
+                    mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
+                    mDp.workspacePadding.bottom);
+            mWorkspaceScreens.put(LEFT_PANEL_ID, leftPanel);
+        }
+
+        CellLayout firstScreen = mRootView.findViewById(R.id.workspace);
+        firstScreen.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingLeftRightPx,
                 mDp.workspacePadding.top,
                 mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
                 mDp.workspacePadding.bottom);
+        mWorkspaceScreens.put(FIRST_SCREEN_ID, firstScreen);
 
         if (FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()) {
             mAppWidgetHost = new LauncherPreviewAppWidgetHost(context);
@@ -335,18 +347,20 @@
 
     @Override
     public CellLayout getScreenWithId(int screenId) {
-        return mWorkspace;
+        return mWorkspaceScreens.get(screenId);
     }
 
     private void inflateAndAddIcon(WorkspaceItemInfo info) {
+        CellLayout screen = mWorkspaceScreens.get(info.screenId);
         BubbleTextView icon = (BubbleTextView) mHomeElementInflater.inflate(
-                R.layout.app_icon, mWorkspace, false);
+                R.layout.app_icon, screen, false);
         icon.applyFromWorkspaceItem(info);
         addInScreenFromBind(icon, info);
     }
 
     private void inflateAndAddFolder(FolderInfo info) {
-        FolderIcon folderIcon = FolderIcon.inflateIcon(R.layout.folder_icon, this, mWorkspace,
+        CellLayout screen = mWorkspaceScreens.get(info.screenId);
+        FolderIcon folderIcon = FolderIcon.inflateIcon(R.layout.folder_icon, this, screen,
                 info);
         addInScreenFromBind(folderIcon, info);
     }
@@ -396,7 +410,8 @@
     }
 
     private void inflateAndAddPredictedIcon(WorkspaceItemInfo info) {
-        View view = PredictedAppIconInflater.inflate(mHomeElementInflater, mWorkspace, info);
+        CellLayout screen = mWorkspaceScreens.get(info.screenId);
+        View view = PredictedAppIconInflater.inflate(mHomeElementInflater, screen, info);
         if (view != null) {
             addInScreenFromBind(view, info);
         }
@@ -428,8 +443,7 @@
         ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>();
         ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>();
 
-        IntSet currentScreenIds = IntSet.wrap(0);
-        // TODO(b/185508060): support two panel preview.
+        IntSet currentScreenIds = IntSet.wrap(mWorkspaceScreens.keySet());
         filterCurrentWorkspaceItems(currentScreenIds, dataModel.workspaceItems,
                 currentWorkspaceItems, otherWorkspaceItems);
         filterCurrentWorkspaceItems(currentScreenIds, dataModel.appWidgets, currentAppWidgets,
@@ -487,12 +501,13 @@
 
         // Add first page QSB
         if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
+            CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID);
             View qsb = mHomeElementInflater.inflate(
-                    R.layout.search_container_workspace, mWorkspace, false);
+                    R.layout.search_container_workspace, firstScreen, false);
             CellLayout.LayoutParams lp =
-                    new CellLayout.LayoutParams(0, 0, mWorkspace.getCountX(), 1);
+                    new CellLayout.LayoutParams(0, 0, firstScreen.getCountX(), 1);
             lp.canReorder = false;
-            mWorkspace.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true);
+            firstScreen.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true);
         }
 
         measureView(mRootView, mDp.widthPx, mDp.heightPx);
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index df49359..13c83be 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -38,11 +38,13 @@
 import androidx.annotation.UiThread;
 import androidx.annotation.WorkerThread;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
 import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.GridSizeMigrationTask;
@@ -163,11 +165,17 @@
 
                 @Override
                 public void run() {
+                    DeviceProfile deviceProfile = mIdp.getDeviceProfile(mContext);
+                    String query = (deviceProfile.isTwoPanels ? LauncherSettings.Favorites.SCREEN
+                            + " = " + Workspace.LEFT_PANEL_ID + " or " : "")
+                            + LauncherSettings.Favorites.SCREEN + " = " + Workspace.FIRST_SCREEN_ID
+                            + " or " + LauncherSettings.Favorites.CONTAINER + " = "
+                            + LauncherSettings.Favorites.CONTAINER_HOTSEAT;
                     loadWorkspace(new ArrayList<>(), LauncherSettings.Favorites.PREVIEW_CONTENT_URI,
-                            LauncherSettings.Favorites.SCREEN + " = 0 or "
-                                    + LauncherSettings.Favorites.CONTAINER + " = "
-                                    + LauncherSettings.Favorites.CONTAINER_HOTSEAT);
+                            query);
+
                     MAIN_EXECUTOR.execute(() -> {
+                        mBgDataModel.isLeftPanelShown = deviceProfile.isTwoPanels;
                         renderView(previewContext, mBgDataModel, mWidgetProvidersMap);
                         mOnDestroyCallbacks.add(previewContext::onDestroy);
                     });
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
index 8a1d73e..3935bcf 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
@@ -41,6 +41,7 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
 import com.android.launcher3.graphics.LauncherPreviewRenderer;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.InstallSessionHelper;
@@ -183,7 +184,7 @@
             Point targetSize = new Point(idp.numColumns, idp.numRows);
             GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(context, t.getDb(),
                     srcReader, destReader, idp.numDatabaseHotseatIcons, targetSize);
-            task.migrate();
+            task.migrate(idp);
 
             if (!migrateForPreview) {
                 dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE);
@@ -210,7 +211,7 @@
     }
 
     @VisibleForTesting
-    protected boolean migrate() {
+    protected boolean migrate(InvariantDeviceProfile idp) {
         if (mHotseatDiff.isEmpty() && mWorkspaceDiff.isEmpty()) {
             return false;
         }
@@ -224,7 +225,17 @@
         Collections.sort(mWorkspaceDiff);
 
         // Migrate workspace.
+        // First we create a collection of the screens
+        List<Integer> screens = new ArrayList<>();
+        if (idp.getDeviceProfile(mContext).isTwoPanels) {
+            screens.add(Workspace.LEFT_PANEL_ID);
+        }
         for (int screenId = 0; screenId <= mDestReader.mLastScreenId; screenId++) {
+            screens.add(screenId);
+        }
+
+        // Then we place the items on the screens
+        for (int screenId : screens) {
             if (DEBUG) {
                 Log.d(TAG, "Migrating " + screenId);
             }
@@ -236,6 +247,8 @@
             }
         }
 
+        // In case the new grid is smaller, there might be some leftover items that don't fit on
+        // any of the screens, in this case we add them to new screens until all of them are placed.
         int screenId = mDestReader.mLastScreenId + 1;
         while (!mWorkspaceDiff.isEmpty()) {
             GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
diff --git a/src/com/android/launcher3/util/IntSet.java b/src/com/android/launcher3/util/IntSet.java
index 0f4df62..e5b4f59 100644
--- a/src/com/android/launcher3/util/IntSet.java
+++ b/src/com/android/launcher3/util/IntSet.java
@@ -101,6 +101,15 @@
         return wrap(IntArray.wrap(array));
     }
 
+    /**
+     * Returns an IntSet with the given values.
+     */
+    public static IntSet wrap(Iterable<Integer> iterable) {
+        IntSet set = new IntSet();
+        iterable.forEach(set::add);
+        return set;
+    }
+
     @Override
     public Iterator<Integer> iterator() {
         return mArray.iterator();