GridLayout.java revision 6dafd87fb4174447018b044bc67818d54fab57d8
13f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/*
23f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Copyright (C) 2011 The Android Open Source Project
33f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
43f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Licensed under the Apache License, Version 2.0 (the "License");
53f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * you may not use this file except in compliance with the License.
63f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * You may obtain a copy of the License at
73f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
83f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *      http://www.apache.org/licenses/LICENSE-2.0
93f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Unless required by applicable law or agreed to in writing, software
113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * distributed under the License is distributed on an "AS IS" BASIS,
123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See the License for the specific language governing permissions and
143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * limitations under the License.
153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */
163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepackage android.widget;
183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbyeimport android.annotation.IntDef;
203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.content.Context;
213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.content.res.TypedArray;
223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Canvas;
233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Color;
241557fd7809078e421f751efc7d2539b3efdc54b2Philip Milneimport android.graphics.Insets;
253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Paint;
263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.AttributeSet;
273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.Log;
28211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milneimport android.util.LogPrinter;
2948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milneimport android.util.Pair;
30211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milneimport android.util.Printer;
313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.Gravity;
323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.View;
333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.ViewGroup;
34edd69518ffec87fb7b1931e708678ef441152cdePhilip Milneimport android.widget.RemoteViews.RemoteView;
3510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milneimport com.android.internal.R;
363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
37d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbyeimport java.lang.annotation.Retention;
38d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbyeimport java.lang.annotation.RetentionPolicy;
393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.lang.reflect.Array;
403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.ArrayList;
413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Arrays;
423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.HashMap;
433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.List;
443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Map;
453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
465125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milneimport static android.view.Gravity.*;
47899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.EXACTLY;
48899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.makeMeasureSpec;
493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.max;
503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.min;
513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/**
533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * A layout that places its children in a rectangular <em>grid</em>.
543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p>
553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The grid is composed of a set of infinitely thin lines that separate the
563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * viewing area into <em>cells</em>. Throughout the API, grid lines are referenced
577fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * by grid <em>indices</em>. A grid with {@code N} columns
587fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * has {@code N + 1} grid indices that run from {@code 0}
597fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * through {@code N} inclusive. Regardless of how GridLayout is
607fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * configured, grid index {@code 0} is fixed to the leading edge of the
617fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * container and grid index {@code N} is fixed to its trailing edge
623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * (after padding is taken into account).
633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
6493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <h4>Row and Column Specs</h4>
653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Children occupy one or more contiguous cells, as defined
6793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and
6893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters.
6993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Each spec defines the set of rows or columns that are to be
703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * occupied; and how children should be aligned within the resulting group of cells.
713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Although cells do not normally overlap in a GridLayout, GridLayout does
723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * not prevent children being defined to occupy the same cell or group of cells.
733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * In this case however, there is no guarantee that children will not themselves
743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * overlap after the layout operation completes.
753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Default Cell Assignment</h4>
773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
7848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne * If a child does not specify the row and column indices of the cell it
793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * wishes to occupy, GridLayout assigns cell locations automatically using its:
803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setOrientation(int) orientation},
813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setRowCount(int) rowCount} and
823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setColumnCount(int) columnCount} properties.
833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Space</h4>
853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Space between children may be specified either by using instances of the
873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * dedicated {@link Space} view or by setting the
883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#leftMargin leftMargin},
903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#topMargin topMargin},
913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#rightMargin rightMargin} and
923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#bottomMargin bottomMargin}
933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters. When the
953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins}
963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * property is set, default margins around children are automatically
97f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * allocated based on the prevailing UI style guide for the platform.
98f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Each of the margins so defined may be independently overridden by an assignment
993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to the appropriate layout parameter.
100f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Default values will generally produce a reasonable spacing between components
101f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * but values may change between different releases of the platform.
1023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
1033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Excess Space Distribution</h4>
1043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
10587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * As of API 21, GridLayout's distribution of excess space accomodates the principle of weight.
10687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * In the event that no weights are specified, the previous conventions are respected and
10787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * columns and rows are taken as flexible if their views specify some form of alignment
10887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * within their groups.
109f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p>
11087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * The flexibility of a view is therefore influenced by its alignment which is,
11187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * in turn, typically defined by setting the
11287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters.
11387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * If either a weight or alignment were defined along a given axis then the component
11487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * is taken as <em>flexible</em> in that direction. If no weight or alignment was set,
115f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * the component is instead assumed to be <em>inflexible</em>.
116f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p>
117f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Multiple components in the same row or column group are
118f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * considered to act in <em>parallel</em>. Such a
119899d5922870c78e0e663bc5661849eb468afc984Philip Milne * group is flexible only if <em>all</em> of the components
120899d5922870c78e0e663bc5661849eb468afc984Philip Milne * within it are flexible. Row and column groups that sit either side of a common boundary
121899d5922870c78e0e663bc5661849eb468afc984Philip Milne * are instead considered to act in <em>series</em>. The composite group made of these two
122899d5922870c78e0e663bc5661849eb468afc984Philip Milne * elements is flexible if <em>one</em> of its elements is flexible.
123899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p>
124899d5922870c78e0e663bc5661849eb468afc984Philip Milne * To make a column stretch, make sure all of the components inside it define a
12587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * weight or a gravity. To prevent a column from stretching, ensure that one of the components
12687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * in the column does not define a weight or a gravity.
1273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p>
128f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * When the principle of flexibility does not provide complete disambiguation,
129f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em>
13087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * and <em>bottom</em> edges. To be more precise, GridLayout treats each of its layout
13187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * parameters as a constraint in the a set of variables that define the grid-lines along a
13287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * given axis. During layout, GridLayout solves the constraints so as to return the unique
13387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * solution to those constraints for which all variables are less-than-or-equal-to
13487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * the corresponding value in any other valid solution.
135f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne *
136a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * <h4>Interpretation of GONE</h4>
137a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne *
138a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * For layout purposes, GridLayout treats views whose visibility status is
139a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * {@link View#GONE GONE}, as having zero width and height. This is subtly different from
140a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * the policy of ignoring views that are marked as GONE outright. If, for example, a gone-marked
141a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * view was alone in a column, that column would itself collapse to zero width if and only if
142a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * no gravity was defined on the view. If gravity was defined, then the gone-marked
143a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * view has no effect on the layout and the container should be laid out as if the view
1446dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar * had never been added to it. GONE views are taken to have zero weight during excess space
1456dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar * distribution.
1466dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar * <p>
147a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * These statements apply equally to rows as well as columns, and to groups of rows or columns.
148a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne *
1493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p>
1503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See {@link GridLayout.LayoutParams} for a full description of the
1513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters used by GridLayout.
1523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
1533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation
1543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount
1553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount
1563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins
1573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
1583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
1593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */
160edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne@RemoteView
1613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepublic class GridLayout extends ViewGroup {
1623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Public constants
1643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
165d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    /** @hide */
166d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    @IntDef({HORIZONTAL, VERTICAL})
167d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    @Retention(RetentionPolicy.SOURCE)
168d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    public @interface Orientation {}
169d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye
1703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
1713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * The horizontal orientation.
1723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
1733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
174aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
1763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * The vertical orientation.
1773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
1783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final int VERTICAL = LinearLayout.VERTICAL;
1793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
180aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
181aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * The constant used to indicate that a value is undefined.
182aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * Fields can use this value to indicate that their values
183aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * have not yet been set. Similarly, methods can return this value
184aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * to indicate that there is no suitable value that the implementation
185aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * can return.
186aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * The value used for the constant (currently {@link Integer#MIN_VALUE}) is
187aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * intended to avoid confusion between valid values whose sign may not be known.
188aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
189aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    public static final int UNDEFINED = Integer.MIN_VALUE;
190aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
191d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    /** @hide */
192d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    @IntDef({ALIGN_BOUNDS, ALIGN_MARGINS})
193d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    @Retention(RetentionPolicy.SOURCE)
194d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    public @interface AlignmentMode {}
195d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye
1961e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    /**
1971e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * This constant is an {@link #setAlignmentMode(int) alignmentMode}.
1981e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * When the {@code alignmentMode} is set to {@link #ALIGN_BOUNDS}, alignment
1991e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * is made between the edges of each component's raw
2001e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * view boundary: i.e. the area delimited by the component's:
2011e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getTop() top},
2021e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getLeft() left},
2031e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getBottom() bottom} and
2041e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getRight() right} properties.
2051e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * <p>
2061e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * For example, when {@code GridLayout} is in {@link #ALIGN_BOUNDS} mode,
2071e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * children that belong to a row group that uses {@link #TOP} alignment will
2081e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * all return the same value when their {@link android.view.View#getTop()}
2091e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * method is called.
2101e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
2111e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
2121e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     */
2131e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public static final int ALIGN_BOUNDS = 0;
2141e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne
2151e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    /**
2161e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * This constant is an {@link #setAlignmentMode(int) alignmentMode}.
2171e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * When the {@code alignmentMode} is set to {@link #ALIGN_MARGINS},
2181e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * the bounds of each view are extended outwards, according
2191e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * to their margins, before the edges of the resulting rectangle are aligned.
2201e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * <p>
2211e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * For example, when {@code GridLayout} is in {@link #ALIGN_MARGINS} mode,
2221e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * the quantity {@code top - layoutParams.topMargin} is the same for all children that
2231e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * belong to a row group that uses {@link #TOP} alignment.
2241e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
2251e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
2261e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     */
2271e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public static final int ALIGN_MARGINS = 1;
2281e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne
2293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Misc constants
2303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
231f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final int MAX_SIZE = 100000;
232f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final int DEFAULT_CONTAINER_MARGIN = 0;
233d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    static final int UNINITIALIZED_HASH = 0;
234a2353621524472f71850a54b5a41188dd8281039Philip Milne    static final Printer LOG_PRINTER = new LogPrinter(Log.DEBUG, GridLayout.class.getName());
235a2353621524472f71850a54b5a41188dd8281039Philip Milne    static final Printer NO_PRINTER = new Printer() {
236a2353621524472f71850a54b5a41188dd8281039Philip Milne        @Override
237a2353621524472f71850a54b5a41188dd8281039Philip Milne        public void println(String x) {
238a2353621524472f71850a54b5a41188dd8281039Philip Milne        }
239a2353621524472f71850a54b5a41188dd8281039Philip Milne    };
2403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Defaults
2423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private static final int DEFAULT_ORIENTATION = HORIZONTAL;
2443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private static final int DEFAULT_COUNT = UNDEFINED;
2453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false;
246899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static final boolean DEFAULT_ORDER_PRESERVED = true;
2471e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
2483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // TypedArray indices
2503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
251b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ORIENTATION = R.styleable.GridLayout_orientation;
252b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ROW_COUNT = R.styleable.GridLayout_rowCount;
253b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount;
254b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins;
255b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode;
256b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved;
257b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved;
2583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Instance variables
2603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
261465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    final Axis mHorizontalAxis = new Axis(true);
262465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    final Axis mVerticalAxis = new Axis(false);
263465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    int mOrientation = DEFAULT_ORIENTATION;
264465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
265465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
266465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    int mDefaultGap;
267465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    int mLastLayoutParamsHashCode = UNINITIALIZED_HASH;
268465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    Printer mPrinter = LOG_PRINTER;
269aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
2703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Constructors
2713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
272d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette    public GridLayout(Context context) {
273d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette        this(context, null);
274d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette    }
275d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette
276d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette    public GridLayout(Context context, AttributeSet attrs) {
277d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette        this(context, attrs, 0);
278d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette    }
279d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette
280617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public GridLayout(Context context, AttributeSet attrs, int defStyleAttr) {
281617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
282617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
283617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
284617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public GridLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
285617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
286465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
287617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(
288617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                attrs, R.styleable.GridLayout, defStyleAttr, defStyleRes);
2893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        try {
2901e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne            setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
2911e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne            setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT));
2925125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            setOrientation(a.getInt(ORIENTATION, DEFAULT_ORIENTATION));
2935125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            setUseDefaultMargins(a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS));
2945125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            setAlignmentMode(a.getInt(ALIGNMENT_MODE, DEFAULT_ALIGNMENT_MODE));
2953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
2963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
2973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        } finally {
2983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            a.recycle();
2993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
3003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Implementation
3033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
3053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns the current orientation.
3063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3077fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
3083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setOrientation(int)
3103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_orientation
3123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
313d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    @Orientation
3143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public int getOrientation() {
315465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mOrientation;
3163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
319b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *
320b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * GridLayout uses the orientation property for two purposes:
321b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * <ul>
322b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *  <li>
323b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *      To control the 'direction' in which default row/column indices are generated
324b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *      when they are not specified in a component's layout parameters.
325b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *  </li>
326b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *  <li>
327b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *      To control which axis should be processed first during the layout operation:
328b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *      when orientation is {@link #HORIZONTAL} the horizontal axis is laid out first.
329b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *  </li>
330b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * </ul>
331b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *
332b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * The order in which axes are laid out is important if, for example, the height of
333b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * one of GridLayout's children is dependent on its width - and its width is, in turn,
334b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * dependent on the widths of other components.
335b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * <p>
336b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * If your layout contains a {@link TextView} (or derivative:
337b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * {@code Button}, {@code EditText}, {@code CheckBox}, etc.) which is
338b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * in multi-line mode (the default) it is normally best to leave GridLayout's
339b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * orientation as {@code HORIZONTAL} - because {@code TextView} is capable of
340b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * deriving its height for a given width, but not the other way around.
341b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * <p>
342b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * Other than the effects above, orientation does not affect the actual layout operation of
343b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * GridLayout, so it's fine to leave GridLayout in {@code HORIZONTAL} mode even if
344b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * the height of the intended layout greatly exceeds its width.
3457fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
3467fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * The default value of this property is {@link #HORIZONTAL}.
3473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3487fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param orientation either {@link #HORIZONTAL} or {@link #VERTICAL}
3493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getOrientation()
3513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_orientation
3533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
354d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    public void setOrientation(@Orientation int orientation) {
355465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (this.mOrientation != orientation) {
356465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            this.mOrientation = orientation;
357f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            invalidateStructure();
3583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            requestLayout();
3593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
3603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
3633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns the current number of rows. This is either the last value that was set
3643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * with {@link #setRowCount(int)} or, if no such value was set, the maximum
36593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * value of each the upper bounds defined in {@link LayoutParams#rowSpec}.
3663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @return the current number of rows
3683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setRowCount(int)
37093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#rowSpec
3713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowCount
3733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public int getRowCount() {
375465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mVerticalAxis.getCount();
3763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
379f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * RowCount is used only to generate default row/column indices when
380f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * they are not specified by a component's layout parameters.
3813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3827fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param rowCount the number of rows
3833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getRowCount()
38593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#rowSpec
3863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowCount
3883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setRowCount(int rowCount) {
390465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mVerticalAxis.setCount(rowCount);
391f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        invalidateStructure();
392f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        requestLayout();
3933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
3963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns the current number of columns. This is either the last value that was set
3973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * with {@link #setColumnCount(int)} or, if no such value was set, the maximum
39893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * value of each the upper bounds defined in {@link LayoutParams#columnSpec}.
3993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @return the current number of columns
4013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setColumnCount(int)
40393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#columnSpec
4043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnCount
4063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public int getColumnCount() {
408465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mHorizontalAxis.getCount();
4093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
4103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
4113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
412f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * ColumnCount is used only to generate default column/column indices when
413f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * they are not specified by a component's layout parameters.
4143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @param columnCount the number of columns.
4163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getColumnCount()
41893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#columnSpec
4193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnCount
4213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setColumnCount(int columnCount) {
423465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mHorizontalAxis.setCount(columnCount);
424f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        invalidateStructure();
425f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        requestLayout();
4263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
4273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
4283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
4293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns whether or not this GridLayout will allocate default margins when no
4303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * corresponding layout parameters are defined.
4313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4327fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return {@code true} if default margins should be allocated
4333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setUseDefaultMargins(boolean)
4353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_useDefaultMargins
4373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public boolean getUseDefaultMargins() {
439465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mUseDefaultMargins;
4403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
4413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
4423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
4437fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When {@code true}, GridLayout allocates default margins around children
4443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * based on the child's visual characteristics. Each of the
4453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * margins so defined may be independently overridden by an assignment
4463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * to the appropriate layout parameter.
4473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
4487fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When {@code false}, the default value of all margins is zero.
449aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * <p>
4507fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When setting to {@code true}, consider setting the value of the
4511e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link #setAlignmentMode(int) alignmentMode}
4521e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * property to {@link #ALIGN_BOUNDS}.
4537fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
4547fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * The default value of this property is {@code false}.
4553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4567fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param useDefaultMargins use {@code true} to make GridLayout allocate default margins
4573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getUseDefaultMargins()
4591e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
4603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#leftMargin
4623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#topMargin
4633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#rightMargin
4643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#bottomMargin
4653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_useDefaultMargins
4673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setUseDefaultMargins(boolean useDefaultMargins) {
469465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        this.mUseDefaultMargins = useDefaultMargins;
470aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
471aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
472aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
473aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
4741e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * Returns the alignment mode.
4751e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
4761e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @return the alignment mode; either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS}
477aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4781e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_BOUNDS
4791e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_MARGINS
480aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4811e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
482aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4831e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @attr ref android.R.styleable#GridLayout_alignmentMode
484aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
485d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    @AlignmentMode
4861e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public int getAlignmentMode() {
487465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mAlignmentMode;
488aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
489aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
490aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
4911e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * Sets the alignment mode to be used for all of the alignments between the
4921e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * children of this container.
4937fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
4941e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * The default value of this property is {@link #ALIGN_MARGINS}.
4951e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
4961e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @param alignmentMode either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS}
497aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4981e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_BOUNDS
4991e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_MARGINS
500aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
5011e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #getAlignmentMode()
502aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
5031e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @attr ref android.R.styleable#GridLayout_alignmentMode
504aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
505d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye    public void setAlignmentMode(@AlignmentMode int alignmentMode) {
506465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        this.mAlignmentMode = alignmentMode;
507aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
5083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
5113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns whether or not row boundaries are ordered by their grid indices.
5123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5137fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return {@code true} if row boundaries must appear in the order of their indices,
5147fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *         {@code false} otherwise
5153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setRowOrderPreserved(boolean)
5173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
5193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
5203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public boolean isRowOrderPreserved() {
521465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mVerticalAxis.isOrderPreserved();
5223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
5257fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When this property is {@code true}, GridLayout is forced to place the row boundaries
526aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * so that their associated grid indices are in ascending order in the view.
5273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
528899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * When this property is {@code false} GridLayout is at liberty to place the vertical row
529899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * boundaries in whatever order best fits the given constraints.
5307fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
531899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The default value of this property is {@code true}.
5327fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
5337fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param rowOrderPreserved {@code true} to force GridLayout to respect the order
5347fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *        of row boundaries
5353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #isRowOrderPreserved()
5373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
5393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
5403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setRowOrderPreserved(boolean rowOrderPreserved) {
541465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mVerticalAxis.setOrderPreserved(rowOrderPreserved);
542aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        invalidateStructure();
543aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
5443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
5473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns whether or not column boundaries are ordered by their grid indices.
5483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5497fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return {@code true} if column boundaries must appear in the order of their indices,
5507fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *         {@code false} otherwise
5513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setColumnOrderPreserved(boolean)
5533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
5553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
5563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public boolean isColumnOrderPreserved() {
557465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mHorizontalAxis.isOrderPreserved();
5583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
5617fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When this property is {@code true}, GridLayout is forced to place the column boundaries
562aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * so that their associated grid indices are in ascending order in the view.
5633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
564899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * When this property is {@code false} GridLayout is at liberty to place the horizontal column
565899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * boundaries in whatever order best fits the given constraints.
5667fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
567899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The default value of this property is {@code true}.
5683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5697fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param columnOrderPreserved use {@code true} to force GridLayout to respect the order
5703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *        of column boundaries.
5713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #isColumnOrderPreserved()
5733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
5753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
5763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setColumnOrderPreserved(boolean columnOrderPreserved) {
577465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mHorizontalAxis.setOrderPreserved(columnOrderPreserved);
578aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        invalidateStructure();
579aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
5803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
582211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    /**
583211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * Return the printer that will log diagnostics from this layout.
584211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     *
585211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * @see #setPrinter(android.util.Printer)
586211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     *
587211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * @return the printer associated with this view
588465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell     *
589465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell     * @hide
590211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     */
591211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    public Printer getPrinter() {
592465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mPrinter;
593211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    }
594211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne
595211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    /**
596211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * Set the printer that will log diagnostics from this layout.
597211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * The default value is created by {@link android.util.LogPrinter}.
598211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     *
599211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * @param printer the printer associated with this layout
600211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     *
601211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * @see #getPrinter()
602465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell     *
603465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell     * @hide
604211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     */
605211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    public void setPrinter(Printer printer) {
606465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        this.mPrinter = (printer == null) ? NO_PRINTER : printer;
607211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    }
608211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne
6095125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    // Static utility methods
6105125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
611f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static int max2(int[] a, int valueIfEmpty) {
61251f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        int result = valueIfEmpty;
61351f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        for (int i = 0, N = a.length; i < N; i++) {
61451f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne            result = Math.max(result, a[i]);
61551f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        }
61651f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        return result;
61751f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne    }
61851f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne
619899d5922870c78e0e663bc5661849eb468afc984Philip Milne    @SuppressWarnings("unchecked")
620f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static <T> T[] append(T[] a, T[] b) {
62148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
62248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        System.arraycopy(a, 0, result, 0, a.length);
62348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        System.arraycopy(b, 0, result, a.length, b.length);
6243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return result;
6253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
627f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static Alignment getAlignment(int gravity, boolean horizontal) {
6285125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        int mask = horizontal ? HORIZONTAL_GRAVITY_MASK : VERTICAL_GRAVITY_MASK;
6295125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        int shift = horizontal ? AXIS_X_SHIFT : AXIS_Y_SHIFT;
6305125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        int flags = (gravity & mask) >> shift;
6315125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        switch (flags) {
6325125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE):
6331557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne                return horizontal ? LEFT : TOP;
6345125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case (AXIS_SPECIFIED | AXIS_PULL_AFTER):
6351557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne                return horizontal ? RIGHT : BOTTOM;
6365125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER):
6375125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return FILL;
6385125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case AXIS_SPECIFIED:
6395125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return CENTER;
64047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | RELATIVE_LAYOUT_DIRECTION):
64147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio                return START;
64247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio            case (AXIS_SPECIFIED | AXIS_PULL_AFTER | RELATIVE_LAYOUT_DIRECTION):
64347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio                return END;
6445125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            default:
6455125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return UNDEFINED_ALIGNMENT;
6465125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
6475125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
6485125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
6494c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    /** @noinspection UnusedParameters*/
6501fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
651899d5922870c78e0e663bc5661849eb468afc984Philip Milne        if (c.getClass() == Space.class) {
652899d5922870c78e0e663bc5661849eb468afc984Philip Milne            return 0;
653899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
654465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mDefaultGap / 2;
6553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
6571fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
6587b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        return /*isAtEdge ? DEFAULT_CONTAINER_MARGIN :*/ getDefaultMargin(c, horizontal, leading);
6593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
6617a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne    private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) {
662465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (!mUseDefaultMargins) {
6633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return 0;
6643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
66593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        Spec spec = horizontal ? p.columnSpec : p.rowSpec;
666465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
66793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        Interval span = spec.span;
66847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        boolean leading1 = (horizontal && isLayoutRtl()) ? !leading : leading;
66947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount());
6703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
6711fd16378812792913a6aa6923acbec20037e09ffPhilip Milne        return getDefaultMargin(c, isAtEdge, horizontal, leading);
6723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
674f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    int getMargin1(View view, boolean horizontal, boolean leading) {
6753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        LayoutParams lp = getLayoutParams(view);
6763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int margin = horizontal ?
677aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                (leading ? lp.leftMargin : lp.rightMargin) :
678aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                (leading ? lp.topMargin : lp.bottomMargin);
6797a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        return margin == UNDEFINED ? getDefaultMargin(view, lp, horizontal, leading) : margin;
6801fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    }
6811fd16378812792913a6aa6923acbec20037e09ffPhilip Milne
6824c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    private int getMargin(View view, boolean horizontal, boolean leading) {
683465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (mAlignmentMode == ALIGN_MARGINS) {
6844c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            return getMargin1(view, horizontal, leading);
6854c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        } else {
686465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
6874c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins();
6884c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            LayoutParams lp = getLayoutParams(view);
6894c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
6904c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int index = leading ? spec.span.min : spec.span.max;
6914c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            return margins[index];
6924c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        }
6934c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    }
6944c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne
6951fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private int getTotalMargin(View child, boolean horizontal) {
6961fd16378812792913a6aa6923acbec20037e09ffPhilip Milne        return getMargin(child, horizontal, true) + getMargin(child, horizontal, false);
6973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
699899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static boolean fits(int[] a, int value, int start, int end) {
700899d5922870c78e0e663bc5661849eb468afc984Philip Milne        if (end > a.length) {
701899d5922870c78e0e663bc5661849eb468afc984Philip Milne            return false;
702899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
703899d5922870c78e0e663bc5661849eb468afc984Philip Milne        for (int i = start; i < end; i++) {
704899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (a[i] > value) {
705899d5922870c78e0e663bc5661849eb468afc984Philip Milne                return false;
7063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
707899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
708899d5922870c78e0e663bc5661849eb468afc984Philip Milne        return true;
709899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
7103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
711899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static void procrusteanFill(int[] a, int start, int end, int value) {
712899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int length = a.length;
713899d5922870c78e0e663bc5661849eb468afc984Philip Milne        Arrays.fill(a, Math.min(start, length), Math.min(end, length), value);
714899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
7153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
716899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static void setCellGroup(LayoutParams lp, int row, int rowSpan, int col, int colSpan) {
717899d5922870c78e0e663bc5661849eb468afc984Philip Milne        lp.setRowSpecSpan(new Interval(row, row + rowSpan));
718899d5922870c78e0e663bc5661849eb468afc984Philip Milne        lp.setColumnSpecSpan(new Interval(col, col + colSpan));
719899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
7203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
721899d5922870c78e0e663bc5661849eb468afc984Philip Milne    // Logic to avert infinite loops by ensuring that the cells can be placed somewhere.
722899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static int clip(Interval minorRange, boolean minorWasDefined, int count) {
723899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int size = minorRange.size();
724899d5922870c78e0e663bc5661849eb468afc984Philip Milne        if (count == 0) {
725899d5922870c78e0e663bc5661849eb468afc984Philip Milne            return size;
726899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
727899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int min = minorWasDefined ? min(minorRange.min, count) : 0;
728899d5922870c78e0e663bc5661849eb468afc984Philip Milne        return min(size, count - min);
729899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
730f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne
731899d5922870c78e0e663bc5661849eb468afc984Philip Milne    // install default indices for cells that don't define them
732899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private void validateLayoutParams() {
733465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        final boolean horizontal = (mOrientation == HORIZONTAL);
734465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        final Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
735782c04b864dc5f71f7ec0c8e36cbaf5b838dc69cJim Miller        final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0;
736f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne
737899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int major = 0;
738899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int minor = 0;
739899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int[] maxSizes = new int[count];
740f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne
741899d5922870c78e0e663bc5661849eb468afc984Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
742d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
743899d5922870c78e0e663bc5661849eb468afc984Philip Milne
744f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec;
745f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Interval majorRange = majorSpec.span;
746f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final boolean majorWasDefined = majorSpec.startDefined;
747899d5922870c78e0e663bc5661849eb468afc984Philip Milne            final int majorSpan = majorRange.size();
748899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (majorWasDefined) {
749899d5922870c78e0e663bc5661849eb468afc984Philip Milne                major = majorRange.min;
750899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
751899d5922870c78e0e663bc5661849eb468afc984Philip Milne
752f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Spec minorSpec = horizontal ? lp.columnSpec : lp.rowSpec;
753f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Interval minorRange = minorSpec.span;
754f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final boolean minorWasDefined = minorSpec.startDefined;
755899d5922870c78e0e663bc5661849eb468afc984Philip Milne            final int minorSpan = clip(minorRange, minorWasDefined, count);
756899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (minorWasDefined) {
757899d5922870c78e0e663bc5661849eb468afc984Philip Milne                minor = minorRange.min;
758899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
759899d5922870c78e0e663bc5661849eb468afc984Philip Milne
760899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (count != 0) {
761899d5922870c78e0e663bc5661849eb468afc984Philip Milne                // Find suitable row/col values when at least one is undefined.
762899d5922870c78e0e663bc5661849eb468afc984Philip Milne                if (!majorWasDefined || !minorWasDefined) {
763899d5922870c78e0e663bc5661849eb468afc984Philip Milne                    while (!fits(maxSizes, major, minor, minor + minorSpan)) {
764899d5922870c78e0e663bc5661849eb468afc984Philip Milne                        if (minorWasDefined) {
765899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            major++;
766899d5922870c78e0e663bc5661849eb468afc984Philip Milne                        } else {
767899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            if (minor + minorSpan <= count) {
768899d5922870c78e0e663bc5661849eb468afc984Philip Milne                                minor++;
769899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            } else {
770899d5922870c78e0e663bc5661849eb468afc984Philip Milne                                minor = 0;
771899d5922870c78e0e663bc5661849eb468afc984Philip Milne                                major++;
772899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            }
773f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne                        }
774f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne                    }
7753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
776899d5922870c78e0e663bc5661849eb468afc984Philip Milne                procrusteanFill(maxSizes, minor, minor + minorSpan, major + majorSpan);
7773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
778899d5922870c78e0e663bc5661849eb468afc984Philip Milne
779899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (horizontal) {
780899d5922870c78e0e663bc5661849eb468afc984Philip Milne                setCellGroup(lp, major, majorSpan, minor, minorSpan);
781899d5922870c78e0e663bc5661849eb468afc984Philip Milne            } else {
782899d5922870c78e0e663bc5661849eb468afc984Philip Milne                setCellGroup(lp, minor, minorSpan, major, majorSpan);
783899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
784899d5922870c78e0e663bc5661849eb468afc984Philip Milne
785899d5922870c78e0e663bc5661849eb468afc984Philip Milne            minor = minor + minorSpan;
786899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
7873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private void invalidateStructure() {
790465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mLastLayoutParamsHashCode = UNINITIALIZED_HASH;
791465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mHorizontalAxis.invalidateStructure();
792465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mVerticalAxis.invalidateStructure();
793899d5922870c78e0e663bc5661849eb468afc984Philip Milne        // This can end up being done twice. Better twice than not at all.
7943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        invalidateValues();
7953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private void invalidateValues() {
798aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        // Need null check because requestLayout() is called in View's initializer,
799aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        // before we are set up.
800465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (mHorizontalAxis != null && mVerticalAxis != null) {
801465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            mHorizontalAxis.invalidateValues();
802465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            mVerticalAxis.invalidateValues();
803aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
8043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
806d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    /** @hide */
807d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    @Override
808d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    protected void onSetLayoutParams(View child, ViewGroup.LayoutParams layoutParams) {
809d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        super.onSetLayoutParams(child, layoutParams);
8100f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8110f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        if (!checkLayoutParams(layoutParams)) {
8120f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            handleInvalidParams("supplied LayoutParams are of the wrong type");
8130f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        }
8140f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
815d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        invalidateStructure();
8163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
818f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final LayoutParams getLayoutParams(View c) {
819d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        return (LayoutParams) c.getLayoutParams();
8203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8220f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    private static void handleInvalidParams(String msg) {
8230f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        throw new IllegalArgumentException(msg + ". ");
8240f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    }
8250f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8260f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    private void checkLayoutParams(LayoutParams lp, boolean horizontal) {
8270f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        String groupName = horizontal ? "column" : "row";
8280f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
8290f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        Interval span = spec.span;
8300f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        if (span.min != UNDEFINED && span.min < 0) {
8310f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            handleInvalidParams(groupName + " indices must be positive");
8320f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        }
833465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
8340f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        int count = axis.definedCount;
8350f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        if (count != UNDEFINED) {
8360f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            if (span.max > count) {
8370f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                handleInvalidParams(groupName +
8380f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                        " indices (start + span) mustn't exceed the " + groupName + " count");
8390f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            }
8400f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            if (span.size() > count) {
8410f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                handleInvalidParams(groupName + " span mustn't exceed the " + groupName + " count");
8420f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            }
8430f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        }
8440f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    }
8450f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8460f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    @Override
8470f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
8480f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        if (!(p instanceof LayoutParams)) {
8490f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            return false;
8500f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        }
8510f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        LayoutParams lp = (LayoutParams) p;
8520f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8530f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        checkLayoutParams(lp, true);
8540f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        checkLayoutParams(lp, false);
8550f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8560f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        return true;
8570f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    }
8580f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
8603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    protected LayoutParams generateDefaultLayoutParams() {
8613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return new LayoutParams();
8623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
8653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public LayoutParams generateLayoutParams(AttributeSet attrs) {
8665125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return new LayoutParams(getContext(), attrs);
8673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
8703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
8713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return new LayoutParams(p);
8723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Draw grid
8753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
87747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        if (isLayoutRtl()) {
87847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio            int width = getWidth();
8797b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne            graphics.drawLine(width - x1, y1, width - x2, y2, paint);
88047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        } else {
8817b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne            graphics.drawLine(x1, y1, x2, y2, paint);
88247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        }
8833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
88510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne    /**
88610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne     * @hide
88710ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne     */
88810ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne    @Override
8897b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne    protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
89010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        // Apply defaults, so as to remove UNDEFINED values
89110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        LayoutParams lp = new LayoutParams();
89210ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        for (int i = 0; i < getChildCount(); i++) {
89310ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne            View c = getChildAt(i);
89410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne            lp.setMargins(
8957b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                    getMargin1(c, true, true),
8967b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                    getMargin1(c, false, true),
8977b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                    getMargin1(c, true, false),
8987b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                    getMargin1(c, false, false));
8997b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne            lp.onDebugDraw(c, canvas, paint);
90010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        }
901b559976a50c34848d602cc7138859507a379893cPhilip Milne    }
902b559976a50c34848d602cc7138859507a379893cPhilip Milne
90310ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne    /**
90410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne     * @hide
90510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne     */
9063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
90710ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne    protected void onDebugDraw(Canvas canvas) {
90810ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        Paint paint = new Paint();
90910ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        paint.setStyle(Paint.Style.STROKE);
91010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        paint.setColor(Color.argb(50, 255, 255, 255));
91110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne
9127b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        Insets insets = getOpticalInsets();
9137b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne
9147b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        int top    =               getPaddingTop()    + insets.top;
9157b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        int left   =               getPaddingLeft()   + insets.left;
9167b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        int right  = getWidth()  - getPaddingRight()  - insets.right;
9177b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        int bottom = getHeight() - getPaddingBottom() - insets.bottom;
9187b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne
919465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        int[] xs = mHorizontalAxis.locations;
92010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        if (xs != null) {
92110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne            for (int i = 0, length = xs.length; i < length; i++) {
9227b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                int x = left + xs[i];
9237b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                drawLine(canvas, x, top, x, bottom, paint);
924b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            }
92510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        }
926b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
927465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        int[] ys = mVerticalAxis.locations;
92810ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        if (ys != null) {
92910ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne            for (int i = 0, length = ys.length; i < length; i++) {
9307b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                int y = top + ys[i];
9317b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                drawLine(canvas, left, y, right, y, paint);
9323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
9333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
93410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne
93510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        super.onDebugDraw(canvas);
9363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
9373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
9383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Add/remove
9393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
940e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne    /**
941e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     * @hide
942e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     */
9433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
944f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne    protected void onViewAdded(View child) {
945f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne        super.onViewAdded(child);
9463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        invalidateStructure();
9473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
9483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
949e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne    /**
950e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     * @hide
951e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     */
9523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
953f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne    protected void onViewRemoved(View child) {
954f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne        super.onViewRemoved(child);
955b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        invalidateStructure();
956350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne    }
957350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne
958350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne    /**
959350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     * We need to call invalidateStructure() when a child's GONE flag changes state.
960350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     * This implementation is a catch-all, invalidating on any change in the visibility flags.
961350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     *
962350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     * @hide
963350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     */
964350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne    @Override
9650d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
9660d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        super.onChildVisibilityChanged(child, oldVisibility, newVisibility);
9670d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        if (oldVisibility == GONE || newVisibility == GONE) {
968a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne        invalidateStructure();
9690d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        }
970b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    }
971b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne
972d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    private int computeLayoutParamsHashCode() {
973d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        int result = 1;
974d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
975d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            View c = getChildAt(i);
976d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (c.getVisibility() == View.GONE) continue;
977d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            LayoutParams lp = (LayoutParams) c.getLayoutParams();
978d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            result = 31 * result + lp.hashCode();
979d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        }
980d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        return result;
981d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    }
9823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
983edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne    private void consistencyCheck() {
984465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (mLastLayoutParamsHashCode == UNINITIALIZED_HASH) {
985edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne            validateLayoutParams();
986465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            mLastLayoutParamsHashCode = computeLayoutParamsHashCode();
987465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        } else if (mLastLayoutParamsHashCode != computeLayoutParamsHashCode()) {
988465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            mPrinter.println("The fields of some layout parameters were modified in between "
989211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne                    + "layout operations. Check the javadoc for GridLayout.LayoutParams#rowSpec.");
990edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne            invalidateStructure();
991edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne            consistencyCheck();
992d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        }
993b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne    }
994b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
995d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    // Measurement
996d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
997e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne    // Note: padding has already been removed from the supplied specs
9984a145d72622772b920f60195e80942058984259cPhilip Milne    private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec,
999edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne            int childWidth, int childHeight) {
10004a145d72622772b920f60195e80942058984259cPhilip Milne        int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
1001e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne                getTotalMargin(child, true), childWidth);
10024a145d72622772b920f60195e80942058984259cPhilip Milne        int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
1003e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne                getTotalMargin(child, false), childHeight);
10044a145d72622772b920f60195e80942058984259cPhilip Milne        child.measure(childWidthSpec, childHeightSpec);
1005b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne    }
1006b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
1007e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne    // Note: padding has already been removed from the supplied specs
10084a145d72622772b920f60195e80942058984259cPhilip Milne    private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) {
1009b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
1010b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            View c = getChildAt(i);
1011d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (c.getVisibility() == View.GONE) continue;
10124a145d72622772b920f60195e80942058984259cPhilip Milne            LayoutParams lp = getLayoutParams(c);
10134a145d72622772b920f60195e80942058984259cPhilip Milne            if (firstPass) {
10144a145d72622772b920f60195e80942058984259cPhilip Milne                measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
10159505480ee37494a33e12565db4febfb18b6d7494Philip Milne                mHorizontalAxis.recordOriginalMeasurement(i);
10169505480ee37494a33e12565db4febfb18b6d7494Philip Milne                mVerticalAxis.recordOriginalMeasurement(i);
10174a145d72622772b920f60195e80942058984259cPhilip Milne            } else {
1018465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell                boolean horizontal = (mOrientation == HORIZONTAL);
1019ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
10206dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                if (spec.getAbsoluteAlignment(horizontal) == FILL) {
10214a145d72622772b920f60195e80942058984259cPhilip Milne                    Interval span = spec.span;
1022465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell                    Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
10234a145d72622772b920f60195e80942058984259cPhilip Milne                    int[] locations = axis.getLocations();
1024ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                    int cellSize = locations[span.max] - locations[span.min];
1025ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                    int viewSize = cellSize - getTotalMargin(c, horizontal);
1026ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                    if (horizontal) {
1027ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                        measureChildWithMargins2(c, widthSpec, heightSpec, viewSize, lp.height);
10284a145d72622772b920f60195e80942058984259cPhilip Milne                    } else {
1029ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                        measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, viewSize);
10304a145d72622772b920f60195e80942058984259cPhilip Milne                    }
10314a145d72622772b920f60195e80942058984259cPhilip Milne                }
10324a145d72622772b920f60195e80942058984259cPhilip Milne            }
1033b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        }
1034b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne    }
1035b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
1036e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne    static int adjust(int measureSpec, int delta) {
1037e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        return makeMeasureSpec(
1038e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne                MeasureSpec.getSize(measureSpec + delta),  MeasureSpec.getMode(measureSpec));
1039e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne    }
1040e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne
1041aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    @Override
1042aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    protected void onMeasure(int widthSpec, int heightSpec) {
1043edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne        consistencyCheck();
1044d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
10454a145d72622772b920f60195e80942058984259cPhilip Milne        /** If we have been called by {@link View#measure(int, int)}, one of width or height
10464a145d72622772b920f60195e80942058984259cPhilip Milne         *  is  likely to have changed. We must invalidate if so. */
10474a145d72622772b920f60195e80942058984259cPhilip Milne        invalidateValues();
10484a145d72622772b920f60195e80942058984259cPhilip Milne
1049e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int hPadding = getPaddingLeft() + getPaddingRight();
1050e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int vPadding = getPaddingTop()  + getPaddingBottom();
1051e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne
1052e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int widthSpecSansPadding =  adjust( widthSpec, -hPadding);
1053e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int heightSpecSansPadding = adjust(heightSpec, -vPadding);
10544a145d72622772b920f60195e80942058984259cPhilip Milne
1055e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, true);
1056e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne
1057e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int widthSansPadding;
1058e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int heightSansPadding;
10594a145d72622772b920f60195e80942058984259cPhilip Milne
10604a145d72622772b920f60195e80942058984259cPhilip Milne        // Use the orientation property to decide which axis should be laid out first.
1061465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (mOrientation == HORIZONTAL) {
1062465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding);
1063e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne            measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
1064465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding);
10654a145d72622772b920f60195e80942058984259cPhilip Milne        } else {
1066465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding);
1067e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne            measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
1068465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding);
10694a145d72622772b920f60195e80942058984259cPhilip Milne        }
1070aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1071e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int measuredWidth  = Math.max(widthSansPadding  + hPadding, getSuggestedMinimumWidth());
1072e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int measuredHeight = Math.max(heightSansPadding + vPadding, getSuggestedMinimumHeight());
107309e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne
10743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        setMeasuredDimension(
1075e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne                resolveSizeAndState(measuredWidth,   widthSpec, 0),
107609e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne                resolveSizeAndState(measuredHeight, heightSpec, 0));
10773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
10783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
107948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    private int getMeasurement(View c, boolean horizontal) {
10807b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
10813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
10823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1083f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final int getMeasurementIncludingMargin(View c, boolean horizontal) {
1084d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        if (c.getVisibility() == View.GONE) {
10855125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            return 0;
10865125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
10874c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal);
1088aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
10893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1090aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    @Override
1091aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    public void requestLayout() {
1092aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        super.requestLayout();
1093aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        invalidateValues();
1094aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
1095aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
10963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Layout container
10973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1098aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
1099aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * {@inheritDoc}
1100aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
1101aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
1102aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     The layout operation is implemented by delegating the heavy lifting to the
1103aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     to the mHorizontalAxis and mVerticalAxis instances of the internal Axis class.
1104aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     Together they compute the locations of the vertical and horizontal lines of
1105aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     the grid (respectively!).
1106aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1107aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     This method is then left with the simpler task of applying margins, gravity
1108aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     and sizing to each child view and then placing it in its cell.
1109aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
11103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
111109e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1112edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne        consistencyCheck();
1113d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
111409e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne        int targetWidth = right - left;
111509e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne        int targetHeight = bottom - top;
11163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingLeft = getPaddingLeft();
11183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingTop = getPaddingTop();
11193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingRight = getPaddingRight();
11203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingBottom = getPaddingBottom();
11213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1122465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
1123465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom);
11243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1125465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        int[] hLocations = mHorizontalAxis.getLocations();
1126465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        int[] vLocations = mVerticalAxis.getLocations();
11274c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne
1128b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
1129b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            View c = getChildAt(i);
1130d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (c.getVisibility() == View.GONE) continue;
1131b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            LayoutParams lp = getLayoutParams(c);
113293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec columnSpec = lp.columnSpec;
113393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec rowSpec = lp.rowSpec;
1134aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
113593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Interval colSpan = columnSpec.span;
113693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Interval rowSpan = rowSpec.span;
11373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11384c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int x1 = hLocations[colSpan.min];
11394c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int y1 = vLocations[rowSpan.min];
11403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11414c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int x2 = hLocations[colSpan.max];
11424c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int y2 = vLocations[rowSpan.max];
11433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int cellWidth = x2 - x1;
11453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int cellHeight = y2 - y1;
11463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
114748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int pWidth = getMeasurement(c, true);
114848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int pHeight = getMeasurement(c, false);
11493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11506dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar            Alignment hAlign = columnSpec.getAbsoluteAlignment(true);
11516dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar            Alignment vAlign = rowSpec.getAbsoluteAlignment(false);
1152aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1153465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i);
1154465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i);
11557fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
11567fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            // Gravity offsets: the location of the alignment group relative to its cell group.
11576216e87fe8ad3273855233965b34049d22763e94Philip Milne            int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true));
11586216e87fe8ad3273855233965b34049d22763e94Philip Milne            int gravityOffsetY = vAlign.getGravityOffset(c, cellHeight - boundsY.size(true));
11596216e87fe8ad3273855233965b34049d22763e94Philip Milne
11606216e87fe8ad3273855233965b34049d22763e94Philip Milne            int leftMargin = getMargin(c, true, true);
11614c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int topMargin = getMargin(c, false, true);
11626216e87fe8ad3273855233965b34049d22763e94Philip Milne            int rightMargin = getMargin(c, true, false);
11634c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int bottomMargin = getMargin(c, false, false);
11647fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
11651557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int sumMarginsX = leftMargin + rightMargin;
11661557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int sumMarginsY = topMargin + bottomMargin;
11671557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne
11684c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            // Alignment offsets: the location of the view relative to its alignment group.
11691557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true);
11701557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false);
11717fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
11721557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX);
11731557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY);
11747fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
11756216e87fe8ad3273855233965b34049d22763e94Philip Milne            int dx = x1 + gravityOffsetX + alignmentOffsetX;
11763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11776216e87fe8ad3273855233965b34049d22763e94Philip Milne            int cx = !isLayoutRtl() ? paddingLeft + leftMargin + dx :
11786216e87fe8ad3273855233965b34049d22763e94Philip Milne                    targetWidth - width - paddingRight - rightMargin - dx;
11796216e87fe8ad3273855233965b34049d22763e94Philip Milne            int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin;
11803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1181899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) {
1182899d5922870c78e0e663bc5661849eb468afc984Philip Milne                c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
1183899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
1184b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            c.layout(cx, cy, cx + width, cy + height);
11853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
11863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
11873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11888a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
1189a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn    public CharSequence getAccessibilityClassName() {
1190a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn        return GridLayout.class.getName();
11918a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
11928a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
11933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Inner classes
11943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1195aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
1196aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     This internal class houses the algorithm for computing the locations of grid lines;
1197aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     along either the horizontal or vertical axis. A GridLayout uses two instances of this class -
1198aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     distinguished by the "horizontal" flag which is true for the horizontal axis and false
1199aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     for the vertical one.
1200aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
1201f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final class Axis {
120248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private static final int NEW = 0;
12033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int PENDING = 1;
12043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int COMPLETE = 2;
12053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final boolean horizontal;
12073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1208f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int definedCount = UNDEFINED;
12094a145d72622772b920f60195e80942058984259cPhilip Milne        private int maxIndex = UNDEFINED;
12103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
121193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        PackedMap<Spec, Bounds> groupBounds;
12123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean groupBoundsValid = false;
12133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
121448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        PackedMap<Interval, MutableInt> forwardLinks;
121548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean forwardLinksValid = false;
121648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
121748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        PackedMap<Interval, MutableInt> backwardLinks;
121848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean backwardLinksValid = false;
12193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int[] leadingMargins;
1221aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public boolean leadingMarginsValid = false;
1222aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
12233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int[] trailingMargins;
1224aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public boolean trailingMarginsValid = false;
12253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public Arc[] arcs;
12273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean arcsValid = false;
12283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1229aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public int[] locations;
123048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean locationsValid = false;
1231aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
12329505480ee37494a33e12565db4febfb18b6d7494Philip Milne        public boolean hasWeights;
12339505480ee37494a33e12565db4febfb18b6d7494Philip Milne        public boolean hasWeightsValid = false;
12349505480ee37494a33e12565db4febfb18b6d7494Philip Milne        public int[] originalMeasurements;
12359505480ee37494a33e12565db4febfb18b6d7494Philip Milne        public int[] deltas;
12369505480ee37494a33e12565db4febfb18b6d7494Philip Milne
1237f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        boolean orderPreserved = DEFAULT_ORDER_PRESERVED;
12383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
123948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private MutableInt parentMin = new MutableInt(0);
124048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private MutableInt parentMax = new MutableInt(-MAX_SIZE);
124148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
12423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private Axis(boolean horizontal) {
12433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.horizontal = horizontal;
12443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12464a145d72622772b920f60195e80942058984259cPhilip Milne        private int calculateMaxIndex() {
12474a145d72622772b920f60195e80942058984259cPhilip Milne            // the number Integer.MIN_VALUE + 1 comes up in undefined cells
12484a145d72622772b920f60195e80942058984259cPhilip Milne            int result = -1;
1249b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
1250b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                View c = getChildAt(i);
1251b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                LayoutParams params = getLayoutParams(c);
125293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec spec = horizontal ? params.columnSpec : params.rowSpec;
12534a145d72622772b920f60195e80942058984259cPhilip Milne                Interval span = spec.span;
12544a145d72622772b920f60195e80942058984259cPhilip Milne                result = max(result, span.min);
12554a145d72622772b920f60195e80942058984259cPhilip Milne                result = max(result, span.max);
12560f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                result = max(result, span.size());
12573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
12584a145d72622772b920f60195e80942058984259cPhilip Milne            return result == -1 ? UNDEFINED : result;
12593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12614a145d72622772b920f60195e80942058984259cPhilip Milne        private int getMaxIndex() {
12624a145d72622772b920f60195e80942058984259cPhilip Milne            if (maxIndex == UNDEFINED) {
12634a145d72622772b920f60195e80942058984259cPhilip Milne                maxIndex = max(0, calculateMaxIndex()); // use zero when there are no children
12643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
12654a145d72622772b920f60195e80942058984259cPhilip Milne            return maxIndex;
1266f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1267f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1268f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int getCount() {
12694a145d72622772b920f60195e80942058984259cPhilip Milne            return max(definedCount, getMaxIndex());
12703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public void setCount(int count) {
12730f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            if (count != UNDEFINED && count < getMaxIndex()) {
12740f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                handleInvalidParams((horizontal ? "column" : "row") +
12750f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                        "Count must be greater than or equal to the maximum of all grid indices " +
12760f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                        "(and spans) defined in the LayoutParams of each child");
12770f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            }
1278f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.definedCount = count;
12793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean isOrderPreserved() {
1282f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return orderPreserved;
12833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public void setOrderPreserved(boolean orderPreserved) {
1286f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.orderPreserved = orderPreserved;
12873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            invalidateStructure();
12883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
129093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        private PackedMap<Spec, Bounds> createGroupBounds() {
129193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class);
129248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
1293b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                View c = getChildAt(i);
1294a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne                // we must include views that are GONE here, see introductory javadoc
12955125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                LayoutParams lp = getLayoutParams(c);
12965125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
12976dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                Bounds bounds = spec.getAbsoluteAlignment(horizontal).getBounds();
12985125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                assoc.put(spec, bounds);
12993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
130048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return assoc.pack();
13013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
13033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private void computeGroupBounds() {
1304b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            Bounds[] values = groupBounds.values;
1305b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0; i < values.length; i++) {
1306b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                values[i].reset();
13073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
1308aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
13093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                View c = getChildAt(i);
1310a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne                // we must include views that are GONE here, see introductory javadoc
13113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                LayoutParams lp = getLayoutParams(c);
131293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
1313dea890fa64bca15637e824306aa301775e933eeePhilip Milne                int size = (spec.weight == 0) ?
13149505480ee37494a33e12565db4febfb18b6d7494Philip Milne                        getMeasurementIncludingMargin(c, horizontal) :
13159505480ee37494a33e12565db4febfb18b6d7494Philip Milne                        getOriginalMeasurements()[i] + getDeltas()[i];
13169505480ee37494a33e12565db4febfb18b6d7494Philip Milne                groupBounds.getValue(i).include(GridLayout.this, c, spec, this, size);
13173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1320f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public PackedMap<Spec, Bounds> getGroupBounds() {
13213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (groupBounds == null) {
13223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                groupBounds = createGroupBounds();
13233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (!groupBoundsValid) {
13253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                computeGroupBounds();
13263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                groupBoundsValid = true;
13273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return groupBounds;
13293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
13313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Add values computed by alignment - taking the max of all alignments in each span
133248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private PackedMap<Interval, MutableInt> createLinks(boolean min) {
133348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class);
133493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec[] keys = getGroupBounds().keys;
133548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0, N = keys.length; i < N; i++) {
133648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Interval span = min ? keys[i].span : keys[i].span.inverse();
133748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                result.put(span, new MutableInt());
13383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
133948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return result.pack();
13403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
134248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void computeLinks(PackedMap<Interval, MutableInt> links, boolean min) {
134348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            MutableInt[] spans = links.values;
13443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < spans.length; i++) {
13453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                spans[i].reset();
13463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
13485d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            // Use getter to trigger a re-evaluation
134948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Bounds[] bounds = getGroupBounds().values;
13503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < bounds.length; i++) {
135148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                int size = bounds[i].size(min);
135248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                MutableInt valueHolder = links.getValue(i);
13535125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                // this effectively takes the max() of the minima and the min() of the maxima
13545125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                valueHolder.value = max(valueHolder.value, min ? size : -size);
13553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
135848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private PackedMap<Interval, MutableInt> getForwardLinks() {
135948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (forwardLinks == null) {
136048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                forwardLinks = createLinks(true);
13613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
136248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!forwardLinksValid) {
136348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeLinks(forwardLinks, true);
136448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                forwardLinksValid = true;
13653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
136648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return forwardLinks;
13673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
136948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private PackedMap<Interval, MutableInt> getBackwardLinks() {
137048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (backwardLinks == null) {
137148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                backwardLinks = createLinks(false);
13723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
137348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!backwardLinksValid) {
137448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeLinks(backwardLinks, false);
137548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                backwardLinksValid = true;
137648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
137748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return backwardLinks;
13783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
138048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void include(List<Arc> arcs, Interval key, MutableInt size,
1381edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne                boolean ignoreIfAlreadyPresent) {
138248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            /*
138348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Remove self referential links.
138448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            These appear:
138548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                . as parental constraints when GridLayout has no children
138648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                . when components have been marked as GONE
138748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            */
138848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (key.size() == 0) {
138948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                return;
13903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
139148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // this bit below should really be computed outside here -
139248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // its just to stop default (row/col > 0) constraints obliterating valid entries
139348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (ignoreIfAlreadyPresent) {
139448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                for (Arc arc : arcs) {
139548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    Interval span = arc.span;
139648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    if (span.equals(key)) {
139748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        return;
139848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    }
139948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
140048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
140148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            arcs.add(new Arc(key, size));
14023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
14033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
140448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void include(List<Arc> arcs, Interval key, MutableInt size) {
140548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(arcs, key, size, true);
14063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
14073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1408aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        // Group arcs by their first vertex, returning an array of arrays.
14093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // This is linear in the number of arcs.
1410f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        Arc[][] groupArcsByFirstVertex(Arc[] arcs) {
141148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int N = getCount() + 1; // the number of vertices
14123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Arc[][] result = new Arc[N][];
14133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int[] sizes = new int[N];
14143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (Arc arc : arcs) {
14153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                sizes[arc.span.min]++;
14165d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            }
14173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < sizes.length; i++) {
14183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                result[i] = new Arc[sizes[i]];
14193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
14203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            // reuse the sizes array to hold the current last elements as we insert each arc
14213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Arrays.fill(sizes, 0);
14223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (Arc arc : arcs) {
14233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int i = arc.span.min;
14243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                result[i][sizes[i]++] = arc;
14253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
14263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
14273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
14283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
14293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
143048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private Arc[] topologicalSort(final Arc[] arcs) {
143148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return new Object() {
143248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Arc[] result = new Arc[arcs.length];
143348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                int cursor = result.length - 1;
143448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Arc[][] arcsByVertex = groupArcsByFirstVertex(arcs);
14353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int[] visited = new int[getCount() + 1];
14363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
143748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                void walk(int loc) {
143848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    switch (visited[loc]) {
143948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        case NEW: {
144048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            visited[loc] = PENDING;
144148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            for (Arc arc : arcsByVertex[loc]) {
144248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                                walk(arc.span.max);
144348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                                result[cursor--] = arc;
14443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                            }
144548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            visited[loc] = COMPLETE;
144648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            break;
144748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        }
144848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        case PENDING: {
1449b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne                            // le singe est dans l'arbre
145048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            assert false;
145148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            break;
145248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        }
145348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        case COMPLETE: {
145448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            break;
14553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                        }
14563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    }
14573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
145848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
145948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Arc[] sort() {
146048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    for (int loc = 0, N = arcsByVertex.length; loc < N; loc++) {
146148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        walk(loc);
146248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    }
146348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    assert cursor == -1;
146448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return result;
146548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
146648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }.sort();
146748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
146848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
146948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private Arc[] topologicalSort(List<Arc> arcs) {
147048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return topologicalSort(arcs.toArray(new Arc[arcs.size()]));
14713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
14723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
147348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void addComponentSizes(List<Arc> result, PackedMap<Interval, MutableInt> links) {
147448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0; i < links.keys.length; i++) {
147548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Interval key = links.keys[i];
147648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                include(result, key, links.values[i], false);
147748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
147848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
147948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1480aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private Arc[] createArcs() {
148148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            List<Arc> mins = new ArrayList<Arc>();
148248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            List<Arc> maxs = new ArrayList<Arc>();
14833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
148448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add the minimum values from the components.
148548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            addComponentSizes(mins, getForwardLinks());
148648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add the maximum values from the components.
148748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            addComponentSizes(maxs, getBackwardLinks());
14883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
148948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add ordering constraints to prevent row/col sizes from going negative
1490f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            if (orderPreserved) {
149148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                // Add a constraint for every row/col
14923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                for (int i = 0; i < getCount(); i++) {
1493899d5922870c78e0e663bc5661849eb468afc984Philip Milne                    include(mins, new Interval(i, i + 1), new MutableInt(0));
14943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
14953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
149648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
149748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add the container constraints. Use the version of include that allows
149848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // duplicate entries in case a child spans the entire grid.
149948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int N = getCount();
150048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(mins, new Interval(0, N), parentMin, false);
150148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(maxs, new Interval(N, 0), parentMax, false);
150248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
150348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Sort
150448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Arc[] sMins = topologicalSort(mins);
150548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Arc[] sMaxs = topologicalSort(maxs);
150648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
150748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return append(sMins, sMaxs);
150848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
150948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
151048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void computeArcs() {
151148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // getting the links validates the values that are shared by the arc list
151248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            getForwardLinks();
151348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            getBackwardLinks();
15143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1516aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public Arc[] getArcs() {
15173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (arcs == null) {
1518aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                arcs = createArcs();
15193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
15203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (!arcsValid) {
152148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeArcs();
15223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                arcsValid = true;
15233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
15243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return arcs;
15253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1527aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private boolean relax(int[] locations, Arc entry) {
152848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!entry.valid) {
152948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                return false;
153048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
15313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Interval span = entry.span;
15323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int u = span.min;
15333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int v = span.max;
15343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int value = entry.value.value;
15353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int candidate = locations[u] + value;
1536aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (candidate > locations[v]) {
15373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                locations[v] = candidate;
15383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return true;
15393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
15403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return false;
15413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1543f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private void init(int[] locations) {
15444a145d72622772b920f60195e80942058984259cPhilip Milne            Arrays.fill(locations, 0);
1545f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1546f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1547f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private String arcsToString(List<Arc> arcs) {
15484a145d72622772b920f60195e80942058984259cPhilip Milne            String var = horizontal ? "x" : "y";
1549f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            StringBuilder result = new StringBuilder();
15504a145d72622772b920f60195e80942058984259cPhilip Milne            boolean first = true;
15514a145d72622772b920f60195e80942058984259cPhilip Milne            for (Arc arc : arcs) {
15524a145d72622772b920f60195e80942058984259cPhilip Milne                if (first) {
15534a145d72622772b920f60195e80942058984259cPhilip Milne                    first = false;
1554f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                } else {
15554a145d72622772b920f60195e80942058984259cPhilip Milne                    result = result.append(", ");
1556f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
1557f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                int src = arc.span.min;
1558f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                int dst = arc.span.max;
1559f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                int value = arc.value.value;
1560f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                result.append((src < dst) ?
1561edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne                        var + dst + "-" + var + src + ">=" + value :
1562edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne                        var + src + "-" + var + dst + "<=" + -value);
1563f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1564f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            }
1565f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return result.toString();
1566f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1567f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1568f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private void logError(String axisName, Arc[] arcs, boolean[] culprits0) {
1569f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            List<Arc> culprits = new ArrayList<Arc>();
1570f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            List<Arc> removed = new ArrayList<Arc>();
1571f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            for (int c = 0; c < arcs.length; c++) {
1572f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                Arc arc = arcs[c];
1573f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                if (culprits0[c]) {
1574f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    culprits.add(arc);
1575f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
1576f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                if (!arc.valid) {
1577f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    removed.add(arc);
1578f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
1579f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            }
1580465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            mPrinter.println(axisName + " constraints: " + arcsToString(culprits) +
1581211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne                    " are inconsistent; permanently removing: " + arcsToString(removed) + ". ");
1582f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1583f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1584aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        /*
1585aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N)
1586aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1587aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        GridLayout converts its requirements into a system of linear constraints of the
1588aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        form:
1589aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1590aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        x[i] - x[j] < a[k]
1591aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1592aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Where the x[i] are variables and the a[k] are constants.
1593aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1594aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        For example, if the variables were instead labeled x, y, z we might have:
1595aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1596aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            x - y < 17
1597aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            y - z < 23
1598aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            z - x < 42
1599aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1600aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        This is a special case of the Linear Programming problem that is, in turn,
1601aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        equivalent to the single-source shortest paths problem on a digraph, for
1602aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        which the O(n^2) Bellman-Ford algorithm the most commonly used general solution.
1603aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        */
160498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar        private boolean solve(Arc[] arcs, int[] locations) {
160598d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            return solve(arcs, locations, true);
160698d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar        }
160798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar
160898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar        private boolean solve(Arc[] arcs, int[] locations, boolean modifyOnError) {
1609f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            String axisName = horizontal ? "horizontal" : "vertical";
16103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
1611f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            boolean[] originalCulprits = null;
16123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1613f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            for (int p = 0; p < arcs.length; p++) {
1614f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                init(locations);
1615f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1616f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                // We take one extra pass over traditional Bellman-Ford (and omit their final step)
1617f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                for (int i = 0; i < N; i++) {
1618f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    boolean changed = false;
1619f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    for (int j = 0, length = arcs.length; j < length; j++) {
1620f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        changed |= relax(locations, arcs[j]);
1621f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    }
1622f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    if (!changed) {
1623f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        if (originalCulprits != null) {
1624f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                            logError(axisName, arcs, originalCulprits);
1625f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        }
162698d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                        return true;
16273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    }
16283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
162948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
163098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                if (!modifyOnError) {
163198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                    return false; // cannot solve with these constraints
163298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                }
163398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar
1634f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                boolean[] culprits = new boolean[arcs.length];
1635f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                for (int i = 0; i < N; i++) {
1636f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    for (int j = 0, length = arcs.length; j < length; j++) {
1637f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        culprits[j] |= relax(locations, arcs[j]);
1638f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    }
1639f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
164048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1641f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                if (p == 0) {
1642f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    originalCulprits = culprits;
164348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
1644f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1645f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                for (int i = 0; i < arcs.length; i++) {
1646f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    if (culprits[i]) {
1647f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        Arc arc = arcs[i];
1648f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        // Only remove max values, min values alone cannot be inconsistent
1649f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        if (arc.span.min < arc.span.max) {
1650f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                            continue;
1651f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        }
1652f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        arc.valid = false;
1653f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        break;
165448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    }
165548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
165648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
165798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            return true;
16583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
16593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1660aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private void computeMargins(boolean leading) {
1661aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            int[] margins = leading ? leadingMargins : trailingMargins;
1662b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
16633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                View c = getChildAt(i);
1664d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne                if (c.getVisibility() == View.GONE) continue;
16653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                LayoutParams lp = getLayoutParams(c);
166693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
166793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Interval span = spec.span;
16683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int index = leading ? span.min : span.max;
16694c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne                margins[index] = max(margins[index], getMargin1(c, horizontal, leading));
16703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
16713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
16723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1673f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        // External entry points
1674f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1675f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int[] getLeadingMargins() {
1676aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (leadingMargins == null) {
1677aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                leadingMargins = new int[getCount() + 1];
1678aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1679aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (!leadingMarginsValid) {
1680aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                computeMargins(true);
1681aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                leadingMarginsValid = true;
1682aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1683aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            return leadingMargins;
1684aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
1685aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1686f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int[] getTrailingMargins() {
1687aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (trailingMargins == null) {
1688aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                trailingMargins = new int[getCount() + 1];
1689aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1690aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (!trailingMarginsValid) {
1691aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                computeMargins(false);
1692aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                trailingMarginsValid = true;
1693aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1694aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            return trailingMargins;
1695aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
16963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
169798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar        private boolean solve(int[] a) {
169898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            return solve(getArcs(), a);
169987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        }
170087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne
17019505480ee37494a33e12565db4febfb18b6d7494Philip Milne        private boolean computeHasWeights() {
17029505480ee37494a33e12565db4febfb18b6d7494Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
17036dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                final View child = getChildAt(i);
17046dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                if (child.getVisibility() == View.GONE) {
17056dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                    continue;
17066dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                }
17076dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                LayoutParams lp = getLayoutParams(child);
17089505480ee37494a33e12565db4febfb18b6d7494Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
17099505480ee37494a33e12565db4febfb18b6d7494Philip Milne                if (spec.weight != 0) {
171087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne                    return true;
171187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne                }
171287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne            }
171387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne            return false;
171487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        }
171587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne
17169505480ee37494a33e12565db4febfb18b6d7494Philip Milne        private boolean hasWeights() {
17179505480ee37494a33e12565db4febfb18b6d7494Philip Milne            if (!hasWeightsValid) {
17189505480ee37494a33e12565db4febfb18b6d7494Philip Milne                hasWeights = computeHasWeights();
17199505480ee37494a33e12565db4febfb18b6d7494Philip Milne                hasWeightsValid = true;
17209505480ee37494a33e12565db4febfb18b6d7494Philip Milne            }
17219505480ee37494a33e12565db4febfb18b6d7494Philip Milne            return hasWeights;
17229505480ee37494a33e12565db4febfb18b6d7494Philip Milne        }
17239505480ee37494a33e12565db4febfb18b6d7494Philip Milne
17249505480ee37494a33e12565db4febfb18b6d7494Philip Milne        public int[] getOriginalMeasurements() {
17259505480ee37494a33e12565db4febfb18b6d7494Philip Milne            if (originalMeasurements == null) {
17269505480ee37494a33e12565db4febfb18b6d7494Philip Milne                originalMeasurements = new int[getChildCount()];
17279505480ee37494a33e12565db4febfb18b6d7494Philip Milne            }
17289505480ee37494a33e12565db4febfb18b6d7494Philip Milne            return originalMeasurements;
17299505480ee37494a33e12565db4febfb18b6d7494Philip Milne        }
17309505480ee37494a33e12565db4febfb18b6d7494Philip Milne
17319505480ee37494a33e12565db4febfb18b6d7494Philip Milne        private void recordOriginalMeasurement(int i) {
17329505480ee37494a33e12565db4febfb18b6d7494Philip Milne            if (hasWeights()) {
17339505480ee37494a33e12565db4febfb18b6d7494Philip Milne                getOriginalMeasurements()[i] = getMeasurementIncludingMargin(getChildAt(i), horizontal);
17349505480ee37494a33e12565db4febfb18b6d7494Philip Milne            }
17359505480ee37494a33e12565db4febfb18b6d7494Philip Milne        }
17369505480ee37494a33e12565db4febfb18b6d7494Philip Milne
17379505480ee37494a33e12565db4febfb18b6d7494Philip Milne        public int[] getDeltas() {
17389505480ee37494a33e12565db4febfb18b6d7494Philip Milne            if (deltas == null) {
17399505480ee37494a33e12565db4febfb18b6d7494Philip Milne                deltas = new int[getChildCount()];
17409505480ee37494a33e12565db4febfb18b6d7494Philip Milne            }
17419505480ee37494a33e12565db4febfb18b6d7494Philip Milne            return deltas;
17429505480ee37494a33e12565db4febfb18b6d7494Philip Milne        }
17439505480ee37494a33e12565db4febfb18b6d7494Philip Milne
174498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar        private void shareOutDelta(int totalDelta, float totalWeight) {
174598d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            Arrays.fill(deltas, 0);
17469505480ee37494a33e12565db4febfb18b6d7494Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
17476dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                final View c = getChildAt(i);
17486dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                if (c.getVisibility() == View.GONE) {
17496dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                    continue;
17506dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                }
17519505480ee37494a33e12565db4febfb18b6d7494Philip Milne                LayoutParams lp = getLayoutParams(c);
17529505480ee37494a33e12565db4febfb18b6d7494Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
17539505480ee37494a33e12565db4febfb18b6d7494Philip Milne                float weight = spec.weight;
17549505480ee37494a33e12565db4febfb18b6d7494Philip Milne                if (weight != 0) {
175587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne                    int delta = Math.round((weight * totalDelta / totalWeight));
17569505480ee37494a33e12565db4febfb18b6d7494Philip Milne                    deltas[i] = delta;
175798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                    // the two adjustments below are to counter the above rounding and avoid
175898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                    // off-by-ones at the end
175987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne                    totalDelta -= delta;
176087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne                    totalWeight -= weight;
176187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne                }
176287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne            }
176387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        }
176487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne
176587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        private void solveAndDistributeSpace(int[] a) {
17669505480ee37494a33e12565db4febfb18b6d7494Philip Milne            Arrays.fill(getDeltas(), 0);
17679505480ee37494a33e12565db4febfb18b6d7494Philip Milne            solve(a);
176898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            int deltaMax = parentMin.value * getChildCount() + 1; //exclusive
176998d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            if (deltaMax < 2) {
177098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                return; //don't have any delta to distribute
177198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            }
177298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            int deltaMin = 0; //inclusive
177398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar
177498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            float totalWeight = calculateTotalWeight();
177598d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar
177698d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            int validDelta = -1; //delta for which a solution exists
177798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            boolean validSolution = true;
177898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            // do a binary search to find the max delta that won't conflict with constraints
177998d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            while(deltaMin < deltaMax) {
178098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                final int delta = (deltaMin + deltaMax) / 2;
178198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                invalidateValues();
178298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                shareOutDelta(delta, totalWeight);
178398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                validSolution = solve(getArcs(), a, false);
178498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                if (validSolution) {
178598d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                    validDelta = delta;
178698d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                    deltaMin = delta + 1;
178798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                } else {
178898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                    deltaMax = delta;
178998d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                }
179098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            }
179198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            if (validDelta > 0 && !validSolution) {
179298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                // last solution was not successful but we have a successful one. Use it.
179398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                invalidateValues();
179498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                shareOutDelta(validDelta, totalWeight);
179598d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                solve(a);
179698d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            }
179798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar        }
179898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar
179998d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar        private float calculateTotalWeight() {
180098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            float totalWeight = 0f;
180198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            for (int i = 0, N = getChildCount(); i < N; i++) {
180298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                View c = getChildAt(i);
18036dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                if (c.getVisibility() == View.GONE) {
18046dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                    continue;
18056dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                }
180698d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                LayoutParams lp = getLayoutParams(c);
180798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
180898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar                totalWeight += spec.weight;
180998d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            }
181098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar            return totalWeight;
181187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        }
181287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne
181387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        private void computeLocations(int[] a) {
18149505480ee37494a33e12565db4febfb18b6d7494Philip Milne            if (!hasWeights()) {
18159505480ee37494a33e12565db4febfb18b6d7494Philip Milne                solve(a);
18169505480ee37494a33e12565db4febfb18b6d7494Philip Milne            } else {
18179505480ee37494a33e12565db4febfb18b6d7494Philip Milne                solveAndDistributeSpace(a);
18189505480ee37494a33e12565db4febfb18b6d7494Philip Milne            }
18194a145d72622772b920f60195e80942058984259cPhilip Milne            if (!orderPreserved) {
18204a145d72622772b920f60195e80942058984259cPhilip Milne                // Solve returns the smallest solution to the constraint system for which all
18214a145d72622772b920f60195e80942058984259cPhilip Milne                // values are positive. One value is therefore zero - though if the row/col
18224a145d72622772b920f60195e80942058984259cPhilip Milne                // order is not preserved this may not be the first vertex. For consistency,
18234a145d72622772b920f60195e80942058984259cPhilip Milne                // translate all the values so that they measure the distance from a[0]; the
18244a145d72622772b920f60195e80942058984259cPhilip Milne                // leading edge of the parent. After this transformation some values may be
18254a145d72622772b920f60195e80942058984259cPhilip Milne                // negative.
18264a145d72622772b920f60195e80942058984259cPhilip Milne                int a0 = a[0];
18274a145d72622772b920f60195e80942058984259cPhilip Milne                for (int i = 0, N = a.length; i < N; i++) {
18284a145d72622772b920f60195e80942058984259cPhilip Milne                    a[i] = a[i] - a0;
18294a145d72622772b920f60195e80942058984259cPhilip Milne                }
18304a145d72622772b920f60195e80942058984259cPhilip Milne            }
18313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1833f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int[] getLocations() {
1834aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (locations == null) {
1835aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                int N = getCount() + 1;
1836aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                locations = new int[N];
1837aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
183848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!locationsValid) {
183948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeLocations(locations);
184048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                locationsValid = true;
184148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
1842aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            return locations;
18433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1845aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private int size(int[] locations) {
18464a145d72622772b920f60195e80942058984259cPhilip Milne            // The parental edges are attached to vertices 0 and N - even when order is not
18474a145d72622772b920f60195e80942058984259cPhilip Milne            // being preserved and other vertices fall outside this range. Measure the distance
18484a145d72622772b920f60195e80942058984259cPhilip Milne            // between vertices 0 and N, assuming that locations[0] = 0.
18494a145d72622772b920f60195e80942058984259cPhilip Milne            return locations[getCount()];
1850aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
1851aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
185248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void setParentConstraints(int min, int max) {
185348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            parentMin.value = min;
185448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            parentMax.value = -max;
185548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            locationsValid = false;
18563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
185848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private int getMeasure(int min, int max) {
185948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            setParentConstraints(min, max);
186048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return size(getLocations());
186148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
1862aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1863f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int getMeasure(int measureSpec) {
186448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int mode = MeasureSpec.getMode(measureSpec);
186548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int size = MeasureSpec.getSize(measureSpec);
186648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            switch (mode) {
186748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                case MeasureSpec.UNSPECIFIED: {
186893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                    return getMeasure(0, MAX_SIZE);
186948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
187048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                case MeasureSpec.EXACTLY: {
187148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return getMeasure(size, size);
187248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
187348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                case MeasureSpec.AT_MOST: {
187448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return getMeasure(0, size);
187548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
187648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                default: {
187748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    assert false;
187848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return 0;
187948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
18803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
188148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
1882aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1883f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void layout(int size) {
188448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            setParentConstraints(size, size);
188548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            getLocations();
18863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
18873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1888f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void invalidateStructure() {
18894a145d72622772b920f60195e80942058984259cPhilip Milne            maxIndex = UNDEFINED;
1890aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
18913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            groupBounds = null;
189248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            forwardLinks = null;
189348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            backwardLinks = null;
189448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1895aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            leadingMargins = null;
1896aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            trailingMargins = null;
1897c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne            arcs = null;
189848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1899aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            locations = null;
19003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19019505480ee37494a33e12565db4febfb18b6d7494Philip Milne            originalMeasurements = null;
19029505480ee37494a33e12565db4febfb18b6d7494Philip Milne            deltas = null;
19039505480ee37494a33e12565db4febfb18b6d7494Philip Milne            hasWeightsValid = false;
19049505480ee37494a33e12565db4febfb18b6d7494Philip Milne
19053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            invalidateValues();
19063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1908f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void invalidateValues() {
19093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            groupBoundsValid = false;
191048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            forwardLinksValid = false;
191148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            backwardLinksValid = false;
191248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1913aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            leadingMarginsValid = false;
1914aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            trailingMarginsValid = false;
191548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            arcsValid = false;
191648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
191748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            locationsValid = false;
19183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
19203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
19223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Layout information associated with each of the children of a GridLayout.
19233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
19243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * GridLayout supports both row and column spanning and arbitrary forms of alignment within
19253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * each cell group. The fundamental parameters associated with each cell group are
19263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * gathered into their vertical and horizontal components and stored
192793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * in the {@link #rowSpec} and {@link #columnSpec} layout parameters.
19286216e87fe8ad3273855233965b34049d22763e94Philip Milne     * {@link GridLayout.Spec Specs} are immutable structures
1929b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne     * and may be shared between the layout parameters of different children.
19303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
193193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * The row and column specs contain the leading and trailing indices along each axis
1932aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * and together specify the four grid indices that delimit the cells of this cell group.
19333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
193493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * The  alignment properties of the row and column specs together specify
19353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * both aspects of alignment within the cell group. It is also possible to specify a child's
19363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
19373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * method.
193887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * <p>
193987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * The weight property is also included in Spec and specifies the proportion of any
19409505480ee37494a33e12565db4febfb18b6d7494Philip Milne     * excess space that is due to the associated view.
1941f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1942f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * <h4>WRAP_CONTENT and MATCH_PARENT</h4>
1943f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1944f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * Because the default values of the {@link #width} and {@link #height}
1945f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * properties are both {@link #WRAP_CONTENT}, this value never needs to be explicitly
1946f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * declared in the layout parameters of GridLayout's children. In addition,
1947f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * GridLayout does not distinguish the special size value {@link #MATCH_PARENT} from
1948f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * {@link #WRAP_CONTENT}. A component's ability to expand to the size of the parent is
1949f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * instead controlled by the principle of <em>flexibility</em>,
1950f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * as discussed in {@link GridLayout}.
1951f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1952f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * <h4>Summary</h4>
1953f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1954f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * You should not need to use either of the special size values:
1955f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * {@code WRAP_CONTENT} or {@code MATCH_PARENT} when configuring the children of
1956f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * a GridLayout.
19573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
19583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <h4>Default values</h4>
19593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
19603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <ul>
19613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #width} = {@link #WRAP_CONTENT}</li>
19623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #height} = {@link #WRAP_CONTENT}</li>
19633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #topMargin} = 0 when
19643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
19657fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
19663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
19673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #leftMargin} = 0 when
19683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
19697fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
19703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
19713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #bottomMargin} = 0 when
19723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
19737fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
19743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
19753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #rightMargin} = 0 when
19763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
19777fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
19783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
1979f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li>
1980f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li>
1981f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li>
198287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *     <li>{@link #rowSpec}<code>.weight</code> = 0 </li>
1983f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li>
1984f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li>
19856216e87fe8ad3273855233965b34049d22763e94Philip Milne     *     <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li>
198687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *     <li>{@link #columnSpec}<code>.weight</code> = 0 </li>
19873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * </ul>
19883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
1989f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * See {@link GridLayout} for a more complete description of the conventions
1990f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * used by GridLayout in the interpretation of the properties of this class.
1991f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
19923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_row
19933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan
199487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_rowWeight
19953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_column
19963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan
199787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_columnWeight
19983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
19993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
20003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static class LayoutParams extends MarginLayoutParams {
20013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Default values
20033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_WIDTH = WRAP_CONTENT;
20053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_HEIGHT = WRAP_CONTENT;
20063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_MARGIN = UNDEFINED;
20073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_ROW = UNDEFINED;
20083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_COLUMN = UNDEFINED;
2009f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne        private static final Interval DEFAULT_SPAN = new Interval(UNDEFINED, UNDEFINED + 1);
20103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_SPAN_SIZE = DEFAULT_SPAN.size();
20113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // TypedArray indices
20133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2014b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int MARGIN = R.styleable.ViewGroup_MarginLayout_layout_margin;
2015b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int LEFT_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginLeft;
2016b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int TOP_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginTop;
2017b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int RIGHT_MARGIN =
2018b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne                R.styleable.ViewGroup_MarginLayout_layout_marginRight;
20193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int BOTTOM_MARGIN =
2020b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne                R.styleable.ViewGroup_MarginLayout_layout_marginBottom;
2021b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
2022b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
202387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight;
20245d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
2025b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int ROW = R.styleable.GridLayout_Layout_layout_row;
2026b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan;
202787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        private static final int ROW_WEIGHT = R.styleable.GridLayout_Layout_layout_rowWeight;
20285d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
2029b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity;
20303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Instance variables
20323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
2034f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne         * The spec that defines the vertical characteristics of the cell group
20353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * described by these layout parameters.
2036d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * If an assignment is made to this field after a measurement or layout operation
2037d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * has already taken place, a call to
2038d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
2039d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * must be made to notify GridLayout of the change. GridLayout is normally able
2040d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * to detect when code fails to observe this rule, issue a warning and take steps to
2041d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * compensate for the omission. This facility is implemented on a best effort basis
2042d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * and should not be relied upon in production code - so it is best to include the above
2043d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * calls to remove the warnings as soon as it is practical.
20443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
2045f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public Spec rowSpec = Spec.UNDEFINED;
2046f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
20473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
2048f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne         * The spec that defines the horizontal characteristics of the cell group
20493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * described by these layout parameters.
2050d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * If an assignment is made to this field after a measurement or layout operation
2051d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * has already taken place, a call to
2052d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
2053d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * must be made to notify GridLayout of the change. GridLayout is normally able
2054d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * to detect when code fails to observe this rule, issue a warning and take steps to
2055d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * compensate for the omission. This facility is implemented on a best effort basis
2056d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * and should not be relied upon in production code - so it is best to include the above
2057d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * calls to remove the warnings as soon as it is practical.
20583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
2059f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public Spec columnSpec = Spec.UNDEFINED;
20603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Constructors
20623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private LayoutParams(
20643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int width, int height,
20653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int left, int top, int right, int bottom,
206693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec rowSpec, Spec columnSpec) {
20673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            super(width, height);
20683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            setMargins(left, top, right, bottom);
206993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            this.rowSpec = rowSpec;
207093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            this.columnSpec = columnSpec;
20713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
207493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * Constructs a new LayoutParams instance for this <code>rowSpec</code>
207593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * and <code>columnSpec</code>. All other fields are initialized with
20763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * default values as defined in {@link LayoutParams}.
20773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
207893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * @param rowSpec    the rowSpec
207993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * @param columnSpec the columnSpec
20803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
208193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        public LayoutParams(Spec rowSpec, Spec columnSpec) {
20823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
20833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
208493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                    rowSpec, columnSpec);
20853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
20883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
20893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
20903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams() {
2091f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this(Spec.UNDEFINED, Spec.UNDEFINED);
20923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Copying constructors
20953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
20973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * {@inheritDoc}
20983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
20993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams(ViewGroup.LayoutParams params) {
21003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            super(params);
21013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
21043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * {@inheritDoc}
21053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
21063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams(MarginLayoutParams params) {
21073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            super(params);
21083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
21110a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette         * Copy constructor. Clones the width, height, margin values, row spec,
21120a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette         * and column spec of the source.
21130a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette         *
21140a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette         * @param source The layout params to copy from.
21153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
21160a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette        public LayoutParams(LayoutParams source) {
21170a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette            super(source);
21180a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette
21190a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette            this.rowSpec = source.rowSpec;
21200a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette            this.columnSpec = source.columnSpec;
21213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // AttributeSet constructors
21243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
21263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * {@inheritDoc}
21273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
21283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Values not defined in the attribute set take the default values
21293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * defined in {@link LayoutParams}.
21303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
21313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams(Context context, AttributeSet attrs) {
21325125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            super(context, attrs);
21335125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            reInitSuper(context, attrs);
21345125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            init(context, attrs);
21353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Implementation
21383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Reinitialise the margins using a different default policy than MarginLayoutParams.
21403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Here we use the value UNDEFINED (as distinct from zero) to represent the undefined state
21413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // so that a layout manager default can be accessed post set up. We need this as, at the
21423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // point of installation, we do not know how many rows/cols there are and therefore
21433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // which elements are positioned next to the container's trailing edges. We need to
21443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // know this as margins around the container's boundary should have different
21453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // defaults to those between peers.
21463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // This method could be parametrized and moved into MarginLayout.
21483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private void reInitSuper(Context context, AttributeSet attrs) {
2149b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne            TypedArray a =
2150b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne                    context.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
21513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            try {
21523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN);
21533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.leftMargin = a.getDimensionPixelSize(LEFT_MARGIN, margin);
21553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.topMargin = a.getDimensionPixelSize(TOP_MARGIN, margin);
21563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.rightMargin = a.getDimensionPixelSize(RIGHT_MARGIN, margin);
21573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.bottomMargin = a.getDimensionPixelSize(BOTTOM_MARGIN, margin);
21583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            } finally {
21593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                a.recycle();
21603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
21613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21635125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        private void init(Context context, AttributeSet attrs) {
2164b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout);
21653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            try {
21665125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                int gravity = a.getInt(GRAVITY, Gravity.NO_GRAVITY);
21673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21681e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne                int column = a.getInt(COLUMN, DEFAULT_COLUMN);
21695125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                int colSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
217087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne                float colWeight = a.getFloat(COLUMN_WEIGHT, Spec.DEFAULT_WEIGHT);
217187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne                this.columnSpec = spec(column, colSpan, getAlignment(gravity, true), colWeight);
21723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21731e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne                int row = a.getInt(ROW, DEFAULT_ROW);
21741e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne                int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
217587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne                float rowWeight = a.getFloat(ROW_WEIGHT, Spec.DEFAULT_WEIGHT);
217687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne                this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false), rowWeight);
21773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            } finally {
21783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                a.recycle();
21793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
21803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
21837fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}.
21846216e87fe8ad3273855233965b34049d22763e94Philip Milne         * See {@link Gravity}.
21853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
21867fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * @param gravity the new gravity value
21873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
21883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
21893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
21903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public void setGravity(int gravity) {
21915125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            rowSpec = rowSpec.copyWriteAlignment(getAlignment(gravity, false));
21925125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            columnSpec = columnSpec.copyWriteAlignment(getAlignment(gravity, true));
21933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
21963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        protected void setBaseAttributes(TypedArray attributes, int widthAttr, int heightAttr) {
21973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.width = attributes.getLayoutDimension(widthAttr, DEFAULT_WIDTH);
21983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT);
21993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2201f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final void setRowSpecSpan(Interval span) {
220293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            rowSpec = rowSpec.copyWriteSpan(span);
22033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2205f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final void setColumnSpecSpan(Interval span) {
220693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            columnSpec = columnSpec.copyWriteSpan(span);
22073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
2208d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
2209d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        @Override
2210d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        public boolean equals(Object o) {
2211d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (this == o) return true;
2212d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (o == null || getClass() != o.getClass()) return false;
2213d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
2214d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            LayoutParams that = (LayoutParams) o;
2215d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
2216d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (!columnSpec.equals(that.columnSpec)) return false;
2217d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (!rowSpec.equals(that.rowSpec)) return false;
2218d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
2219d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            return true;
2220d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        }
2221d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
2222d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        @Override
2223d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        public int hashCode() {
2224d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            int result = rowSpec.hashCode();
2225d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            result = 31 * result + columnSpec.hashCode();
2226d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            return result;
2227d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        }
22283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
22293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2230aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
2231aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs.
2232aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles.
2233aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
2234f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class Arc {
22353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final Interval span;
2236aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public final MutableInt value;
223748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean valid = true;
22383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2239aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public Arc(Interval span, MutableInt value) {
22403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.span = span;
22413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.value = value;
22423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
22443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
22453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public String toString() {
224648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return span + " " + (!valid ? "+>" : "->") + " " + value;
22473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
22493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
22503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // A mutable Integer - used to avoid heap allocation during the layout operation
22513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2252f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class MutableInt {
22533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int value;
22543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2255f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public MutableInt() {
22563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            reset();
22573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2259f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public MutableInt(int value) {
22603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.value = value;
22613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2263f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void reset() {
22643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            value = Integer.MIN_VALUE;
22653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
226648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
226748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        @Override
226848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public String toString() {
226948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return Integer.toString(value);
227048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
227148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    }
227248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
2273f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class Assoc<K, V> extends ArrayList<Pair<K, V>> {
227448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private final Class<K> keyType;
227548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private final Class<V> valueType;
227648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
227748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private Assoc(Class<K> keyType, Class<V> valueType) {
227848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            this.keyType = keyType;
227948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            this.valueType = valueType;
228048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
228148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
2282f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) {
228348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return new Assoc<K, V>(keyType, valueType);
228448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
228548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
228648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public void put(K key, V value) {
228748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            add(Pair.create(key, value));
228848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
228948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
229048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        @SuppressWarnings(value = "unchecked")
229148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public PackedMap<K, V> pack() {
229248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int N = size();
229348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            K[] keys = (K[]) Array.newInstance(keyType, N);
229448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            V[] values = (V[]) Array.newInstance(valueType, N);
229548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0; i < N; i++) {
229648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                keys[i] = get(i).first;
229748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                values[i] = get(i).second;
229848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
229948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return new PackedMap<K, V>(keys, values);
230048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
23013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
23023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2303aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
2304aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    This data structure is used in place of a Map where we have an index that refers to the order
2305aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    in which each key/value pairs were added to the map. In this case we store keys and values
2306aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    in arrays of a length that is equal to the number of unique keys. We also maintain an
2307aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    array of indexes from insertion order to the compacted arrays of keys and values.
2308aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
2309aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    Note that behavior differs from that of a LinkedHashMap in that repeated entries
2310aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    *do* get added multiples times. So the length of index is equals to the number of
2311aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    items added.
2312aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
2313aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    This is useful in the GridLayout class where we can rely on the order of children not
2314aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    changing during layout - to use integer-based lookup for our internal structures
2315aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    rather than using (and storing) an implementation of Map<Key, ?>.
2316aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
23173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @SuppressWarnings(value = "unchecked")
2318f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class PackedMap<K, V> {
23193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final int[] index;
23203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final K[] keys;
23213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final V[] values;
23223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private PackedMap(K[] keys, V[] values) {
23243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.index = createIndex(keys);
23253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2326aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            this.keys = compact(keys, index);
2327aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            this.values = compact(values, index);
23283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2330f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public V getValue(int i) {
23313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return values[index[i]];
23323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static <K> int[] createIndex(K[] keys) {
23353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int size = keys.length;
23363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int[] result = new int[size];
23373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Map<K, Integer> keyToIndex = new HashMap<K, Integer>();
23393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < size; i++) {
23403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                K key = keys[i];
23413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                Integer index = keyToIndex.get(key);
23423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                if (index == null) {
23433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    index = keyToIndex.size();
23443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    keyToIndex.put(key, index);
23453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
23463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                result[i] = index;
23473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
23483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
23493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2351aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        /*
2352aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Create a compact array of keys or values using the supplied index.
2353aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne         */
2354aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private static <K> K[] compact(K[] a, int[] index) {
2355aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            int size = a.length;
2356aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            Class<?> componentType = a.getClass().getComponentType();
235751f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne            K[] result = (K[]) Array.newInstance(componentType, max2(index, -1) + 1);
23583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            // this overwrite duplicates, retaining the last equivalent entry
23603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < size; i++) {
2361aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                result[index[i]] = a[i];
23623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
23633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
23643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
23663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2367aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
236893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    For each group (with a given alignment) we need to store the amount of space required
23697fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne    before the alignment point and the amount of space required after it. One side of this
237047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    calculation is always 0 for START and END alignments but we don't make use of this.
2371aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
2372aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    simple optimisations are possible.
2373aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
2374aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    The general algorithm therefore is to create a Map (actually a PackedMap) from
237593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    group to Bounds and to loop through all Views in the group taking the maximum
2376aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    of the values for each View.
2377aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    */
2378f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static class Bounds {
23797fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne        public int before;
23807fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne        public int after;
23815125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        public int flexibility; // we're flexible iff all included specs are flexible
23823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private Bounds() {
23843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            reset();
23853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2387a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        protected void reset() {
23887fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            before = Integer.MIN_VALUE;
23897fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            after = Integer.MIN_VALUE;
23905125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            flexibility = CAN_STRETCH; // from the above, we're flexible when empty
23913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2393a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        protected void include(int before, int after) {
23947fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            this.before = max(this.before, before);
23957fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            this.after = max(this.after, after);
23963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
239848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        protected int size(boolean min) {
23995d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            if (!min) {
24005125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                if (canStretch(flexibility)) {
24015d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne                    return MAX_SIZE;
24025d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne                }
240348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
24044885f2f773915a48d0e2f67bc604b081327372a0Philip Milne            return before + after;
24053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24071557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne        protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
24087a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne            return before - a.getAlignmentValue(c, size, gl.getLayoutMode());
240948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
241048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
24119505480ee37494a33e12565db4febfb18b6d7494Philip Milne        protected final void include(GridLayout gl, View c, Spec spec, Axis axis, int size) {
24125125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            this.flexibility &= spec.getFlexibility();
24131557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            boolean horizontal = axis.horizontal;
24146dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar            Alignment alignment = spec.getAbsoluteAlignment(axis.horizontal);
24154c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            // todo test this works correctly when the returned value is UNDEFINED
24167a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne            int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode());
241748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(before, size - before);
2418a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
2419a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
24203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
24213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public String toString() {
24223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return "Bounds{" +
24237fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne                    "before=" + before +
24247fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne                    ", after=" + after +
24253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    '}';
24263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
24283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
24303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * An Interval represents a contiguous range of values that lie between
24313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * the interval's {@link #min} and {@link #max} values.
24323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
24333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Intervals are immutable so may be passed as values and used as keys in hash tables.
24343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * It is not necessary to have multiple instances of Intervals which have the same
24353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * {@link #min} and {@link #max} values.
24363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
24377fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * Intervals are often written as {@code [min, max]} and represent the set of values
24387fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * {@code x} such that {@code min <= x < max}.
24393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2440f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class Interval {
24413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
24423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * The minimum value.
24433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
24443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final int min;
2445aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
24463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
24473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * The maximum value.
24483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
24493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final int max;
24503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
24527fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * Construct a new Interval, {@code interval}, where:
24533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * <ul>
24547fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         *     <li> {@code interval.min = min} </li>
24557fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         *     <li> {@code interval.max = max} </li>
24563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * </ul>
24573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
24583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @param min the minimum value.
24593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @param max the maximum value.
24603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
24613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public Interval(int min, int max) {
24623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.min = min;
24633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.max = max;
24643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2466f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        int size() {
24673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return max - min;
24683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2470f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        Interval inverse() {
24713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return new Interval(max, min);
24723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
24757fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * Returns {@code true} if the {@link #getClass class},
24767fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * {@link #min} and {@link #max} properties of this Interval and the
24777fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * supplied parameter are pairwise equal; {@code false} otherwise.
24783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
24797fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * @param that the object to compare this interval with
24803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
24813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @return {@code true} if the specified object is equal to this
24827fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         *         {@code Interval}, {@code false} otherwise.
24833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
24843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
24853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean equals(Object that) {
24863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (this == that) {
24873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return true;
24883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
24893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (that == null || getClass() != that.getClass()) {
24903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
24913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
24923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Interval interval = (Interval) that;
24943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (max != interval.max) {
24963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
24973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
24984c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            //noinspection RedundantIfStatement
24993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (min != interval.min) {
25003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
25013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
25023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
25033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return true;
25043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
25053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
25063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
25073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int hashCode() {
25083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int result = min;
25093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            result = 31 * result + max;
25103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
25113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
25123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
25133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
25143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public String toString() {
25153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return "[" + min + ", " + max + "]";
25163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
25173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
25183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2519899d5922870c78e0e663bc5661849eb468afc984Philip Milne    /**
2520899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * A Spec defines the horizontal or vertical characteristics of a group of
25214a145d72622772b920f60195e80942058984259cPhilip Milne     * cells. Each spec. defines the <em>grid indices</em> and <em>alignment</em>
25224a145d72622772b920f60195e80942058984259cPhilip Milne     * along the appropriate axis.
2523899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * <p>
2524899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The <em>grid indices</em> are the leading and trailing edges of this cell group.
2525899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * See {@link GridLayout} for a description of the conventions used by GridLayout
2526899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * for grid indices.
2527899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * <p>
2528899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The <em>alignment</em> property specifies how cells should be aligned in this group.
2529899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * For row groups, this specifies the vertical alignment.
2530899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * For column groups, this specifies the horizontal alignment.
25314a145d72622772b920f60195e80942058984259cPhilip Milne     * <p>
25324a145d72622772b920f60195e80942058984259cPhilip Milne     * Use the following static methods to create specs:
25334a145d72622772b920f60195e80942058984259cPhilip Milne     * <ul>
25344a145d72622772b920f60195e80942058984259cPhilip Milne     *   <li>{@link #spec(int)}</li>
25354a145d72622772b920f60195e80942058984259cPhilip Milne     *   <li>{@link #spec(int, int)}</li>
25364a145d72622772b920f60195e80942058984259cPhilip Milne     *   <li>{@link #spec(int, Alignment)}</li>
25374a145d72622772b920f60195e80942058984259cPhilip Milne     *   <li>{@link #spec(int, int, Alignment)}</li>
253887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *   <li>{@link #spec(int, float)}</li>
253987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *   <li>{@link #spec(int, int, float)}</li>
254087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *   <li>{@link #spec(int, Alignment, float)}</li>
254187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *   <li>{@link #spec(int, int, Alignment, float)}</li>
25424a145d72622772b920f60195e80942058984259cPhilip Milne     * </ul>
25434a145d72622772b920f60195e80942058984259cPhilip Milne     *
2544899d5922870c78e0e663bc5661849eb468afc984Philip Milne     */
254593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    public static class Spec {
2546f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        static final Spec UNDEFINED = spec(GridLayout.UNDEFINED);
254787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        static final float DEFAULT_WEIGHT = 0;
2548f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
2549f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final boolean startDefined;
255048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        final Interval span;
255193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        final Alignment alignment;
255287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        final float weight;
25533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
255487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        private Spec(boolean startDefined, Interval span, Alignment alignment, float weight) {
2555f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.startDefined = startDefined;
25565d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            this.span = span;
25575d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            this.alignment = alignment;
255887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne            this.weight = weight;
25595d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne        }
25605d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
256187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        private Spec(boolean startDefined, int start, int size, Alignment alignment, float weight) {
256287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne            this(startDefined, new Interval(start, start + size), alignment, weight);
25633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
25643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
25656dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar        public Alignment getAbsoluteAlignment(boolean horizontal) {
25666dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar            if (alignment != UNDEFINED_ALIGNMENT) {
25676dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                return alignment;
25686dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar            }
25696dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar            if (weight == 0f) {
25706dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar                return horizontal ? START : BASELINE;
25716dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar            }
25726dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar            return FILL;
25736dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar        }
25746dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar
2575f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final Spec copyWriteSpan(Interval span) {
257687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne            return new Spec(startDefined, span, alignment, weight);
25773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
25783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2579f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final Spec copyWriteAlignment(Alignment alignment) {
258087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne            return new Spec(startDefined, span, alignment, weight);
25815125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
25825125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
2583f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final int getFlexibility() {
258487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne            return (alignment == UNDEFINED_ALIGNMENT && weight == 0) ? INFLEXIBLE : CAN_STRETCH;
25853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
25863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
25873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
258893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * Returns {@code true} if the {@code class}, {@code alignment} and {@code span}
258993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * properties of this Spec and the supplied parameter are pairwise equal,
25907fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * {@code false} otherwise.
25913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
259293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * @param that the object to compare this spec with
25933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
25943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @return {@code true} if the specified object is equal to this
259593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         *         {@code Spec}; {@code false} otherwise
25963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
25973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
25983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean equals(Object that) {
25993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (this == that) {
26003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return true;
26013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
26023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (that == null || getClass() != that.getClass()) {
26033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
26043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
26053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
260693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec spec = (Spec) that;
26073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
260893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            if (!alignment.equals(spec.alignment)) {
26093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
26103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
26114c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            //noinspection RedundantIfStatement
261293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            if (!span.equals(spec.span)) {
26133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
26143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
26153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
26163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return true;
26173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
26183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
26193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
26203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int hashCode() {
26213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int result = span.hashCode();
26223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            result = 31 * result + alignment.hashCode();
26233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
26243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
26253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
26263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
26273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
262893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * Return a Spec, {@code spec}, where:
262993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * <ul>
263093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.span = [start, start + size]} </li>
263193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.alignment = alignment} </li>
263287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *     <li> {@code spec.weight = weight} </li>
263393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * </ul>
26347b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * <p>
26357b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * To leave the start index undefined, use the value {@link #UNDEFINED}.
263693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *
263793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param start     the start
263893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param size      the size
263993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param alignment the alignment
264087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param weight    the weight
264187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     */
264287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    public static Spec spec(int start, int size, Alignment alignment, float weight) {
264387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        return new Spec(start != UNDEFINED, start, size, alignment, weight);
264487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    }
264587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne
264687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    /**
264787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * Equivalent to: {@code spec(start, 1, alignment, weight)}.
264887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *
264987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param start     the start
265087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param alignment the alignment
265187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param weight    the weight
265287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     */
265387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    public static Spec spec(int start, Alignment alignment, float weight) {
265487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        return spec(start, 1, alignment, weight);
265587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    }
265687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne
265787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    /**
265887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * Equivalent to: {@code spec(start, 1, default_alignment, weight)} -
265987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * where {@code default_alignment} is specified in
266087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * {@link android.widget.GridLayout.LayoutParams}.
266187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *
266287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param start  the start
266387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param size   the size
266487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param weight the weight
266587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     */
266687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    public static Spec spec(int start, int size, float weight) {
266787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        return spec(start, size, UNDEFINED_ALIGNMENT, weight);
266887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    }
266987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne
267087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    /**
267187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * Equivalent to: {@code spec(start, 1, weight)}.
267287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *
267387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param start  the start
267487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param weight the weight
267587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     */
267687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    public static Spec spec(int start, float weight) {
267787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        return spec(start, 1, weight);
267887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    }
267987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne
268087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne    /**
268187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * Equivalent to: {@code spec(start, size, alignment, 0f)}.
268287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     *
268387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param start     the start
268487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param size      the size
268587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne     * @param alignment the alignment
268693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     */
268793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    public static Spec spec(int start, int size, Alignment alignment) {
268887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne        return spec(start, size, alignment, Spec.DEFAULT_WEIGHT);
268993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    }
269093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne
269193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    /**
269293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * Return a Spec, {@code spec}, where:
269393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * <ul>
269493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.span = [start, start + 1]} </li>
269593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.alignment = alignment} </li>
269693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * </ul>
26977b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * <p>
26987b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * To leave the start index undefined, use the value {@link #UNDEFINED}.
269993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *
270093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param start     the start index
270193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param alignment the alignment
27027b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     *
27037b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * @see #spec(int, int, Alignment)
270493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     */
270593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    public static Spec spec(int start, Alignment alignment) {
270693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        return spec(start, 1, alignment);
270793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    }
270893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne
270993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    /**
27105125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * Return a Spec, {@code spec}, where:
27115125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * <ul>
27125125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *     <li> {@code spec.span = [start, start + size]} </li>
27135125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * </ul>
27147b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * <p>
27157b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * To leave the start index undefined, use the value {@link #UNDEFINED}.
27165125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *
27175125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * @param start     the start
27185125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * @param size      the size
27197b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     *
27207b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * @see #spec(int, Alignment)
27215125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     */
27225125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    public static Spec spec(int start, int size) {
27235125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return spec(start, size, UNDEFINED_ALIGNMENT);
27245125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
27255125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
27265125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    /**
27275125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * Return a Spec, {@code spec}, where:
27285125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * <ul>
27295125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *     <li> {@code spec.span = [start, start + 1]} </li>
27305125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * </ul>
27317b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * <p>
27327b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * To leave the start index undefined, use the value {@link #UNDEFINED}.
27335125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *
27345125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * @param start     the start index
27357b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     *
27367b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * @see #spec(int, int)
27375125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     */
27385125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    public static Spec spec(int start) {
27395125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return spec(start, 1);
27405125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
27415125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
27425125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    /**
27433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Alignments specify where a view should be placed within a cell group and
27443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * what size it should be.
27453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
274693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec}
274793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an
274893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * {@code alignment}. Overall placement of the view in the cell
27493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * group is specified by the two alignments which act along each axis independently.
27503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
2751a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne     *  The GridLayout class defines the most common alignments used in general layout:
27526216e87fe8ad3273855233965b34049d22763e94Philip Milne     * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #START},
27536216e87fe8ad3273855233965b34049d22763e94Philip Milne     * {@link #END}, {@link #CENTER}, {@link #BASELINE} and {@link #FILL}.
2754a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne     */
2755a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne    /*
2756c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne     * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)},
27573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * to return the appropriate value for the type of alignment being defined.
27583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * The enclosing algorithms position the children
27591e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * so that the locations defined by the alignment values
27603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * are the same for all of the views in a group.
27613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
27623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2763c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    public static abstract class Alignment {
276448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        Alignment() {
2765a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
2766a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
27676216e87fe8ad3273855233965b34049d22763e94Philip Milne        abstract int getGravityOffset(View view, int cellDelta);
27686216e87fe8ad3273855233965b34049d22763e94Philip Milne
27693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
27703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Returns an alignment value. In the case of vertical alignments the value
27713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * returned should indicate the distance from the top of the view to the
27723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * alignment location.
27733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * For horizontal alignments measurement is made from the left edge of the component.
27743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
2775c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param view              the view to which this alignment should be applied
2776c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param viewSize          the measured size of the view
27777a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne         * @param mode              the basis of alignment: CLIP or OPTICAL
2778b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne         * @return the alignment value
27793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
27807a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        abstract int getAlignmentValue(View view, int viewSize, int mode);
27813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
27823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
27833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Returns the size of the view specified by this alignment.
27843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * In the case of vertical alignments this method should return a height; for
27853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * horizontal alignments this method should return the width.
2786c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * <p>
2787c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * The default implementation returns {@code viewSize}.
2788c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         *
2789c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param view              the view to which this alignment should be applied
2790c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param viewSize          the measured size of the view
2791c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param cellSize          the size of the cell into which this view will be placed
2792b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne         * @return the aligned size
27933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
27946216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getSizeInCell(View view, int viewSize, int cellSize) {
27953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return viewSize;
27963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
2797a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
279848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        Bounds getBounds() {
2799a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne            return new Bounds();
2800a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
28013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
28023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2803f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final Alignment UNDEFINED_ALIGNMENT = new Alignment() {
280447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
28056216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
28066216e87fe8ad3273855233965b34049d22763e94Philip Milne            return UNDEFINED;
28076216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
28086216e87fe8ad3273855233965b34049d22763e94Philip Milne
28096216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
28107a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
28115125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            return UNDEFINED;
28125125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
28135125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    };
28145125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
281547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    /**
281647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * Indicates that a view should be aligned with the <em>start</em>
281747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * edges of the other views in its cell group.
281847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     */
2819c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    private static final Alignment LEADING = new Alignment() {
282047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
28216216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
28226216e87fe8ad3273855233965b34049d22763e94Philip Milne            return 0;
28236216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
28246216e87fe8ad3273855233965b34049d22763e94Philip Milne
28256216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
28267a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
28273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return 0;
28283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
28293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
28303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
283147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    /**
283247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * Indicates that a view should be aligned with the <em>end</em>
283347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * edges of the other views in its cell group.
283447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     */
2835c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    private static final Alignment TRAILING = new Alignment() {
283647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
28376216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
28386216e87fe8ad3273855233965b34049d22763e94Philip Milne            return cellDelta;
28396216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
28406216e87fe8ad3273855233965b34049d22763e94Philip Milne
28416216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
28427a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
28433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return viewSize;
28443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
28453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
28463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
28473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
28483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>top</em>
28493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
28503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
28513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment TOP = LEADING;
28523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
28533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
28543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>bottom</em>
28553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
28563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
28573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment BOTTOM = TRAILING;
28583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
28593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
286047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * Indicates that a view should be aligned with the <em>start</em>
28613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
28623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
286347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    public static final Alignment START = LEADING;
286447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio
286547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    /**
286647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * Indicates that a view should be aligned with the <em>end</em>
286747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * edges of the other views in its cell group.
286847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     */
286947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    public static final Alignment END = TRAILING;
287047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio
28716216e87fe8ad3273855233965b34049d22763e94Philip Milne    private static Alignment createSwitchingAlignment(final Alignment ltr, final Alignment rtl) {
287247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        return new Alignment() {
287347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio            @Override
28746216e87fe8ad3273855233965b34049d22763e94Philip Milne            int getGravityOffset(View view, int cellDelta) {
28756216e87fe8ad3273855233965b34049d22763e94Philip Milne                return (!view.isLayoutRtl() ? ltr : rtl).getGravityOffset(view, cellDelta);
28766216e87fe8ad3273855233965b34049d22763e94Philip Milne            }
28776216e87fe8ad3273855233965b34049d22763e94Philip Milne
28786216e87fe8ad3273855233965b34049d22763e94Philip Milne            @Override
28797a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne            public int getAlignmentValue(View view, int viewSize, int mode) {
28807a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne                return (!view.isLayoutRtl() ? ltr : rtl).getAlignmentValue(view, viewSize, mode);
288147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio            }
288247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        };
288347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    }
28843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
28853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
28863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>left</em>
28873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
28883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
28896216e87fe8ad3273855233965b34049d22763e94Philip Milne    public static final Alignment LEFT = createSwitchingAlignment(START, END);
289047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio
289147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    /**
289247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * Indicates that a view should be aligned with the <em>right</em>
289347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * edges of the other views in its cell group.
289447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     */
28956216e87fe8ad3273855233965b34049d22763e94Philip Milne    public static final Alignment RIGHT = createSwitchingAlignment(END, START);
28963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
28973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
28983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be <em>centered</em> with the other views in its cell group.
289993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link
290093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * LayoutParams#columnSpec columnSpecs}.
29013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2902c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    public static final Alignment CENTER = new Alignment() {
290347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
29046216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
29056216e87fe8ad3273855233965b34049d22763e94Philip Milne            return cellDelta >> 1;
29066216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
29076216e87fe8ad3273855233965b34049d22763e94Philip Milne
29086216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
29097a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
29103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return viewSize >> 1;
29113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
29123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
29133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
29143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
29153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>baselines</em>
29163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * of the other views in its cell group.
291793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}.
29183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
29193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see View#getBaseline()
29203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2921c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    public static final Alignment BASELINE = new Alignment() {
292247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
29236216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
29246216e87fe8ad3273855233965b34049d22763e94Philip Milne            return 0; // baseline gravity is top
29256216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
29266216e87fe8ad3273855233965b34049d22763e94Philip Milne
29276216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
29287a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
2929a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne            if (view.getVisibility() == GONE) {
2930a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne                return 0;
2931a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne            }
29323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int baseline = view.getBaseline();
29337b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne            return baseline == -1 ? UNDEFINED : baseline;
2934a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
2935a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2936a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        @Override
2937a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        public Bounds getBounds() {
2938a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne            return new Bounds() {
2939a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                /*
2940a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                In a baseline aligned row in which some components define a baseline
2941a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                and some don't, we need a third variable to properly account for all
2942a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                the sizes. This tracks the maximum size of all the components -
2943a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                including those that don't define a baseline.
2944a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                */
2945a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                private int size;
2946a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2947a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
2948a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                protected void reset() {
2949a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                    super.reset();
295048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    size = Integer.MIN_VALUE;
2951a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2952a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2953a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
2954a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                protected void include(int before, int after) {
2955a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                    super.include(before, after);
2956a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                    size = max(size, before + after);
2957a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2958a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2959a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
296048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                protected int size(boolean min) {
296148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return max(super.size(min), size);
2962a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2963a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2964a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
29651557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne                protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) {
29661557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne                    return max(0, super.getOffset(gl, c, a, size, hrz));
2967a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2968a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne            };
29693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
29703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
29713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
29723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
29733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should expanded to fit the boundaries of its cell group.
297493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and
297593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * {@link LayoutParams#columnSpec columnSpecs}.
29763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
29773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment FILL = new Alignment() {
297847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
29796216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
29806216e87fe8ad3273855233965b34049d22763e94Philip Milne            return 0;
29816216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
29826216e87fe8ad3273855233965b34049d22763e94Philip Milne
29836216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
29847a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
29853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return UNDEFINED;
29863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
29873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2988c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne        @Override
29896216e87fe8ad3273855233965b34049d22763e94Philip Milne        public int getSizeInCell(View view, int viewSize, int cellSize) {
29903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return cellSize;
29913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
29923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
299348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
2994f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static boolean canStretch(int flexibility) {
29955d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne        return (flexibility & CAN_STRETCH) != 0;
29965d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne    }
29975d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
29985125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    private static final int INFLEXIBLE = 0;
29994c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    private static final int CAN_STRETCH = 2;
3000452eec33d667f9e705b57e60948b070536fbc1b4Jim Miller}
3001