Merge "Render to measured size when using expand mode" into lmp-mr1-dev
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 6b99de8..ec4d8bf 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -218,7 +218,12 @@
         return NULL;
     }
     SkRegion* region = new SkRegion;
-    region->readFromMemory(regionData, size);
+    size_t actualSize = region->readFromMemory(regionData, size);
+
+    if (size != actualSize) {
+        delete region;
+        return NULL;
+    }
 
     return reinterpret_cast<jlong>(region);
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ccdb5db..baa4e24 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1333,6 +1333,11 @@
                 android:description="@string/permdesc_control_incall_experience"
                 android:label="@string/permlab_control_incall_experience" />
 
+    <!-- Allows an application to receive STK related commands.
+         @hide -->
+    <permission android:name="android.permission.RECEIVE_STK_COMMANDS"
+        android:protectionLevel="system|signature" />
+
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
     <!-- ================================== -->
diff --git a/docs/html/guide/topics/ui/controls/text.jd b/docs/html/guide/topics/ui/controls/text.jd
index 9474dee..c11dc32 100644
--- a/docs/html/guide/topics/ui/controls/text.jd
+++ b/docs/html/guide/topics/ui/controls/text.jd
@@ -172,7 +172,7 @@
 are any subsequent <a
 href="{@docRoot}reference/android/view/View.html#attr_android:focusable">{@code
 android:focusable}</a> fields. If any focusable fields are found following this one, the system
-applies the (@code actionNext} action to the current {@link android.widget.EditText} so the user can
+applies the {@code "actionNext"} action to the current {@link android.widget.EditText} so the user can
 select Next to move to the next field. If there's no subsequent focusable field, the system applies
 the {@code "actionDone"} action. You can override this by setting the <a
 href="{@docRoot}reference/android/widget/TextView.html#attr_android:imeOptions">{@code
@@ -263,7 +263,7 @@
 
 <p>If you want to provide suggestions to users as they type, you can use a subclass of {@link
 android.widget.EditText} called {@link android.widget.AutoCompleteTextView}. To implement
-auto-complete, you must specify an (@link android.widget.Adapter) that provides the text
+auto-complete, you must specify an {@link android.widget.Adapter} that provides the text
 suggestions. There are several kinds of adapters available, depending on where the data is coming
 from, such as from a database or an array.</p>
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4844aa9..e0836a1 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2695,9 +2695,14 @@
             // should never happen).
             SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
             if (procs == null) return null;
-            final int N = procs.size();
-            for (int i = 0; i < N; i++) {
-                if (UserHandle.isSameUser(procs.keyAt(i), uid)) return procs.valueAt(i);
+            final int procCount = procs.size();
+            for (int i = 0; i < procCount; i++) {
+                final int procUid = procs.keyAt(i);
+                if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) {
+                    // Don't use an app process or different user process for system component.
+                    continue;
+                }
+                return procs.valueAt(i);
             }
         }
         ProcessRecord proc = mProcessNames.get(processName, uid);
diff --git a/tools/layoutlib/.idea/artifacts/studio_android_widgets_jar.xml b/tools/layoutlib/.idea/artifacts/studio_android_widgets_jar.xml
new file mode 100644
index 0000000..0450be3
--- /dev/null
+++ b/tools/layoutlib/.idea/artifacts/studio_android_widgets_jar.xml
@@ -0,0 +1,8 @@
+<component name="ArtifactManager">
+  <artifact type="jar" name="studio-android-widgets:jar">
+    <output-path>$PROJECT_DIR$/out/artifacts/studio_android_widgets_jar</output-path>
+    <root id="archive" name="studio-android-widgets.jar">
+      <element id="module-output" name="studio-android-widgets" />
+    </root>
+  </artifact>
+</component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/artifacts/studio_android_widgets_src_jar.xml b/tools/layoutlib/.idea/artifacts/studio_android_widgets_src_jar.xml
new file mode 100644
index 0000000..a844ca3
--- /dev/null
+++ b/tools/layoutlib/.idea/artifacts/studio_android_widgets_src_jar.xml
@@ -0,0 +1,8 @@
+<component name="ArtifactManager">
+  <artifact type="jar" name="studio-android-widgets-src:jar">
+    <output-path>$PROJECT_DIR$/out/artifacts/studio_android_widgets_src_jar</output-path>
+    <root id="archive" name="studio-android-widgets-src.jar">
+      <element id="dir-copy" path="$PROJECT_DIR$/studio-custom-widgets/src" />
+    </root>
+  </artifact>
+</component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/modules.xml b/tools/layoutlib/.idea/modules.xml
index 684f4fd..9bdc381 100644
--- a/tools/layoutlib/.idea/modules.xml
+++ b/tools/layoutlib/.idea/modules.xml
@@ -4,7 +4,7 @@
     <modules>
       <module fileurl="file://$PROJECT_DIR$/bridge/bridge.iml" filepath="$PROJECT_DIR$/bridge/bridge.iml" />
       <module fileurl="file://$PROJECT_DIR$/create/create.iml" filepath="$PROJECT_DIR$/create/create.iml" />
+      <module fileurl="file://$PROJECT_DIR$/studio-custom-widgets/studio-android-widgets.iml" filepath="$PROJECT_DIR$/studio-custom-widgets/studio-android-widgets.iml" />
     </modules>
   </component>
-</project>
-
+</project>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
index 703719c..cbc30c3 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -23,6 +23,8 @@
 
 import android.graphics.Shader.TileMode;
 
+import java.awt.image.ColorModel;
+
 /**
  * Delegate implementing the native methods of android.graphics.LinearGradient
  *
@@ -158,7 +160,7 @@
                     java.awt.image.ColorModel colorModel) {
                 mCanvasMatrix = canvasMatrix;
                 mLocalMatrix = localMatrix;
-                mColorModel = colorModel;
+                mColorModel = colorModel.hasAlpha() ? colorModel : ColorModel.getRGBdefault();
             }
 
             @Override
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index 6edb140..750580b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -23,6 +23,8 @@
 
 import android.graphics.Shader.TileMode;
 
+import java.awt.image.ColorModel;
+
 /**
  * Delegate implementing the native methods of android.graphics.RadialGradient
  *
@@ -146,7 +148,7 @@
                     java.awt.image.ColorModel colorModel) {
                 mCanvasMatrix = canvasMatrix;
                 mLocalMatrix = localMatrix;
-                mColorModel = colorModel;
+                mColorModel = colorModel.hasAlpha() ? colorModel : ColorModel.getRGBdefault();
             }
 
             @Override
diff --git a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
index 38846bd..2f93bc8 100644
--- a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
+++ b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
@@ -34,12 +34,15 @@
      * new image. This method attempts to mimic the same visual characteristics as the rectangular
      * shadow painting methods in this class, {@link #createRectangularDropShadow(java.awt.image.BufferedImage)}
      * and {@link #createSmallRectangularDropShadow(java.awt.image.BufferedImage)}.
+     * <p/>
+     * If shadowSize is less or equals to 1, no shadow will be painted and the source image will be
+     * returned instead.
      *
      * @param source the source image
      * @param shadowSize the size of the shadow, normally {@link #SHADOW_SIZE or {@link
      * #SMALL_SHADOW_SIZE}}
      *
-     * @return a new image with the shadow painted in
+     * @return an image with the shadow painted in or the source image if shadowSize <= 1
      */
     @NonNull
     public static BufferedImage createDropShadow(BufferedImage source, int shadowSize) {
@@ -60,11 +63,15 @@
      * @param shadowOpacity the opacity of the shadow, with 0=transparent and 1=opaque
      * @param shadowRgb the RGB int to use for the shadow color
      *
-     * @return a new image with the source image on top of its shadow
+     * @return a new image with the source image on top of its shadow when shadowSize > 0 or the
+     * source image otherwise
      */
     @SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"})  // Imported code
     public static BufferedImage createDropShadow(BufferedImage source, int shadowSize,
             float shadowOpacity, int shadowRgb) {
+        if (shadowSize <= 0) {
+            return source;
+        }
 
         // This code is based on
         //      http://www.jroller.com/gfx/entry/non_rectangular_shadow
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
index c34f9b5..a39eb4d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -616,6 +616,8 @@
                 return;
             }
 
+            int x = 0;
+            int y = 0;
             int width;
             int height;
             Rectangle clipBounds = originalGraphics.getClipBounds();
@@ -626,6 +628,8 @@
                 }
                 // If we have clipBounds available, use them as they will always be
                 // smaller than the full layer size.
+                x = clipBounds.x;
+                y = clipBounds.y;
                 width = clipBounds.width;
                 height = clipBounds.height;
             } else {
@@ -646,13 +650,20 @@
                     true /*compositeOnly*/, forceMode);
             try {
                 // The main draw operation.
+                // We translate the operation to take into account that the rendering does not
+                // know about the clipping area.
+                imageGraphics.translate(-x, -y);
                 drawable.draw(imageGraphics, paint);
 
                 // Apply the color filter.
+                // Restore the original coordinates system and apply the filter only to the
+                // clipped area.
+                imageGraphics.translate(x, y);
                 filter.applyFilter(imageGraphics, width, height);
 
-                // Draw the tinted image on the main layer.
-                configuredGraphics.drawImage(image, 0, 0, null);
+                // Draw the tinted image on the main layer using as start point the clipping
+                // upper left coordinates.
+                configuredGraphics.drawImage(image, x, y, null);
                 layer.change();
             } finally {
                 // dispose Graphics2D objects
diff --git a/tools/layoutlib/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/ErrorCatcher.java b/tools/layoutlib/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/ErrorCatcher.java
new file mode 100644
index 0000000..ecf39b3
--- /dev/null
+++ b/tools/layoutlib/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/ErrorCatcher.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.tools.idea.editors.theme.widgets;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * {@link ViewGroup} that wraps another view and catches any possible exceptions that the child view
+ * might generate.
+ * This is used by the theme editor to stop custom views from breaking the preview.
+ */
+// TODO: This view is just a temporary solution that will be replaced by adding a try / catch
+// for custom views in the ClassConverter
+public class ErrorCatcher extends ViewGroup {
+    public ErrorCatcher(Context context) {
+        super(context);
+    }
+
+    public ErrorCatcher(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public ErrorCatcher(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public ErrorCatcher(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        assert getChildCount() == 1 : "ErrorCatcher can only have one child";
+
+        View child = getChildAt(0);
+        try {
+            measureChild(child, widthMeasureSpec, heightMeasureSpec);
+
+            setMeasuredDimension(resolveSize(child.getMeasuredWidth(), widthMeasureSpec),
+                    resolveSize(child.getMeasuredHeight(), heightMeasureSpec));
+        } catch (Throwable t) {
+            Bridge.getLog().warning(LayoutLog.TAG_BROKEN, "Failed to do onMeasure for view " +
+                    child.getClass().getCanonicalName(), t);
+            setMeasuredDimension(resolveSize(0, widthMeasureSpec),
+                    resolveSize(0, heightMeasureSpec));
+        }
+    }
+
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        try {
+            return super.drawChild(canvas, child, drawingTime);
+        } catch (Throwable t) {
+            Bridge.getLog().warning(LayoutLog.TAG_BROKEN, "Failed to draw for view " +
+                    child.getClass().getCanonicalName(), t);
+        }
+
+        return false;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        assert getChildCount() == 1 : "ErrorCatcher can only have one child";
+
+        View child = getChildAt(0);
+        try {
+            child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
+        } catch (Throwable e) {
+            Bridge.getLog().warning(LayoutLog.TAG_BROKEN, "Failed to do onLayout for view " +
+                    child.getClass().getCanonicalName(), e);
+        }
+    }
+}
diff --git a/tools/layoutlib/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/PressedButton.java b/tools/layoutlib/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/PressedButton.java
new file mode 100644
index 0000000..4320157
--- /dev/null
+++ b/tools/layoutlib/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/PressedButton.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.tools.idea.editors.theme.widgets;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+@SuppressWarnings("unused")
+public class PressedButton extends Button {
+    public PressedButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        setPressed(true);
+        jumpDrawablesToCurrentState();
+    }
+}
diff --git a/tools/layoutlib/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/ThemePreviewLayout.java b/tools/layoutlib/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/ThemePreviewLayout.java
new file mode 100644
index 0000000..af89910
--- /dev/null
+++ b/tools/layoutlib/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/ThemePreviewLayout.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.tools.idea.editors.theme.widgets;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Custom layout used in the theme editor to display the component preview. It arranges the child
+ * Views as a grid of cards.
+ * <p/>
+ * The Views are measured and the maximum width and height are used to dimension all the child
+ * components. Any margin attributes from the children are ignored and only the item_margin element
+ * is used.
+ */
+@SuppressWarnings("unused")
+public class ThemePreviewLayout extends ViewGroup {
+    private final int mMaxColumns;
+    private final int mMaxColumnWidth;
+    private final int mMinColumnWidth;
+    private final int mItemHorizontalMargin;
+    private final int mItemVerticalMargin;
+
+    /** Item width to use for every card component. This includes margins. */
+    private int mItemWidth;
+    /** Item height to use for every card component. This includes margins. */
+    private int mItemHeight;
+
+    /** Calculated number of columns */
+    private int mNumColumns;
+
+    public ThemePreviewLayout(Context context) {
+        this(context, null);
+    }
+
+    public ThemePreviewLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ThemePreviewLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        if (attrs == null) {
+            mMaxColumnWidth = Integer.MAX_VALUE;
+            mMinColumnWidth = 0;
+            mMaxColumns = Integer.MAX_VALUE;
+            mItemHorizontalMargin = 0;
+            mItemVerticalMargin = 0;
+            return;
+        }
+
+        DisplayMetrics dm = getResources().getDisplayMetrics();
+        int maxColumnWidth = attrs.getAttributeIntValue(null, "max_column_width", Integer
+                .MAX_VALUE);
+        int minColumnWidth = attrs.getAttributeIntValue(null, "min_column_width", 0);
+        int itemHorizontalMargin = attrs.getAttributeIntValue(null, "item_horizontal_margin", 0);
+        int itemVerticalMargin = attrs.getAttributeIntValue(null, "item_vertical_margin", 0);
+
+        mMaxColumnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                maxColumnWidth,
+                dm);
+        mMinColumnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                minColumnWidth,
+                dm);
+        mItemHorizontalMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                itemHorizontalMargin,
+                dm);
+        mItemVerticalMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                itemVerticalMargin,
+                dm);
+        mMaxColumns = attrs.getAttributeIntValue(null, "max_columns", Integer.MAX_VALUE);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // Measure the column size.
+        // The column has a minimum width that will be used to calculate the maximum number of
+        // columns that we can fit in the available space.
+        //
+        // Once we have the maximum number of columns, we will span all columns width evenly to fill
+        // all the available space.
+        int wSize = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
+
+        // Calculate the desired width of all columns and take the maximum.
+        // This step can be skipped if we have a fixed column height so we do not have to
+        // dynamically calculate it.
+        int childWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        int itemWidth = 0;
+        int itemHeight = 0;
+        for (int i = 0; i < getChildCount(); i++) {
+            View v = getChildAt(i);
+
+            if (v.getVisibility() == GONE) {
+                continue;
+            }
+
+            measureChild(v, childWidthSpec, childHeightSpec);
+
+            itemWidth = Math.max(itemWidth, v.getMeasuredWidth());
+            itemHeight = Math.max(itemHeight, v.getMeasuredHeight());
+        }
+
+        itemWidth = Math.min(Math.max(itemWidth, mMinColumnWidth), mMaxColumnWidth);
+        mNumColumns = Math.min((int) Math.ceil((double) wSize / itemWidth), mMaxColumns);
+
+        // Check how much space this distribution would take taking into account the margins.
+        // If it's bigger than what we have, remove one column.
+        int wSizeNeeded = mNumColumns * itemWidth + (mNumColumns - 1) * mItemHorizontalMargin;
+        if (wSizeNeeded > wSize && mNumColumns > 1) {
+            mNumColumns--;
+        }
+
+        if (getChildCount() < mNumColumns) {
+            mNumColumns = getChildCount();
+        }
+        if (mNumColumns == 0) {
+            mNumColumns = 1;
+        }
+
+        // Inform each child of the measurement
+        childWidthSpec = MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY);
+        childHeightSpec = MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY);
+        for (int i = 0; i < getChildCount(); i++) {
+            View v = getChildAt(i);
+
+            if (v.getVisibility() == GONE) {
+                continue;
+            }
+
+            measureChild(v, childWidthSpec, childHeightSpec);
+        }
+
+        // Calculate the height of the first column to measure our own size
+        int firstColumnItems = getChildCount() / mNumColumns + ((getChildCount() % mNumColumns) > 0
+                ? 1 : 0);
+
+        int horizontalMarginsTotalWidth = (mNumColumns - 1) * mItemHorizontalMargin;
+        int verticalMarginsTotalHeight = (firstColumnItems - 1) * mItemVerticalMargin;
+        int totalWidth = mNumColumns * itemWidth + horizontalMarginsTotalWidth +
+                mPaddingRight + mPaddingLeft;
+        int totalHeight = firstColumnItems * itemHeight + verticalMarginsTotalHeight +
+                mPaddingBottom + mPaddingTop;
+
+        setMeasuredDimension(resolveSize(totalWidth, widthMeasureSpec),
+                resolveSize(totalHeight, heightMeasureSpec));
+
+        mItemWidth = itemWidth;
+        mItemHeight = itemHeight;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int itemsPerColumn = getChildCount() / mNumColumns;
+        // The remainder items are distributed one per column.
+        int remainderItems = getChildCount() % mNumColumns;
+
+        int x = mPaddingLeft;
+        int y = mPaddingTop;
+        int position = 1;
+        for (int i = 0; i < getChildCount(); i++) {
+            View v = getChildAt(i);
+            v.layout(x,
+                    y,
+                    x + mItemWidth,
+                    y + mItemHeight);
+
+            if (position == itemsPerColumn + (remainderItems > 0 ? 1 : 0)) {
+                // Break column
+                position = 1;
+                remainderItems--;
+                x += mItemWidth + mItemHorizontalMargin;
+                y = mPaddingTop;
+            } else {
+                position++;
+                y += mItemHeight + mItemVerticalMargin;
+            }
+        }
+    }
+}
+
+
diff --git a/tools/layoutlib/studio-custom-widgets/studio-android-widgets.iml b/tools/layoutlib/studio-custom-widgets/studio-android-widgets.iml
new file mode 100644
index 0000000..b0363d7
--- /dev/null
+++ b/tools/layoutlib/studio-custom-widgets/studio-android-widgets.iml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="layoutlib_api-prebuilt" level="project" />
+    <orderEntry type="library" name="framework.jar" level="project" />
+    <orderEntry type="module" module-name="bridge" />
+  </component>
+</module>
\ No newline at end of file