Adding support for dynamically resolved default layouts.

Change-Id: Id05c60b93423ce37dd06a126ecf33c74a0ba1d62
diff --git a/res/xml-sw720dp/default_workspace.xml b/res/xml-sw720dp/default_workspace.xml
deleted file mode 100644
index 1c1d70e..0000000
--- a/res/xml-sw720dp/default_workspace.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
-    <!-- Far-left screen [0] -->
-
-    <!-- Left screen [1] -->
-    <appwidget
-        launcher:packageName="com.android.settings"
-        launcher:className="com.android.settings.widget.SettingsAppWidgetProvider"
-        launcher:screen="1"
-        launcher:x="0"
-        launcher:y="3"
-        launcher:spanX="4"
-        launcher:spanY="1" />
-
-    <!-- Middle screen [2] -->
-    <appwidget
-        launcher:packageName="com.android.deskclock"
-        launcher:className="com.android.alarmclock.AnalogAppWidgetProvider"
-        launcher:screen="2"
-        launcher:x="1"
-        launcher:y="0"
-        launcher:spanX="2"
-        launcher:spanY="2" />
-    <favorite
-        launcher:packageName="com.android.camera"
-        launcher:className="com.android.camera.Camera"
-        launcher:screen="2"
-        launcher:x="0"
-        launcher:y="3" />
-
-    <!-- Right screen [3] -->
-    <favorite
-        launcher:packageName="com.android.gallery3d"
-        launcher:className="com.android.gallery3d.app.Gallery"
-        launcher:screen="3"
-        launcher:x="1"
-        launcher:y="3" />
-    <favorite
-        launcher:packageName="com.android.settings"
-        launcher:className="com.android.settings.Settings"
-        launcher:screen="3"
-        launcher:x="2"
-        launcher:y="3" />
-
-    <!-- Far-right screen [4] -->
-</favorites>
diff --git a/res/xml/default_workspace.xml b/res/xml/default_workspace_4x4.xml
similarity index 100%
rename from res/xml/default_workspace.xml
rename to res/xml/default_workspace_4x4.xml
diff --git a/res/xml/default_workspace_no_all_apps.xml b/res/xml/default_workspace_4x4_no_all_apps.xml
similarity index 100%
rename from res/xml/default_workspace_no_all_apps.xml
rename to res/xml/default_workspace_4x4_no_all_apps.xml
diff --git a/res/xml/default_workspace.xml b/res/xml/default_workspace_5x5.xml
similarity index 100%
copy from res/xml/default_workspace.xml
copy to res/xml/default_workspace_5x5.xml
diff --git a/res/xml/default_workspace_5x5_no_all_apps.xml b/res/xml/default_workspace_5x5_no_all_apps.xml
new file mode 100644
index 0000000..f54a204
--- /dev/null
+++ b/res/xml/default_workspace_5x5_no_all_apps.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
+    <!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
+    <!-- Dialer Hangouts Maps Chrome Camera -->
+    <favorite
+        launcher:packageName="com.google.android.dialer"
+        launcher:className="com.google.android.dialer.extensions.GoogleDialtactsActivity"
+        launcher:container="-101"
+        launcher:screen="1"
+        launcher:x="1"
+        launcher:y="0" />
+    <favorite
+        launcher:packageName="com.google.android.talk"
+        launcher:className="com.google.android.talk.SigningInActivity"
+        launcher:container="-101"
+        launcher:screen="2"
+        launcher:x="2"
+        launcher:y="0" />
+    <favorite
+        launcher:packageName="com.google.android.apps.maps"
+        launcher:className="com.google.android.maps.MapsActivity"
+        launcher:container="-101"
+        launcher:screen="3"
+        launcher:x="3"
+        launcher:y="0"/>
+    <favorite
+        launcher:packageName="com.android.chrome"
+        launcher:className="com.google.android.apps.chrome.Main"
+        launcher:container="-101"
+        launcher:screen="4"
+        launcher:x="4"
+        launcher:y="0" />
+    <favorite
+        launcher:packageName="com.google.android.GoogleCamera"
+        launcher:className="com.android.camera.CameraLauncher"
+        launcher:container="-101"
+        launcher:screen="5"
+        launcher:x="5"
+        launcher:y="0" />
+</favorites>
+
diff --git a/res/xml-sw600dp/default_workspace.xml b/res/xml/default_workspace_5x6.xml
similarity index 100%
rename from res/xml-sw600dp/default_workspace.xml
rename to res/xml/default_workspace_5x6.xml
diff --git a/res/xml/default_workspace_5x6_no_all_apps.xml b/res/xml/default_workspace_5x6_no_all_apps.xml
new file mode 100644
index 0000000..f54a204
--- /dev/null
+++ b/res/xml/default_workspace_5x6_no_all_apps.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
+    <!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
+    <!-- Dialer Hangouts Maps Chrome Camera -->
+    <favorite
+        launcher:packageName="com.google.android.dialer"
+        launcher:className="com.google.android.dialer.extensions.GoogleDialtactsActivity"
+        launcher:container="-101"
+        launcher:screen="1"
+        launcher:x="1"
+        launcher:y="0" />
+    <favorite
+        launcher:packageName="com.google.android.talk"
+        launcher:className="com.google.android.talk.SigningInActivity"
+        launcher:container="-101"
+        launcher:screen="2"
+        launcher:x="2"
+        launcher:y="0" />
+    <favorite
+        launcher:packageName="com.google.android.apps.maps"
+        launcher:className="com.google.android.maps.MapsActivity"
+        launcher:container="-101"
+        launcher:screen="3"
+        launcher:x="3"
+        launcher:y="0"/>
+    <favorite
+        launcher:packageName="com.android.chrome"
+        launcher:className="com.google.android.apps.chrome.Main"
+        launcher:container="-101"
+        launcher:screen="4"
+        launcher:x="4"
+        launcher:y="0" />
+    <favorite
+        launcher:packageName="com.google.android.GoogleCamera"
+        launcher:className="com.android.camera.CameraLauncher"
+        launcher:container="-101"
+        launcher:screen="5"
+        launcher:x="5"
+        launcher:y="0" />
+</favorites>
+
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index e67ec19..8470b39 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -43,16 +43,18 @@
 
 
 class DeviceProfileQuery {
+    DeviceProfile profile;
     float widthDps;
     float heightDps;
     float value;
     PointF dimens;
 
-    DeviceProfileQuery(float w, float h, float v) {
-        widthDps = w;
-        heightDps = h;
+    DeviceProfileQuery(DeviceProfile p, float v) {
+        widthDps = p.minWidthDps;
+        heightDps = p.minHeightDps;
         value = v;
-        dimens = new PointF(w, h);
+        dimens = new PointF(widthDps, heightDps);
+        profile = p;
     }
 }
 
@@ -72,6 +74,9 @@
     private int iconDrawablePaddingOriginalPx;
     private float hotseatIconSize;
 
+    int defaultLayoutId;
+    int defaultNoAllAppsLayoutId;
+
     boolean isLandscape;
     boolean isTablet;
     boolean isLargeTablet;
@@ -127,7 +132,7 @@
     private ArrayList<DeviceProfileCallbacks> mCallbacks = new ArrayList<DeviceProfileCallbacks>();
 
     DeviceProfile(String n, float w, float h, float r, float c,
-                  float is, float its, float hs, float his) {
+                  float is, float its, float hs, float his, int dlId, int dnalId) {
         // Ensure that we have an odd number of hotseat items (since we need to place all apps)
         if (!LauncherAppState.isDisableAllApps() && hs % 2 == 0) {
             throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
@@ -142,6 +147,8 @@
         iconTextSize = its;
         numHotseatIcons = hs;
         hotseatIconSize = his;
+        defaultLayoutId = dlId;
+        defaultNoAllAppsLayoutId = dnalId;
     }
 
     DeviceProfile(Context context,
@@ -182,29 +189,32 @@
         overviewModeScaleFactor =
                 res.getInteger(R.integer.config_dynamic_grid_overview_scale_percentage) / 100f;
 
-        // Interpolate the rows
+        // Find the closes profile given the width/height
         for (DeviceProfile p : profiles) {
-            points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numRows));
+            points.add(new DeviceProfileQuery(p, 0f));
         }
-        numRows = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points));
-        // Interpolate the columns
-        points.clear();
-        for (DeviceProfile p : profiles) {
-            points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numColumns));
-        }
-        numColumns = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points));
-        // Interpolate the hotseat length
-        points.clear();
-        for (DeviceProfile p : profiles) {
-            points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numHotseatIcons));
-        }
-        numHotseatIcons = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points));
+        DeviceProfile closestProfile = findClosestDeviceProfile(minWidth, minHeight, points);
+
+        // Snap to the closest row count
+        numRows = closestProfile.numRows;
+
+        // Snap to the closest column count
+        numColumns = closestProfile.numColumns;
+
+        // Snap to the closest hotseat size
+        numHotseatIcons = closestProfile.numHotseatIcons;
         hotseatAllAppsRank = (int) (numHotseatIcons / 2);
 
+        // Snap to the closest default layout id
+        defaultLayoutId = closestProfile.defaultLayoutId;
+
+        // Snap to the closest default no all-apps layout id
+        defaultNoAllAppsLayoutId = closestProfile.defaultNoAllAppsLayoutId;
+
         // Interpolate the icon size
         points.clear();
         for (DeviceProfile p : profiles) {
-            points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.iconSize));
+            points.add(new DeviceProfileQuery(p, p.iconSize));
         }
         iconSize = invDistWeightedInterpolate(minWidth, minHeight, points);
         // AllApps uses the original non-scaled icon size
@@ -213,7 +223,7 @@
         // Interpolate the icon text size
         points.clear();
         for (DeviceProfile p : profiles) {
-            points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.iconTextSize));
+            points.add(new DeviceProfileQuery(p, p.iconTextSize));
         }
         iconTextSize = invDistWeightedInterpolate(minWidth, minHeight, points);
         iconDrawablePaddingOriginalPx =
@@ -224,7 +234,7 @@
         // Interpolate the hotseat icon size
         points.clear();
         for (DeviceProfile p : profiles) {
-            points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.hotseatIconSize));
+            points.add(new DeviceProfileQuery(p, p.hotseatIconSize));
         }
         // Hotseat
         hotseatIconSize = invDistWeightedInterpolate(minWidth, minHeight, points);
@@ -398,6 +408,28 @@
         return (float) (1f / Math.pow(d, pow));
     }
 
+    /** Returns the closest device profile given the width and height and a list of profiles */
+    private DeviceProfile findClosestDeviceProfile(float width, float height,
+                                                   ArrayList<DeviceProfileQuery> points) {
+        return findClosestDeviceProfiles(width, height, points).get(0).profile;
+    }
+
+    /** Returns the closest device profiles ordered by closeness to the specified width and height */
+    private ArrayList<DeviceProfileQuery> findClosestDeviceProfiles(float width, float height,
+                                                   ArrayList<DeviceProfileQuery> points) {
+        final PointF xy = new PointF(width, height);
+
+        // Sort the profiles by their closeness to the dimensions
+        ArrayList<DeviceProfileQuery> pointsByNearness = points;
+        Collections.sort(pointsByNearness, new Comparator<DeviceProfileQuery>() {
+            public int compare(DeviceProfileQuery a, DeviceProfileQuery b) {
+                return (int) (dist(xy, a.dimens) - dist(xy, b.dimens));
+            }
+        });
+
+        return pointsByNearness;
+    }
+
     private float invDistWeightedInterpolate(float width, float height,
                 ArrayList<DeviceProfileQuery> points) {
         float sum = 0;
@@ -406,12 +438,8 @@
         float kNearestNeighbors = 3;
         final PointF xy = new PointF(width, height);
 
-        ArrayList<DeviceProfileQuery> pointsByNearness = points;
-        Collections.sort(pointsByNearness, new Comparator<DeviceProfileQuery>() {
-            public int compare(DeviceProfileQuery a, DeviceProfileQuery b) {
-                return (int) (dist(xy, a.dimens) - dist(xy, b.dimens));
-            }
-        });
+        ArrayList<DeviceProfileQuery> pointsByNearness = findClosestDeviceProfiles(width, height,
+                points);
 
         for (int i = 0; i < pointsByNearness.size(); ++i) {
             DeviceProfileQuery p = pointsByNearness.get(i);
diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java
index 447bb1c..94a07d7 100644
--- a/src/com/android/launcher3/DynamicGrid.java
+++ b/src/com/android/launcher3/DynamicGrid.java
@@ -60,36 +60,41 @@
         DEFAULT_ICON_SIZE_PX = pxFromDp(DEFAULT_ICON_SIZE_DP, dm);
         // Our phone profiles include the bar sizes in each orientation
         deviceProfiles.add(new DeviceProfile("Super Short Stubby",
-                255, 300,  2, 3,  48, 13, (hasAA ? 5 : 5), 48));
+                255, 300,  2, 3,  48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4,
+                R.xml.default_workspace_4x4_no_all_apps));
         deviceProfiles.add(new DeviceProfile("Shorter Stubby",
-                255, 400,  3, 3,  48, 13, (hasAA ? 5 : 5), 48));
+                255, 400,  3, 3,  48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4,
+                R.xml.default_workspace_4x4_no_all_apps));
         deviceProfiles.add(new DeviceProfile("Short Stubby",
-                275, 420,  3, 4,  48, 13, (hasAA ? 5 : 5), 48));
+                275, 420,  3, 4,  48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4,
+                R.xml.default_workspace_4x4_no_all_apps));
         deviceProfiles.add(new DeviceProfile("Stubby",
-                255, 450,  3, 4,  48, 13, (hasAA ? 5 : 5), 48));
+                255, 450,  3, 4,  48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4,
+                R.xml.default_workspace_4x4_no_all_apps));
         deviceProfiles.add(new DeviceProfile("Nexus S",
-                296, 491.33f,  4, 4,  48, 13, (hasAA ? 5 : 5), 48));
+                296, 491.33f,  4, 4,  48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4,
+                R.xml.default_workspace_4x4_no_all_apps));
         deviceProfiles.add(new DeviceProfile("Nexus 4",
-                335, 567,  4, 4,  DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56));
+                335, 567,  4, 4,  DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56, R.xml.default_workspace_4x4,
+                R.xml.default_workspace_4x4_no_all_apps));
         deviceProfiles.add(new DeviceProfile("Nexus 5",
-                359, 567,  4, 4,  DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56));
+                359, 567,  4, 4,  DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56, R.xml.default_workspace_4x4,
+                R.xml.default_workspace_4x4_no_all_apps));
         deviceProfiles.add(new DeviceProfile("Large Phone",
-                406, 694,  5, 5,  64, 14.4f,  5, 56));
+                406, 694,  5, 5,  64, 14.4f,  5, 56, R.xml.default_workspace_5x5,
+                R.xml.default_workspace_5x5_no_all_apps));
         // The tablet profile is odd in that the landscape orientation
         // also includes the nav bar on the side
         deviceProfiles.add(new DeviceProfile("Nexus 7",
-                575, 904,  5, 6,  72, 14.4f,  7, 60));
+                575, 904,  5, 6,  72, 14.4f,  7, 60, R.xml.default_workspace_5x6,
+                R.xml.default_workspace_5x6_no_all_apps));
         // Larger tablet profiles always have system bars on the top & bottom
         deviceProfiles.add(new DeviceProfile("Nexus 10",
-                727, 1207,  5, 6,  76, 14.4f,  7, 64));
-        /*
-        deviceProfiles.add(new DeviceProfile("Nexus 7",
-                600, 960,  5, 5,  72, 14.4f,  5, 60));
-        deviceProfiles.add(new DeviceProfile("Nexus 10",
-                800, 1280,  5, 5,  80, 14.4f, (hasAA ? 7 : 6), 64));
-         */
+                727, 1207,  5, 6,  76, 14.4f,  7, 64, R.xml.default_workspace_5x6,
+                R.xml.default_workspace_5x6_no_all_apps));
         deviceProfiles.add(new DeviceProfile("20-inch Tablet",
-                1527, 2527,  7, 7,  100, 20,  7, 72));
+                1527, 2527,  7, 7,  100, 20,  7, 72, R.xml.default_workspace_4x4,
+                R.xml.default_workspace_4x4_no_all_apps));
         mMinWidth = dpiFromPx(minWidthPx, dm);
         mMinHeight = dpiFromPx(minHeightPx, dm);
         mProfile = new DeviceProfile(context, deviceProfiles,
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 437c2ad..93708b5 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -336,10 +336,12 @@
     }
 
     private static int getDefaultWorkspaceResourceId() {
+        LauncherAppState app = LauncherAppState.getInstance();
+        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
         if (LauncherAppState.isDisableAllApps()) {
-            return R.xml.default_workspace_no_all_apps;
+            return grid.defaultNoAllAppsLayoutId;
         } else {
-            return R.xml.default_workspace;
+            return grid.defaultLayoutId;
         }
     }