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