Adding support for determining split layout for launcher.

> Simulating the windo wmanager API to get available device
  profiles until final API
> When a device has multiple internal displays, and with both
  tablet and phone possibilities, it uses a split workspace layout

Bug: 186160341
Bug: 175782275
Test: Manual
Change-Id: Ieff2329acac7cdd6b9abe6f96cd459cd45bd0efe
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index fd97936..d5860dc 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -31,7 +31,6 @@
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.view.Surface;
 import android.view.WindowInsets;
 import android.view.WindowManager;
@@ -42,7 +41,6 @@
 import com.android.launcher3.icons.DotRenderer;
 import com.android.launcher3.icons.GraphicsUtils;
 import com.android.launcher3.icons.IconNormalizer;
-import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.WindowBounds;
@@ -52,9 +50,6 @@
 @SuppressLint("NewApi")
 public class DeviceProfile {
 
-    private static final float TABLET_MIN_DPS = 600;
-    private static final float LARGE_TABLET_MIN_DPS = 720;
-
     private static final int DEFAULT_DOT_SIZE = 100;
 
     public final InvariantDeviceProfile inv;
@@ -63,9 +58,9 @@
 
     // Device properties
     public final boolean isTablet;
-    public final boolean isLargeTablet;
     public final boolean isPhone;
     public final boolean transposeLayoutWithOrientation;
+    public final boolean isTwoPanels;
 
     // Device properties in current orientation
     public final boolean isLandscape;
@@ -164,6 +159,7 @@
     public int allAppsCellWidthPx;
     public int allAppsIconSizePx;
     public int allAppsIconDrawablePaddingPx;
+    public final int numShownAllAppsColumns;
     public float allAppsIconTextSizePx;
 
     // Overview
@@ -194,42 +190,30 @@
     // How much of the bottom inset is due to Taskbar rather than other system elements.
     public int nonOverlappingTaskbarInset;
 
-    DeviceProfile(Context context, InvariantDeviceProfile inv, Info info,
-            Point minSize, Point maxSize, int width, int height, boolean isLandscape,
+    DeviceProfile(Context context, InvariantDeviceProfile inv, Info info, WindowBounds windowBounds,
             boolean isMultiWindowMode, boolean transposeLayoutWithOrientation,
-            Point windowPosition) {
+            boolean useTwoPanels) {
 
         this.inv = inv;
-        this.isLandscape = isLandscape;
+        this.isLandscape = windowBounds.isLandscape();
         this.isMultiWindowMode = isMultiWindowMode;
         this.transposeLayoutWithOrientation = transposeLayoutWithOrientation;
-        windowX = windowPosition.x;
-        windowY = windowPosition.y;
+        windowX = windowBounds.bounds.left;
+        windowY = windowBounds.bounds.top;
 
         isScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
 
         // Determine sizes.
-        widthPx = width;
-        heightPx = height;
-        int nonFinalAvailableHeightPx;
-        if (isLandscape) {
-            availableWidthPx = maxSize.x;
-            nonFinalAvailableHeightPx = minSize.y;
-        } else {
-            availableWidthPx = minSize.x;
-            nonFinalAvailableHeightPx = maxSize.y;
-        }
+        widthPx = windowBounds.bounds.width();
+        heightPx = windowBounds.bounds.height();
+        availableWidthPx = windowBounds.availableSize.x;
+        int nonFinalAvailableHeightPx = windowBounds.availableSize.y;
 
         mInfo = info;
+        isTablet = info.isTablet(windowBounds);
+        isPhone = !isTablet;
+        isTwoPanels = isTablet && useTwoPanels;
 
-        // Constants from resources
-        float swDPs = dpiFromPx(Math.min(info.smallestSize.x, info.smallestSize.y),
-                info.densityDpi);
-        boolean allowRotation = context.getResources().getBoolean(R.bool.allow_rotation);
-        // Tablet UI is built with assumption that simulated landscape is disabled.
-        isTablet = allowRotation && swDPs >= TABLET_MIN_DPS;
-        isLargeTablet = isTablet && swDPs >= LARGE_TABLET_MIN_DPS;
-        isPhone = !isTablet && !isLargeTablet;
         aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
         boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
 
@@ -284,7 +268,7 @@
                 ? 0
                 : res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding);
 
-        if (FeatureFlags.ENABLE_TWO_PANEL_HOME.get() && isTablet) {
+        if (isTwoPanels) {
             cellLayoutPaddingLeftRightPx =
                     res.getDimensionPixelSize(R.dimen.two_panel_home_side_padding);
             cellLayoutBottomPaddingPx = 0;
@@ -309,7 +293,10 @@
 
         workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
 
-        numShownHotseatIcons = inv.numShownHotseatIcons;
+        numShownHotseatIcons =
+                isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons;
+        numShownAllAppsColumns =
+                isTwoPanels ? inv.numDatabaseAllAppsColumns : inv.numAllAppsColumns;
         hotseatBarTopPaddingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
         hotseatBarBottomPaddingPx = (isTallDevice ? 0
@@ -393,11 +380,12 @@
     }
 
     public Builder toBuilder(Context context) {
-        Point size = new Point(availableWidthPx, availableHeightPx);
+        WindowBounds bounds =
+                new WindowBounds(widthPx, heightPx, availableWidthPx, availableHeightPx);
+        bounds.bounds.offsetTo(windowX, windowY);
         return new Builder(context, inv, mInfo)
-                .setSizeRange(size, size)
-                .setSize(widthPx, heightPx)
-                .setWindowPosition(windowX, windowY)
+                .setWindowBounds(bounds)
+                .setUseTwoPanels(isTwoPanels)
                 .setMultiWindowMode(isMultiWindowMode);
     }
 
@@ -409,15 +397,8 @@
      * TODO: Move this to the builder as part of setMultiWindowMode
      */
     public DeviceProfile getMultiWindowProfile(Context context, WindowBounds windowBounds) {
-        // We take the minimum sizes of this profile and it's multi-window variant to ensure that
-        // the system decor is always excluded.
-        Point mwSize = new Point(Math.min(availableWidthPx, windowBounds.availableSize.x),
-                Math.min(availableHeightPx, windowBounds.availableSize.y));
-
         DeviceProfile profile = toBuilder(context)
-                .setSizeRange(mwSize, mwSize)
-                .setSize(windowBounds.bounds.width(), windowBounds.bounds.height())
-                .setWindowPosition(windowBounds.bounds.left, windowBounds.bounds.top)
+                .setWindowBounds(windowBounds)
                 .setMultiWindowMode(true)
                 .build();
 
@@ -434,14 +415,6 @@
     }
 
     /**
-     * Inverse of {@link #getMultiWindowProfile(Context, WindowBounds)}
-     * @return device profile corresponding to the current orientation in non multi-window mode.
-     */
-    public DeviceProfile getFullScreenProfile() {
-        return isLandscape ? inv.landscapeProfile : inv.portraitProfile;
-    }
-
-    /**
      * Checks if there is enough space for labels on the workspace.
      * If there is not, labels on the Workspace are hidden.
      * It is important to call this method after the All Apps variables have been set.
@@ -553,7 +526,7 @@
         }
 
         // All apps
-        if (allAppsHasDifferentNumColumns()) {
+        if (numShownAllAppsColumns != inv.numColumns) {
             allAppsIconSizePx = pxFromDp(inv.allAppsIconSize, mMetrics);
             allAppsIconTextSizePx = Utilities.pxFromSp(inv.allAppsIconTextSize, mMetrics);
             allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
@@ -667,18 +640,20 @@
     }
 
     public Point getCellSize() {
-        return getCellSize(inv.numColumns, inv.numRows);
+        return getCellSize(null);
     }
 
-    private Point getCellSize(int numColumns, int numRows) {
-        Point result = new Point();
+    public Point getCellSize(Point result) {
+        if (result == null) {
+            result = new Point();
+        }
         // Since we are only concerned with the overall padding, layout direction does
         // not matter.
         Point padding = getTotalWorkspacePadding();
         result.x = calculateCellWidth(availableWidthPx - padding.x
-                - cellLayoutPaddingLeftRightPx * 2, cellLayoutBorderSpacingPx, numColumns);
+                - cellLayoutPaddingLeftRightPx * 2, cellLayoutBorderSpacingPx, inv.numColumns);
         result.y = calculateCellHeight(availableHeightPx - padding.y
-                - cellLayoutBottomPaddingPx, cellLayoutBorderSpacingPx, numRows);
+                - cellLayoutBottomPaddingPx, cellLayoutBorderSpacingPx, inv.numRows);
         return result;
     }
 
@@ -723,7 +698,7 @@
                 padding.set(availablePaddingX / 2, edgeMarginPx + availablePaddingY / 2,
                         availablePaddingX / 2, paddingBottom + availablePaddingY / 2);
 
-                if (FeatureFlags.ENABLE_TWO_PANEL_HOME.get()) {
+                if (isTwoPanels) {
                     padding.set(0, padding.top, 0, padding.bottom);
                 }
             } else {
@@ -751,7 +726,7 @@
             // for this, we pad the left and right of the hotseat with half of the difference of a
             // workspace cell vs a hotseat cell.
             float workspaceCellWidth = (float) widthPx / inv.numColumns;
-            float hotseatCellWidth = (float) widthPx / inv.numShownHotseatIcons;
+            float hotseatCellWidth = (float) widthPx / numShownHotseatIcons;
             int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2);
             mHotseatPadding.set(
                     hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx
@@ -802,13 +777,6 @@
     }
 
     /**
-     * Returns true when the number of workspace columns and all apps columns differs.
-     */
-    private boolean allAppsHasDifferentNumColumns() {
-        return inv.numAllAppsColumns != inv.numColumns;
-    }
-
-    /**
      * Updates orientation information and returns true if it has changed from the previous value.
      */
     public boolean updateIsSeascape(Context context) {
@@ -828,7 +796,7 @@
     }
 
     public boolean shouldFadeAdjacentWorkspaceScreens() {
-        return isVerticalBarLayout() || isLargeTablet;
+        return isVerticalBarLayout();
     }
 
     public int getCellHeight(@ContainerType int containerType) {
@@ -854,13 +822,13 @@
         writer.println(prefix + "\t1 dp = " + mMetrics.density + " px");
 
         writer.println(prefix + "\tisTablet:" + isTablet);
-        writer.println(prefix + "\tisLargeTablet:" + isLargeTablet);
         writer.println(prefix + "\tisPhone:" + isPhone);
         writer.println(prefix + "\ttransposeLayoutWithOrientation:"
                 + transposeLayoutWithOrientation);
 
         writer.println(prefix + "\tisLandscape:" + isLandscape);
         writer.println(prefix + "\tisMultiWindowMode:" + isMultiWindowMode);
+        writer.println(prefix + "\tisTwoPanels:" + isTwoPanels);
 
         writer.println(prefix + pxToDpStr("windowX", windowX));
         writer.println(prefix + pxToDpStr("windowY", windowY));
@@ -907,6 +875,7 @@
         writer.println(prefix + pxToDpStr("allAppsIconDrawablePaddingPx",
                 allAppsIconDrawablePaddingPx));
         writer.println(prefix + pxToDpStr("allAppsCellHeightPx", allAppsCellHeightPx));
+        writer.println(prefix + "\tnumShownAllAppsColumns: " + numShownAllAppsColumns);
 
         writer.println(prefix + pxToDpStr("hotseatBarSizePx", hotseatBarSizePx));
         writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx));
@@ -916,6 +885,7 @@
                 hotseatBarSidePaddingStartPx));
         writer.println(prefix + pxToDpStr("hotseatBarSidePaddingEndPx",
                 hotseatBarSidePaddingEndPx));
+        writer.println(prefix + "\tnumShownHotseatIcons: " + numShownHotseatIcons);
 
         writer.println(prefix + "\tisTaskbarPresent:" + isTaskbarPresent);
 
@@ -967,41 +937,16 @@
         private InvariantDeviceProfile mInv;
         private Info mInfo;
 
-        private final Point mWindowPosition = new Point();
-        private Point mMinSize, mMaxSize;
-        private int mWidth, mHeight;
+        private WindowBounds mWindowBounds;
+        private boolean mUseTwoPanels;
 
-        private boolean mIsLandscape;
         private boolean mIsMultiWindowMode = false;
-        private boolean mTransposeLayoutWithOrientation;
+        private Boolean mTransposeLayoutWithOrientation;
 
         public Builder(Context context, InvariantDeviceProfile inv, Info info) {
             mContext = context;
             mInv = inv;
             mInfo = info;
-            mTransposeLayoutWithOrientation = context.getResources()
-                    .getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED,
-                        "transposeLayout=" + mTransposeLayoutWithOrientation);
-            }
-        }
-
-        public Builder setSizeRange(Point minSize, Point maxSize) {
-            mMinSize = minSize;
-            mMaxSize = maxSize;
-            return this;
-        }
-
-        public Builder setSize(int width, int height) {
-            mWidth = width;
-            mHeight = height;
-            mIsLandscape = mWidth > mHeight;
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED,
-                        "isLandscape=" + mIsLandscape + " w=" + mWidth + " h=" + mHeight);
-            }
-            return this;
         }
 
         public Builder setMultiWindowMode(boolean isMultiWindowMode) {
@@ -1009,11 +954,14 @@
             return this;
         }
 
-        /**
-         * Sets the window position if not full-screen
-         */
-        public Builder setWindowPosition(int x, int y) {
-            mWindowPosition.set(x, y);
+        public Builder setUseTwoPanels(boolean useTwoPanels) {
+            mUseTwoPanels = useTwoPanels;
+            return this;
+        }
+
+
+        public Builder setWindowBounds(WindowBounds bounds) {
+            mWindowBounds = bounds;
             return this;
         }
 
@@ -1023,9 +971,14 @@
         }
 
         public DeviceProfile build() {
-            return new DeviceProfile(mContext, mInv, mInfo, mMinSize, mMaxSize,
-                    mWidth, mHeight, mIsLandscape, mIsMultiWindowMode,
-                    mTransposeLayoutWithOrientation, mWindowPosition);
+            if (mWindowBounds == null) {
+                throw new IllegalArgumentException("Window bounds not set");
+            }
+            if (mTransposeLayoutWithOrientation == null) {
+                mTransposeLayoutWithOrientation = !mInfo.isTablet(mWindowBounds);
+            }
+            return new DeviceProfile(mContext, mInv, mInfo, mWindowBounds,
+                    mIsMultiWindowMode, mTransposeLayoutWithOrientation, mUseTwoPanels);
         }
     }