Merge "Fix testQuickSwitchFromApp" into ub-launcher3-qt-future-dev
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 7be584e..de17eb7 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -115,8 +115,6 @@
         <attr name="numFolderColumns" format="integer" />
         <!-- numHotseatIcons defaults to numColumns, if not specified -->
         <attr name="numHotseatIcons" format="integer" />
-        <!-- numAllAppsColumns defaults to numColumns, if not specified -->
-        <attr name="numAllAppsColumns" format="integer" />
         <attr name="defaultLayoutId" format="reference" />
         <attr name="demoModeLayoutId" format="reference" />
     </declare-styleable>
@@ -132,12 +130,6 @@
         <attr name="iconTextSize" format="float" />
         <!-- If true, this display option is used to determine the default grid -->
         <attr name="canBeDefault" format="boolean" />
-
-        <!-- The following values are only enabled if grid is supported. -->
-        <!-- allAppsIconSize defaults to iconSize, if not specified -->
-        <attr name="allAppsIconSize" format="float" />
-        <!-- allAppsIconTextSize defaults to iconTextSize, if not specified -->
-        <attr name="allAppsIconTextSize" format="float" />
     </declare-styleable>
 
     <declare-styleable name="CellLayout">
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 736142f..a35f598 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -25,6 +25,8 @@
 import android.util.DisplayMetrics;
 import android.view.Surface;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.CellLayout.ContainerType;
 import com.android.launcher3.graphics.IconShape;
 import com.android.launcher3.icons.DotRenderer;
@@ -34,6 +36,8 @@
 public class DeviceProfile {
 
     public final InvariantDeviceProfile inv;
+    // IDP with no grid override values.
+    @Nullable private final InvariantDeviceProfile originalIdp;
 
     // Device properties
     public final boolean isTablet;
@@ -134,10 +138,11 @@
     public DotRenderer mDotRendererAllApps;
 
     public DeviceProfile(Context context, InvariantDeviceProfile inv,
-            Point minSize, Point maxSize,
+            InvariantDeviceProfile originalIDP, Point minSize, Point maxSize,
             int width, int height, boolean isLandscape, boolean isMultiWindowMode) {
 
         this.inv = inv;
+        this.originalIdp = inv;
         this.isLandscape = isLandscape;
         this.isMultiWindowMode = isMultiWindowMode;
 
@@ -229,6 +234,19 @@
             // Recalculate the available dimensions using the new hotseat size.
             updateAvailableDimensions(dm, res);
         }
+
+        if (originalIDP != null) {
+            // Grid size change should not affect All Apps UI, so we use the original profile
+            // measurements here.
+            DeviceProfile originalProfile = isLandscape
+                    ? originalIDP.landscapeProfile
+                    : originalIDP.portraitProfile;
+            allAppsIconSizePx = originalProfile.iconSizePx;
+            allAppsIconTextSizePx = originalProfile.iconTextSizePx;
+            allAppsCellHeightPx = originalProfile.allAppsCellHeightPx;
+            allAppsIconDrawablePaddingPx = originalProfile.iconDrawablePaddingOriginalPx;
+            allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx;
+        }
         updateWorkspacePadding();
 
         // This is done last, after iconSizePx is calculated above.
@@ -241,8 +259,8 @@
 
     public DeviceProfile copy(Context context) {
         Point size = new Point(availableWidthPx, availableHeightPx);
-        return new DeviceProfile(context, inv, size, size, widthPx, heightPx, isLandscape,
-                isMultiWindowMode);
+        return new DeviceProfile(context, inv, originalIdp, size, size, widthPx, heightPx,
+                isLandscape, isMultiWindowMode);
     }
 
     public DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
@@ -253,8 +271,8 @@
         // In multi-window mode, we can have widthPx = availableWidthPx
         // and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles'
         // widthPx and heightPx values where it's needed.
-        DeviceProfile profile = new DeviceProfile(context, inv, mwSize, mwSize, mwSize.x, mwSize.y,
-                isLandscape, true);
+        DeviceProfile profile = new DeviceProfile(context, inv, originalIdp, mwSize, mwSize,
+                mwSize.x, mwSize.y, isLandscape, true);
 
         // If there isn't enough vertical cell padding with the labels displayed, hide the labels.
         float workspaceCellPaddingY = profile.getCellSize().y - profile.iconSizePx
@@ -338,18 +356,10 @@
         }
         cellWidthPx = iconSizePx + iconDrawablePaddingPx;
 
-        // All apps
-        if (allAppsHasDifferentNumColumns()) {
-            allAppsIconSizePx = ResourceUtils.pxFromDp(inv.allAppsIconSize, dm);
-            allAppsIconTextSizePx = Utilities.pxFromSp(inv.allAppsIconTextSize, dm);
-            allAppsCellHeightPx = getCellSize(inv.numAllAppsColumns, inv.numAllAppsColumns).y;
-            allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
-        } else {
-            allAppsIconSizePx = iconSizePx;
-            allAppsIconTextSizePx = iconTextSizePx;
-            allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
-            allAppsCellHeightPx = getCellSize().y;
-        }
+        allAppsIconSizePx = iconSizePx;
+        allAppsIconTextSizePx = iconTextSizePx;
+        allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
+        allAppsCellHeightPx = getCellSize().y;
         allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx;
 
         if (isVerticalBarLayout()) {
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 310a9e9..d66ba73 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -58,6 +58,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 
 public class InvariantDeviceProfile {
 
@@ -191,54 +192,11 @@
         Point smallestSize = new Point(displayInfo.smallestSize);
         Point largestSize = new Point(displayInfo.largestSize);
 
-        ArrayList<DisplayOption> allOptions = getPredefinedDeviceProfiles(context, gridName);
         // This guarantees that width < height
         float minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y),
                 displayInfo.metrics);
         float minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y),
                 displayInfo.metrics);
-        // Sort the profiles based on the closeness to the device size
-        Collections.sort(allOptions, (a, b) ->
-                Float.compare(dist(minWidthDps, minHeightDps, a.minWidthDps, a.minHeightDps),
-                        dist(minWidthDps, minHeightDps, b.minWidthDps, b.minHeightDps)));
-        DisplayOption interpolatedDisplayOption =
-                invDistWeightedInterpolate(minWidthDps,  minHeightDps, allOptions);
-
-        GridOption closestProfile = allOptions.get(0).grid;
-        numRows = closestProfile.numRows;
-        numColumns = closestProfile.numColumns;
-        numHotseatIcons = closestProfile.numHotseatIcons;
-        defaultLayoutId = closestProfile.defaultLayoutId;
-        demoModeLayoutId = closestProfile.demoModeLayoutId;
-        numFolderRows = closestProfile.numFolderRows;
-        numFolderColumns = closestProfile.numFolderColumns;
-        numAllAppsColumns = closestProfile.numAllAppsColumns;
-
-        mExtraAttrs = closestProfile.extraAttrs;
-
-        if (!closestProfile.name.equals(gridName)) {
-            Utilities.getPrefs(context).edit()
-                    .putString(KEY_IDP_GRID_NAME, closestProfile.name).apply();
-        }
-
-        iconSize = interpolatedDisplayOption.iconSize;
-        iconShapePath = getIconShapePath(context);
-        landscapeIconSize = interpolatedDisplayOption.landscapeIconSize;
-        iconBitmapSize = ResourceUtils.pxFromDp(iconSize, displayInfo.metrics);
-        iconTextSize = interpolatedDisplayOption.iconTextSize;
-        fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
-
-        if (Utilities.getPrefs(context).getBoolean(GRID_OPTIONS_PREFERENCE_KEY, false)) {
-            allAppsIconSize = interpolatedDisplayOption.allAppsIconSize;
-            allAppsIconTextSize = interpolatedDisplayOption.allAppsIconTextSize;
-        } else {
-            allAppsIconSize = iconSize;
-            allAppsIconTextSize = iconTextSize;
-        }
-
-        // If the partner customization apk contains any grid overrides, apply them
-        // Supported overrides: numRows, numColumns, iconSize
-        applyPartnerDeviceProfileOverrides(context, displayInfo.metrics);
 
         Point realSize = new Point(displayInfo.realSize);
         // The real size never changes. smallSide and largeSide will remain the
@@ -246,10 +204,64 @@
         int smallSide = Math.min(realSize.x, realSize.y);
         int largeSide = Math.max(realSize.x, realSize.y);
 
-        landscapeProfile = new DeviceProfile(context, this, smallestSize, largestSize,
-                largeSide, smallSide, true /* isLandscape */, false /* isMultiWindowMode */);
-        portraitProfile = new DeviceProfile(context, this, smallestSize, largestSize,
-                smallSide, largeSide, false /* isLandscape */, false /* isMultiWindowMode */);
+        // We want a list of all options as well as the list of filtered options. This allows us
+        // to have a consistent UI for areas that the grid size change should not affect
+        // ie. All Apps should be consistent between grid sizes.
+        ArrayList<DisplayOption> allOptions = new ArrayList<>();
+        ArrayList<DisplayOption> filteredOptions = new ArrayList<>();
+        getPredefinedDeviceProfiles(context, gridName, filteredOptions, allOptions);
+
+        if (allOptions.isEmpty() && filteredOptions.isEmpty()) {
+            throw new RuntimeException("No display option with canBeDefault=true");
+        }
+
+        // Sort the profiles based on the closeness to the device size
+        Comparator<DisplayOption> comparator = (a, b) -> Float.compare(dist(minWidthDps,
+                minHeightDps, a.minWidthDps, a.minHeightDps),
+                dist(minWidthDps, minHeightDps, b.minWidthDps, b.minHeightDps));
+
+        // Calculate the device profiles as if there is no grid override.
+        Collections.sort(allOptions, comparator);
+        DisplayOption interpolatedDisplayOption =
+                invDistWeightedInterpolate(minWidthDps,  minHeightDps, allOptions);
+        initGridOption(context, allOptions, interpolatedDisplayOption, displayInfo.metrics);
+
+        // Create IDP with no grid override values.
+        InvariantDeviceProfile originalIDP = new InvariantDeviceProfile(this);
+        originalIDP.landscapeProfile = new DeviceProfile(context, this, null, smallestSize,
+                largestSize, largeSide, smallSide, true /* isLandscape */,
+                false /* isMultiWindowMode */);
+        originalIDP.portraitProfile = new DeviceProfile(context, this, null, smallestSize,
+                largestSize, smallSide, largeSide, false /* isLandscape */,
+                false /* isMultiWindowMode */);
+
+        if (filteredOptions.isEmpty()) {
+            filteredOptions = allOptions;
+
+            landscapeProfile = originalIDP.landscapeProfile;
+            portraitProfile = originalIDP.portraitProfile;
+        } else {
+            Collections.sort(filteredOptions, comparator);
+            interpolatedDisplayOption =
+                    invDistWeightedInterpolate(minWidthDps, minHeightDps, filteredOptions);
+
+            initGridOption(context, filteredOptions, interpolatedDisplayOption,
+                    displayInfo.metrics);
+            numAllAppsColumns = originalIDP.numAllAppsColumns;
+
+            landscapeProfile = new DeviceProfile(context, this, originalIDP, smallestSize,
+                    largestSize, largeSide, smallSide, true /* isLandscape */,
+                    false /* isMultiWindowMode */);
+            portraitProfile = new DeviceProfile(context, this, originalIDP, smallestSize,
+                    largestSize, smallSide, largeSide, false /* isLandscape */,
+                    false /* isMultiWindowMode */);
+        }
+
+        GridOption closestProfile = filteredOptions.get(0).grid;
+        if (!closestProfile.name.equals(gridName)) {
+            Utilities.getPrefs(context).edit()
+                    .putString(KEY_IDP_GRID_NAME, closestProfile.name).apply();
+        }
 
         // We need to ensure that there is enough extra space in the wallpaper
         // for the intended parallax effects
@@ -267,6 +279,33 @@
         return closestProfile.name;
     }
 
+    private void initGridOption(Context context, ArrayList<DisplayOption> options,
+            DisplayOption displayOption, DisplayMetrics metrics) {
+        GridOption closestProfile = options.get(0).grid;
+        numRows = closestProfile.numRows;
+        numColumns = closestProfile.numColumns;
+        numHotseatIcons = closestProfile.numHotseatIcons;
+        defaultLayoutId = closestProfile.defaultLayoutId;
+        demoModeLayoutId = closestProfile.demoModeLayoutId;
+        numFolderRows = closestProfile.numFolderRows;
+        numFolderColumns = closestProfile.numFolderColumns;
+        numAllAppsColumns = numColumns;
+
+        mExtraAttrs = closestProfile.extraAttrs;
+
+        iconSize = displayOption.iconSize;
+        iconShapePath = getIconShapePath(context);
+        landscapeIconSize = displayOption.landscapeIconSize;
+        iconBitmapSize = ResourceUtils.pxFromDp(iconSize, metrics);
+        iconTextSize = displayOption.iconTextSize;
+        fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
+
+        // If the partner customization apk contains any grid overrides, apply them
+        // Supported overrides: numRows, numColumns, iconSize
+        applyPartnerDeviceProfileOverrides(context, metrics);
+    }
+
+
     @Nullable
     public TypedValue getAttrValue(int attr) {
         return mExtraAttrs == null ? null : mExtraAttrs.get(attr);
@@ -344,7 +383,13 @@
         }
     }
 
-    static ArrayList<DisplayOption> getPredefinedDeviceProfiles(Context context, String gridName) {
+    /**
+     * @param gridName The current grid name.
+     * @param filteredOptionsOut List filled with all the filtered options based on gridName.
+     * @param allOptionsOut List filled with all the options that can be the default option.
+     */
+    static void getPredefinedDeviceProfiles(Context context, String gridName,
+            ArrayList<DisplayOption> filteredOptionsOut, ArrayList<DisplayOption> allOptionsOut) {
         ArrayList<DisplayOption> profiles = new ArrayList<>();
         try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
             final int depth = parser.getDepth();
@@ -371,26 +416,19 @@
             throw new RuntimeException(e);
         }
 
-        ArrayList<DisplayOption> filteredProfiles = new ArrayList<>();
         if (!TextUtils.isEmpty(gridName)) {
             for (DisplayOption option : profiles) {
                 if (gridName.equals(option.grid.name)) {
-                    filteredProfiles.add(option);
+                    filteredOptionsOut.add(option);
                 }
             }
         }
-        if (filteredProfiles.isEmpty()) {
-            // No grid found, use the default options
-            for (DisplayOption option : profiles) {
-                if (option.canBeDefault) {
-                    filteredProfiles.add(option);
-                }
+
+        for (DisplayOption option : profiles) {
+            if (option.canBeDefault) {
+                allOptionsOut.add(option);
             }
         }
-        if (filteredProfiles.isEmpty()) {
-            throw new RuntimeException("No display option with canBeDefault=true");
-        }
-        return filteredProfiles;
     }
 
     private int getLauncherIconDensity(int requiredSize) {
@@ -514,8 +552,6 @@
 
         private final int numHotseatIcons;
 
-        private final int numAllAppsColumns;
-
         private final int defaultLayoutId;
         private final int demoModeLayoutId;
 
@@ -538,8 +574,6 @@
                     R.styleable.GridDisplayOption_numFolderRows, numRows);
             numFolderColumns = a.getInt(
                     R.styleable.GridDisplayOption_numFolderColumns, numColumns);
-            numAllAppsColumns = a.getInt(
-                    R.styleable.GridDisplayOption_numAllAppsColumns, numColumns);
 
             a.recycle();
 
@@ -559,8 +593,6 @@
         private float iconSize;
         private float iconTextSize;
         private float landscapeIconSize;
-        private float allAppsIconSize;
-        private float allAppsIconTextSize;
 
         DisplayOption(GridOption grid, Context context, AttributeSet attrs) {
             this.grid = grid;
@@ -579,10 +611,6 @@
                     iconSize);
             iconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0);
 
-            allAppsIconSize = a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconSize,
-                    iconSize);
-            allAppsIconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconTextSize,
-                    iconTextSize);
             a.recycle();
         }
 
@@ -597,18 +625,14 @@
         private DisplayOption multiply(float w) {
             iconSize *= w;
             landscapeIconSize *= w;
-            allAppsIconSize *= w;
             iconTextSize *= w;
-            allAppsIconTextSize *= w;
             return this;
         }
 
         private DisplayOption add(DisplayOption p) {
             iconSize += p.iconSize;
             landscapeIconSize += p.landscapeIconSize;
-            allAppsIconSize += p.allAppsIconSize;
             iconTextSize += p.iconTextSize;
-            allAppsIconTextSize += p.allAppsIconTextSize;
             return this;
         }
     }
diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
index 61ba4e5..5a131c8 100644
--- a/src/com/android/launcher3/util/ViewOnDrawExecutor.java
+++ b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
@@ -55,7 +55,9 @@
             mLoadAnimationCompleted = true;
         }
 
-        attachObserver();
+        if (mAttachedView.isAttachedToWindow()) {
+            attachObserver();
+        }
     }
 
     private void attachObserver() {