1e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet/*
2e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Copyright (C) 2011 The Android Open Source Project
3e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
4e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
5e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * you may not use this file except in compliance with the License.
6e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * You may obtain a copy of the License at
7e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
8e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
9e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
10e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software
11e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
12e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * See the License for the specific language governing permissions and
14e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * limitations under the License.
15e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */
16e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
17e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetpackage android.support.v7.widget;
18e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
19e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.content.Context;
20e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.content.res.TypedArray;
21e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.graphics.Canvas;
22e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.graphics.Paint;
23b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powellimport android.support.v4.view.GravityCompat;
24b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powellimport android.support.v4.view.ViewCompat;
25b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powellimport android.support.v4.view.ViewGroupCompat;
26e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.util.AttributeSet;
27e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.util.Log;
282c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglioimport android.util.LogPrinter;
29e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.util.Pair;
302c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglioimport android.util.Printer;
31e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.view.Gravity;
32e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.view.View;
33e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.view.ViewGroup;
34e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.widget.LinearLayout;
35e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
36e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.support.v7.gridlayout.R;
37e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
38e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.lang.reflect.Array;
39e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.util.ArrayList;
40e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.util.Arrays;
41e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.util.HashMap;
42e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.util.List;
43e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.util.Map;
44e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
45e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport static android.view.Gravity.*;
46e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport static android.view.View.MeasureSpec.EXACTLY;
47e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport static android.view.View.MeasureSpec.makeMeasureSpec;
48e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport static java.lang.Math.max;
49e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport static java.lang.Math.min;
50e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
51e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet/**
52e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * A layout that places its children in a rectangular <em>grid</em>.
53e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p>
54e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The grid is composed of a set of infinitely thin lines that separate the
55e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * viewing area into <em>cells</em>. Throughout the API, grid lines are referenced
56e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * by grid <em>indices</em>. A grid with {@code N} columns
57e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * has {@code N + 1} grid indices that run from {@code 0}
58e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * through {@code N} inclusive. Regardless of how GridLayout is
59e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * configured, grid index {@code 0} is fixed to the leading edge of the
60e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * container and grid index {@code N} is fixed to its trailing edge
61e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * (after padding is taken into account).
62e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
63e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>Row and Column Specs</h4>
64e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
65e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Children occupy one or more contiguous cells, as defined
66e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and
67e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters.
68e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Each spec defines the set of rows or columns that are to be
69e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * occupied; and how children should be aligned within the resulting group of cells.
70e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Although cells do not normally overlap in a GridLayout, GridLayout does
71e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * not prevent children being defined to occupy the same cell or group of cells.
72e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * In this case however, there is no guarantee that children will not themselves
73e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * overlap after the layout operation completes.
74e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
75e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>Default Cell Assignment</h4>
76e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
77e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * If a child does not specify the row and column indices of the cell it
78e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * wishes to occupy, GridLayout assigns cell locations automatically using its:
79e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setOrientation(int) orientation},
80e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setRowCount(int) rowCount} and
81e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setColumnCount(int) columnCount} properties.
82e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
83e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>Space</h4>
84e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
85e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Space between children may be specified either by using instances of the
86b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell * dedicated {@link android.support.v7.widget.Space} view or by setting the
87e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
88e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link ViewGroup.MarginLayoutParams#leftMargin leftMargin},
89e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link ViewGroup.MarginLayoutParams#topMargin topMargin},
90e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link ViewGroup.MarginLayoutParams#rightMargin rightMargin} and
91e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link ViewGroup.MarginLayoutParams#bottomMargin bottomMargin}
92e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
93e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * layout parameters. When the
94e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins}
95e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * property is set, default margins around children are automatically
96e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * allocated based on the prevailing UI style guide for the platform.
97e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Each of the margins so defined may be independently overridden by an assignment
98e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * to the appropriate layout parameter.
99e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Default values will generally produce a reasonable spacing between components
100e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * but values may change between different releases of the platform.
101e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
102e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>Excess Space Distribution</h4>
103e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
104e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * GridLayout's distribution of excess space accommodates the principle of weight.
105e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * In the event that no weights are specified, columns and rows are taken as
106e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * flexible if their views specify some form of alignment within their groups.
107e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p>
108e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * The flexibility of a view is therefore influenced by its alignment which is,
109e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * in turn, typically defined by setting the
110e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters.
111e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * If either a weight or alignment were defined along a given axis then the component
112e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * is taken as <em>flexible</em> in that direction. If no weight or alignment was set,
113e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * the component is instead assumed to be <em>inflexible</em>.
114e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p>
115e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Multiple components in the same row or column group are
116e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * considered to act in <em>parallel</em>. Such a
117e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * group is flexible only if <em>all</em> of the components
118e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * within it are flexible. Row and column groups that sit either side of a common boundary
119e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * are instead considered to act in <em>series</em>. The composite group made of these two
120e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * elements is flexible if <em>one</em> of its elements is flexible.
121e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p>
122e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * To make a column stretch, make sure all of the components inside it define a
123e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * weight or a gravity. To prevent a column from stretching, ensure that one of the components
124e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * in the column does not define a weight or a gravity.
125e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p>
126e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When the principle of flexibility does not provide complete disambiguation,
127e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em>
128e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * and <em>bottom</em> edges. To be more precise, GridLayout treats each of its layout
129e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * parameters as a constraint in the a set of variables that define the grid-lines along a
130e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * given axis. During layout, GridLayout solves the constraints so as to return the unique
131e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * solution to those constraints for which all variables are less-than-or-equal-to
132e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * the corresponding value in any other valid solution.
133e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
1342c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <h4>Interpretation of GONE</h4>
1352c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio *
1362c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * For layout purposes, GridLayout treats views whose visibility status is
1372c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * {@link View#GONE GONE}, as having zero width and height. This is subtly different from
1382c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * the policy of ignoring views that are marked as GONE outright. If, for example, a gone-marked
1392c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * view was alone in a column, that column would itself collapse to zero width if and only if
1402c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * no gravity was defined on the view. If gravity was defined, then the gone-marked
1412c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * view has no effect on the layout and the container should be laid out as if the view
142aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar * had never been added to it. GONE views are taken to have zero weight during excess space
143aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar * distribution.
144aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar * <p>
1452c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * These statements apply equally to rows as well as columns, and to groups of rows or columns.
1462c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio *
147aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar *
148e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p>
149e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * See {@link GridLayout.LayoutParams} for a full description of the
150e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * layout parameters used by GridLayout.
151e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *
152e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @attr ref android.R.styleable#GridLayout_orientation
153e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @attr ref android.R.styleable#GridLayout_rowCount
154e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @attr ref android.R.styleable#GridLayout_columnCount
155e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @attr ref android.R.styleable#GridLayout_useDefaultMargins
156e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
157e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
158e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */
159e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milnepublic class GridLayout extends ViewGroup {
160e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
161e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Public constants
162e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
163e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
164e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The horizontal orientation.
165e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
166e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
167e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
168e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
169e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The vertical orientation.
170e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
171e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final int VERTICAL = LinearLayout.VERTICAL;
172e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
173e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
174e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The constant used to indicate that a value is undefined.
175e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Fields can use this value to indicate that their values
176e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * have not yet been set. Similarly, methods can return this value
177e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * to indicate that there is no suitable value that the implementation
178e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * can return.
179e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The value used for the constant (currently {@link Integer#MIN_VALUE}) is
180e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * intended to avoid confusion between valid values whose sign may not be known.
181e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
182e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final int UNDEFINED = Integer.MIN_VALUE;
183e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
184e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
185e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * This constant is an {@link #setAlignmentMode(int) alignmentMode}.
186e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * When the {@code alignmentMode} is set to {@link #ALIGN_BOUNDS}, alignment
187e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * is made between the edges of each component's raw
188e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * view boundary: i.e. the area delimited by the component's:
189e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link android.view.View#getTop() top},
190e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link android.view.View#getLeft() left},
191e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link android.view.View#getBottom() bottom} and
192e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link android.view.View#getRight() right} properties.
193e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
194e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * For example, when {@code GridLayout} is in {@link #ALIGN_BOUNDS} mode,
195e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * children that belong to a row group that uses {@link #TOP} alignment will
196e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * all return the same value when their {@link android.view.View#getTop()}
197e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * method is called.
198e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
199e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #setAlignmentMode(int)
200e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
201e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final int ALIGN_BOUNDS = 0;
202e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
203e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
204e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * This constant is an {@link #setAlignmentMode(int) alignmentMode}.
205e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * When the {@code alignmentMode} is set to {@link #ALIGN_MARGINS},
206e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * the bounds of each view are extended outwards, according
207e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * to their margins, before the edges of the resulting rectangle are aligned.
208e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
209e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * For example, when {@code GridLayout} is in {@link #ALIGN_MARGINS} mode,
210e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * the quantity {@code top - layoutParams.topMargin} is the same for all children that
211e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * belong to a row group that uses {@link #TOP} alignment.
212e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
213e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #setAlignmentMode(int)
214e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
215e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final int ALIGN_MARGINS = 1;
216e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
217e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Misc constants
218e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
219e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    static final int MAX_SIZE = 100000;
220e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    static final int DEFAULT_CONTAINER_MARGIN = 0;
221e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    static final int UNINITIALIZED_HASH = 0;
2222c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    static final Printer LOG_PRINTER = new LogPrinter(Log.DEBUG, GridLayout.class.getName());
2232c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    static final Printer NO_PRINTER = new Printer() {
2242c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        @Override
2252c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        public void println(String x) {
2262c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        }
2272c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    };
228e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
229e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Defaults
230e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
231e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int DEFAULT_ORIENTATION = HORIZONTAL;
232e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int DEFAULT_COUNT = UNDEFINED;
233e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false;
234e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final boolean DEFAULT_ORDER_PRESERVED = true;
235e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
236e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
237e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // TypedArray indices
238e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
239e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int ORIENTATION = R.styleable.GridLayout_orientation;
240e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int ROW_COUNT = R.styleable.GridLayout_rowCount;
241e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount;
242e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins;
243e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode;
244e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved;
245e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved;
246e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
247e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Instance variables
248e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
249b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell    final Axis mHorizontalAxis = new Axis(true);
250b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell    final Axis mVerticalAxis = new Axis(false);
251b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell    int mOrientation = DEFAULT_ORIENTATION;
252b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell    boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
253b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell    int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
254b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell    int mDefaultGap;
255b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell    int mLastLayoutParamsHashCode = UNINITIALIZED_HASH;
256b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell    Printer mPrinter = LOG_PRINTER;
257e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
258e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Constructors
259e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
260e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
261e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@inheritDoc}
262e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
263e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public GridLayout(Context context, AttributeSet attrs, int defStyle) {
264e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        super(context, attrs, defStyle);
265b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
266e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout);
267e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        try {
268e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
269e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT));
270e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            setOrientation(a.getInt(ORIENTATION, DEFAULT_ORIENTATION));
271e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            setUseDefaultMargins(a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS));
272e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            setAlignmentMode(a.getInt(ALIGNMENT_MODE, DEFAULT_ALIGNMENT_MODE));
273e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
274e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
275e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        } finally {
276e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            a.recycle();
277e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
278e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
279e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
280e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
281e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@inheritDoc}
282e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
283e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public GridLayout(Context context, AttributeSet attrs) {
284e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        this(context, attrs, 0);
285e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
286e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
287e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
288e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@inheritDoc}
289e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
290e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public GridLayout(Context context) {
291e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        //noinspection NullableProblems
292e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        this(context, null);
293e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
294e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
295e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Implementation
296e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
297e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
298e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Returns the current orientation.
299e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
300e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
301e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
302e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #setOrientation(int)
303e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
304e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_orientation
305e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
306e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public int getOrientation() {
307b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        return mOrientation;
308e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
309e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
310e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
3112c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *
3122c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * GridLayout uses the orientation property for two purposes:
3132c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * <ul>
3142c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *  <li>
3152c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *      To control the 'direction' in which default row/column indices are generated
3162c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *      when they are not specified in a component's layout parameters.
3172c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *  </li>
3182c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *  <li>
3192c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *      To control which axis should be processed first during the layout operation:
3202c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *      when orientation is {@link #HORIZONTAL} the horizontal axis is laid out first.
3212c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *  </li>
3222c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * </ul>
3232c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *
3242c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * The order in which axes are laid out is important if, for example, the height of
3252c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * one of GridLayout's children is dependent on its width - and its width is, in turn,
3262c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * dependent on the widths of other components.
3272c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * <p>
3282c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * If your layout contains a {@link android.widget.TextView} (or derivative:
3292c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * {@code Button}, {@code EditText}, {@code CheckBox}, etc.) which is
3302c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * in multi-line mode (the default) it is normally best to leave GridLayout's
3312c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * orientation as {@code HORIZONTAL} - because {@code TextView} is capable of
3322c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * deriving its height for a given width, but not the other way around.
3332c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * <p>
3342c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * Other than the effects above, orientation does not affect the actual layout operation of
3352c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * GridLayout, so it's fine to leave GridLayout in {@code HORIZONTAL} mode even if
3362c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * the height of the intended layout greatly exceeds its width.
337e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
338e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The default value of this property is {@link #HORIZONTAL}.
339e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
340e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param orientation either {@link #HORIZONTAL} or {@link #VERTICAL}
341e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
342e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #getOrientation()
343e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
344e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_orientation
345e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
346e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public void setOrientation(int orientation) {
347b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        if (this.mOrientation != orientation) {
348b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            this.mOrientation = orientation;
349e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            invalidateStructure();
350e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            requestLayout();
351e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
352e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
353e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
354e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
355e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Returns the current number of rows. This is either the last value that was set
356e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * with {@link #setRowCount(int)} or, if no such value was set, the maximum
357e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * value of each the upper bounds defined in {@link LayoutParams#rowSpec}.
358e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
359e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @return the current number of rows
360e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
361e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #setRowCount(int)
362e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see LayoutParams#rowSpec
363e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
364e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_rowCount
365e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
366e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public int getRowCount() {
367b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        return mVerticalAxis.getCount();
368e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
369e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
370e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
371e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * RowCount is used only to generate default row/column indices when
372e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * they are not specified by a component's layout parameters.
373e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
374e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param rowCount the number of rows
375e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
376e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #getRowCount()
377e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see LayoutParams#rowSpec
378e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
379e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_rowCount
380e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
381e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public void setRowCount(int rowCount) {
382b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        mVerticalAxis.setCount(rowCount);
383e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        invalidateStructure();
384e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        requestLayout();
385e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
386e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
387e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
388e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Returns the current number of columns. This is either the last value that was set
389e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * with {@link #setColumnCount(int)} or, if no such value was set, the maximum
390e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * value of each the upper bounds defined in {@link LayoutParams#columnSpec}.
391e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
392e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @return the current number of columns
393e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
394e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #setColumnCount(int)
395e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see LayoutParams#columnSpec
396e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
397e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_columnCount
398e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
399e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public int getColumnCount() {
400b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        return mHorizontalAxis.getCount();
401e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
402e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
403e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
404e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * ColumnCount is used only to generate default column/column indices when
405e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * they are not specified by a component's layout parameters.
406e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
407e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param columnCount the number of columns.
408e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
409e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #getColumnCount()
410e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see LayoutParams#columnSpec
411e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
412e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_columnCount
413e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
414e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public void setColumnCount(int columnCount) {
415b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        mHorizontalAxis.setCount(columnCount);
416e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        invalidateStructure();
417e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        requestLayout();
418e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
419e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
420e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
421e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Returns whether or not this GridLayout will allocate default margins when no
422e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * corresponding layout parameters are defined.
423e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
424e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @return {@code true} if default margins should be allocated
425e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
426e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #setUseDefaultMargins(boolean)
427e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
428e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_useDefaultMargins
429e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
430e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public boolean getUseDefaultMargins() {
431b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        return mUseDefaultMargins;
432e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
433e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
434e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
435e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * When {@code true}, GridLayout allocates default margins around children
436e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * based on the child's visual characteristics. Each of the
437e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * margins so defined may be independently overridden by an assignment
438e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * to the appropriate layout parameter.
439e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
440e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * When {@code false}, the default value of all margins is zero.
441e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
442e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * When setting to {@code true}, consider setting the value of the
443e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link #setAlignmentMode(int) alignmentMode}
444e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * property to {@link #ALIGN_BOUNDS}.
445e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
446e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The default value of this property is {@code false}.
447e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
448e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param useDefaultMargins use {@code true} to make GridLayout allocate default margins
449e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
450e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #getUseDefaultMargins()
451e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #setAlignmentMode(int)
452e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
453e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see MarginLayoutParams#leftMargin
454e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see MarginLayoutParams#topMargin
455e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see MarginLayoutParams#rightMargin
456e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see MarginLayoutParams#bottomMargin
457e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
458e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_useDefaultMargins
459e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
460e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public void setUseDefaultMargins(boolean useDefaultMargins) {
461b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        this.mUseDefaultMargins = useDefaultMargins;
462e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        requestLayout();
463e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
464e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
465e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
466e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Returns the alignment mode.
467e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
468e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @return the alignment mode; either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS}
469e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
470e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #ALIGN_BOUNDS
471e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #ALIGN_MARGINS
472e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
473e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #setAlignmentMode(int)
474e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
475e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_alignmentMode
476e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
477e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public int getAlignmentMode() {
478b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        return mAlignmentMode;
479e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
480e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
481e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
482e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Sets the alignment mode to be used for all of the alignments between the
483e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * children of this container.
484e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
485e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The default value of this property is {@link #ALIGN_MARGINS}.
486e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
487e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param alignmentMode either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS}
488e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
489e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #ALIGN_BOUNDS
490e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #ALIGN_MARGINS
491e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
492e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #getAlignmentMode()
493e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
494e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_alignmentMode
495e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
496e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public void setAlignmentMode(int alignmentMode) {
497b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        this.mAlignmentMode = alignmentMode;
498e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        requestLayout();
499e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
500e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
501e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
502e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Returns whether or not row boundaries are ordered by their grid indices.
503e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
504e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @return {@code true} if row boundaries must appear in the order of their indices,
505e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *         {@code false} otherwise
506e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
507e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #setRowOrderPreserved(boolean)
508e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
509e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
510e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
511e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public boolean isRowOrderPreserved() {
512b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        return mVerticalAxis.isOrderPreserved();
513e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
514e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
515e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
516e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * When this property is {@code true}, GridLayout is forced to place the row boundaries
517e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * so that their associated grid indices are in ascending order in the view.
518e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
519e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * When this property is {@code false} GridLayout is at liberty to place the vertical row
520e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * boundaries in whatever order best fits the given constraints.
521e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
522e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The default value of this property is {@code true}.
523e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
524e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param rowOrderPreserved {@code true} to force GridLayout to respect the order
525e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *        of row boundaries
526e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
527e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #isRowOrderPreserved()
528e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
529e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
530e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
531e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public void setRowOrderPreserved(boolean rowOrderPreserved) {
532b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        mVerticalAxis.setOrderPreserved(rowOrderPreserved);
533e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        invalidateStructure();
534e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        requestLayout();
535e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
536e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
537e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
538e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Returns whether or not column boundaries are ordered by their grid indices.
539e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
540e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @return {@code true} if column boundaries must appear in the order of their indices,
541e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *         {@code false} otherwise
542e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
543e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #setColumnOrderPreserved(boolean)
544e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
545e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
546e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
547e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public boolean isColumnOrderPreserved() {
548b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        return mHorizontalAxis.isOrderPreserved();
549e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
550e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
551e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
552e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * When this property is {@code true}, GridLayout is forced to place the column boundaries
553e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * so that their associated grid indices are in ascending order in the view.
554e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
555e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * When this property is {@code false} GridLayout is at liberty to place the horizontal column
556e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * boundaries in whatever order best fits the given constraints.
557e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
558e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The default value of this property is {@code true}.
559e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
560e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param columnOrderPreserved use {@code true} to force GridLayout to respect the order
561e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *        of column boundaries.
562e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
563e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see #isColumnOrderPreserved()
564e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
565e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
566e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
567e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public void setColumnOrderPreserved(boolean columnOrderPreserved) {
568b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        mHorizontalAxis.setOrderPreserved(columnOrderPreserved);
569e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        invalidateStructure();
570e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        requestLayout();
571e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
572e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
5732c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    /**
5742c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * Return the printer that will log diagnostics from this layout.
5752c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *
5762c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * @see #setPrinter(android.util.Printer)
5772c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *
5782c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * @return the printer associated with this view
5792c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     */
5802c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    public Printer getPrinter() {
581b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        return mPrinter;
5822c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    }
5832c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
5842c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    /**
5852c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * Set the printer that will log diagnostics from this layout.
5862c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * The default value is created by {@link android.util.LogPrinter}.
5872c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *
5882c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * @param printer the printer associated with this layout
5892c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *
5902c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * @see #getPrinter()
5912c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     */
5922c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    public void setPrinter(Printer printer) {
593b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        this.mPrinter = (printer == null) ? NO_PRINTER : printer;
5942c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    }
5952c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
596e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Static utility methods
597e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
598e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    static int max2(int[] a, int valueIfEmpty) {
599e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int result = valueIfEmpty;
600e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        for (int i = 0, N = a.length; i < N; i++) {
601e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            result = Math.max(result, a[i]);
602e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
603e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return result;
604e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
605e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
606e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    @SuppressWarnings("unchecked")
607e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    static <T> T[] append(T[] a, T[] b) {
608e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
609e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        System.arraycopy(a, 0, result, 0, a.length);
610e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        System.arraycopy(b, 0, result, a.length, b.length);
611e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return result;
612e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
613e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
614e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    static Alignment getAlignment(int gravity, boolean horizontal) {
615e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int mask = horizontal ? HORIZONTAL_GRAVITY_MASK : VERTICAL_GRAVITY_MASK;
616e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int shift = horizontal ? AXIS_X_SHIFT : AXIS_Y_SHIFT;
617e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int flags = (gravity & mask) >> shift;
618e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        switch (flags) {
619e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE):
6202c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                return horizontal ? LEFT : TOP;
621e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            case (AXIS_SPECIFIED | AXIS_PULL_AFTER):
6222c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                return horizontal ? RIGHT : BOTTOM;
623e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER):
624e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return FILL;
625e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            case AXIS_SPECIFIED:
626e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return CENTER;
627b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | GravityCompat.RELATIVE_LAYOUT_DIRECTION):
628e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return START;
629b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            case (AXIS_SPECIFIED | AXIS_PULL_AFTER | GravityCompat.RELATIVE_LAYOUT_DIRECTION):
630e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return END;
631e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            default:
632e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return UNDEFINED_ALIGNMENT;
633e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
634e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
635e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
636e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /** @noinspection UnusedParameters*/
637e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
638b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        if (c.getClass() == android.support.v7.widget.Space.class) {
639e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return 0;
640e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
641b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        return mDefaultGap / 2;
642e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
643e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
644e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
6452c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        return /*isAtEdge ? DEFAULT_CONTAINER_MARGIN :*/ getDefaultMargin(c, horizontal, leading);
646e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
647e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
6482c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) {
649b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        if (!mUseDefaultMargins) {
650e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return 0;
651e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
652e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        Spec spec = horizontal ? p.columnSpec : p.rowSpec;
653b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
654e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        Interval span = spec.span;
655b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        boolean leading1 = (horizontal && isLayoutRtlCompat()) ? !leading : leading;
656e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount());
657e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
658e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return getDefaultMargin(c, isAtEdge, horizontal, leading);
659e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
660e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
661e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    int getMargin1(View view, boolean horizontal, boolean leading) {
662e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        LayoutParams lp = getLayoutParams(view);
663e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int margin = horizontal ?
664e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                (leading ? lp.leftMargin : lp.rightMargin) :
665e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                (leading ? lp.topMargin : lp.bottomMargin);
6662c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        return margin == UNDEFINED ? getDefaultMargin(view, lp, horizontal, leading) : margin;
667e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
668e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
669b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell    private boolean isLayoutRtlCompat() {
670b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
671b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell    }
672b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell
673e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private int getMargin(View view, boolean horizontal, boolean leading) {
674b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        if (mAlignmentMode == ALIGN_MARGINS) {
675e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return getMargin1(view, horizontal, leading);
676e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        } else {
677b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
678e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins();
679e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            LayoutParams lp = getLayoutParams(view);
680e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
681e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int index = leading ? spec.span.min : spec.span.max;
682e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return margins[index];
683e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
684e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
685e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
686e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private int getTotalMargin(View child, boolean horizontal) {
687e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return getMargin(child, horizontal, true) + getMargin(child, horizontal, false);
688e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
689e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
690e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static boolean fits(int[] a, int value, int start, int end) {
691e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        if (end > a.length) {
692e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return false;
693e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
694e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        for (int i = start; i < end; i++) {
695e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (a[i] > value) {
696e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return false;
697e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
698e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
699e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return true;
700e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
701e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
702e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static void procrusteanFill(int[] a, int start, int end, int value) {
703e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int length = a.length;
704e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        Arrays.fill(a, Math.min(start, length), Math.min(end, length), value);
705e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
706e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
707e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static void setCellGroup(LayoutParams lp, int row, int rowSpan, int col, int colSpan) {
708e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        lp.setRowSpecSpan(new Interval(row, row + rowSpan));
709e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        lp.setColumnSpecSpan(new Interval(col, col + colSpan));
710e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
711e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
712e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Logic to avert infinite loops by ensuring that the cells can be placed somewhere.
713e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static int clip(Interval minorRange, boolean minorWasDefined, int count) {
714e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int size = minorRange.size();
715e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        if (count == 0) {
716e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return size;
717e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
718e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int min = minorWasDefined ? min(minorRange.min, count) : 0;
719e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return min(size, count - min);
720e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
721e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
722e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // install default indices for cells that don't define them
723e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private void validateLayoutParams() {
724b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        final boolean horizontal = (mOrientation == HORIZONTAL);
725b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        final Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
726e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0;
727e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
728e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int major = 0;
729e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int minor = 0;
730e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int[] maxSizes = new int[count];
731e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
732e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        for (int i = 0, N = getChildCount(); i < N; i++) {
733e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
734e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
735e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec;
736e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            final Interval majorRange = majorSpec.span;
737e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            final boolean majorWasDefined = majorSpec.startDefined;
738e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            final int majorSpan = majorRange.size();
739e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (majorWasDefined) {
740e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                major = majorRange.min;
741e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
742e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
743e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            final Spec minorSpec = horizontal ? lp.columnSpec : lp.rowSpec;
744e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            final Interval minorRange = minorSpec.span;
745e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            final boolean minorWasDefined = minorSpec.startDefined;
746e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            final int minorSpan = clip(minorRange, minorWasDefined, count);
747e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (minorWasDefined) {
748e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                minor = minorRange.min;
749e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
750e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
751e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (count != 0) {
752e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                // Find suitable row/col values when at least one is undefined.
753e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                if (!majorWasDefined || !minorWasDefined) {
754e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    while (!fits(maxSizes, major, minor, minor + minorSpan)) {
755e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        if (minorWasDefined) {
756e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            major++;
757e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        } else {
758e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            if (minor + minorSpan <= count) {
759e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                                minor++;
760e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            } else {
761e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                                minor = 0;
762e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                                major++;
763e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            }
764e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        }
765e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    }
766e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
767e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                procrusteanFill(maxSizes, minor, minor + minorSpan, major + majorSpan);
768e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
769e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
770e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (horizontal) {
771e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                setCellGroup(lp, major, majorSpan, minor, minorSpan);
772e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            } else {
773e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                setCellGroup(lp, minor, minorSpan, major, majorSpan);
774e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
775e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
776e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            minor = minor + minorSpan;
777e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
778e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
779e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
780e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private void invalidateStructure() {
781b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        mLastLayoutParamsHashCode = UNINITIALIZED_HASH;
782b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        if (mHorizontalAxis != null) mHorizontalAxis.invalidateStructure();
783b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        if (mVerticalAxis != null) mVerticalAxis.invalidateStructure();
784e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // This can end up being done twice. Better twice than not at all.
785e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        invalidateValues();
786e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
787e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
788e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private void invalidateValues() {
789e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Need null check because requestLayout() is called in View's initializer,
790e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // before we are set up.
791b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        if (mHorizontalAxis != null && mVerticalAxis != null) {
792b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            mHorizontalAxis.invalidateValues();
793b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            mVerticalAxis.invalidateValues();
7942c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        }
795e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
796e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
797e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    final LayoutParams getLayoutParams(View c) {
798e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return (LayoutParams) c.getLayoutParams();
799e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
800e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
8012c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    private static void handleInvalidParams(String msg) {
8022c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        throw new IllegalArgumentException(msg + ". ");
8032c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    }
8042c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
8052c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    private void checkLayoutParams(LayoutParams lp, boolean horizontal) {
8062c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        String groupName = horizontal ? "column" : "row";
8072c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
8082c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        Interval span = spec.span;
8092c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        if (span.min != UNDEFINED && span.min < 0) {
8102c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            handleInvalidParams(groupName + " indices must be positive");
8112c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        }
812b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
8132c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        int count = axis.definedCount;
8142c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        if (count != UNDEFINED) {
8152c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            if (span.max > count) {
8162c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                handleInvalidParams(groupName +
8172c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                        " indices (start + span) mustn't exceed the " + groupName + " count");
8182c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            }
8192c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            if (span.size() > count) {
8202c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                handleInvalidParams(groupName + " span mustn't exceed the " + groupName + " count");
8212c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            }
8222c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        }
8232c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    }
8242c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
8252c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    @Override
8262c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
8272c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        if (!(p instanceof LayoutParams)) {
8282c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            return false;
8292c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        }
8302c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        LayoutParams lp = (LayoutParams) p;
8312c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
8322c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        checkLayoutParams(lp, true);
8332c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        checkLayoutParams(lp, false);
8342c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
8352c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        return true;
8362c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    }
8372c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
838e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    @Override
839e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    protected LayoutParams generateDefaultLayoutParams() {
840e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return new LayoutParams();
841e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
842e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
843e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    @Override
844e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public LayoutParams generateLayoutParams(AttributeSet attrs) {
845e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return new LayoutParams(getContext(), attrs);
846e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
847e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
848e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    @Override
849e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
850e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return new LayoutParams(p);
851e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
852e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
853e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Draw grid
854e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
855e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
856b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        if (isLayoutRtlCompat()) {
857e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int width = getWidth();
8582c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            graphics.drawLine(width - x1, y1, width - x2, y2, paint);
859e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        } else {
8602c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            graphics.drawLine(x1, y1, x2, y2, paint);
861e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
862e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
863e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
864e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private int computeLayoutParamsHashCode() {
865e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int result = 1;
866e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        for (int i = 0, N = getChildCount(); i < N; i++) {
867e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            View c = getChildAt(i);
868e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (c.getVisibility() == View.GONE) continue;
869e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            LayoutParams lp = (LayoutParams) c.getLayoutParams();
870e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            result = 31 * result + lp.hashCode();
871e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
872e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return result;
873e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
874e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
8752c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    private void consistencyCheck() {
876b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        if (mLastLayoutParamsHashCode == UNINITIALIZED_HASH) {
8772c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            validateLayoutParams();
878b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            mLastLayoutParamsHashCode = computeLayoutParamsHashCode();
879b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        } else if (mLastLayoutParamsHashCode != computeLayoutParamsHashCode()) {
880b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            mPrinter.println("The fields of some layout parameters were modified in between "
8812c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                    + "layout operations. Check the javadoc for GridLayout.LayoutParams#rowSpec.");
882e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            invalidateStructure();
8832c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            consistencyCheck();
884e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
885e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
886e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
887e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Measurement
888e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
8892c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    // Note: padding has already been removed from the supplied specs
890e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec,
891e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                                          int childWidth, int childHeight) {
892e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
8932c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                getTotalMargin(child, true), childWidth);
894e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
8952c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                getTotalMargin(child, false), childHeight);
896e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        child.measure(childWidthSpec, childHeightSpec);
897e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
898e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
8992c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    // Note: padding has already been removed from the supplied specs
900e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) {
901e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        for (int i = 0, N = getChildCount(); i < N; i++) {
902e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            View c = getChildAt(i);
903e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (c.getVisibility() == View.GONE) continue;
904e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            LayoutParams lp = getLayoutParams(c);
905e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (firstPass) {
906e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
907e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            } else {
908b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell                boolean horizontal = (mOrientation == HORIZONTAL);
909e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
910aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                if (spec.getAbsoluteAlignment(horizontal) == FILL) {
911e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    Interval span = spec.span;
912b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell                    Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
913e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    int[] locations = axis.getLocations();
914e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    int cellSize = locations[span.max] - locations[span.min];
915e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    int viewSize = cellSize - getTotalMargin(c, horizontal);
916e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    if (horizontal) {
917e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        measureChildWithMargins2(c, widthSpec, heightSpec, viewSize, lp.height);
918e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    } else {
919e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, viewSize);
920e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    }
921e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
922e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
923e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
924e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
925e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
9262c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    static int adjust(int measureSpec, int delta) {
9272c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        return makeMeasureSpec(
9282c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                MeasureSpec.getSize(measureSpec + delta),  MeasureSpec.getMode(measureSpec));
9292c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio    }
9302c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
931e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    @Override
932e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    protected void onMeasure(int widthSpec, int heightSpec) {
9332c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        consistencyCheck();
934e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
935e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /** If we have been called by {@link View#measure(int, int)}, one of width or height
936e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *  is  likely to have changed. We must invalidate if so. */
937e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        invalidateValues();
938e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
9392c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        int hPadding = getPaddingLeft() + getPaddingRight();
9402c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        int vPadding = getPaddingTop()  + getPaddingBottom();
9412c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
9422c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        int widthSpecSansPadding =  adjust( widthSpec, -hPadding);
9432c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        int heightSpecSansPadding = adjust(heightSpec, -vPadding);
944e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
9452c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, true);
9462c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
9472c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        int widthSansPadding;
9482c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        int heightSansPadding;
949e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
950e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Use the orientation property to decide which axis should be laid out first.
951b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        if (mOrientation == HORIZONTAL) {
952b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding);
9532c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
954b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding);
955e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        } else {
956b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding);
9572c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
958b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding);
959e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
960e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
9612c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        int measuredWidth  = Math.max(widthSansPadding  + hPadding, getSuggestedMinimumWidth());
9622c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        int measuredHeight = Math.max(heightSansPadding + vPadding, getSuggestedMinimumHeight());
963e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
964e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        setMeasuredDimension(
965b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell                ViewCompat.resolveSizeAndState(measuredWidth, widthSpec, 0),
966b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell                ViewCompat.resolveSizeAndState(measuredHeight, heightSpec, 0));
967e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
968e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
969e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private int getMeasurement(View c, boolean horizontal) {
970e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
971e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
972e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
973e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    final int getMeasurementIncludingMargin(View c, boolean horizontal) {
974e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        if (c.getVisibility() == View.GONE) {
975e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return 0;
976e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
977e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal);
978e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
979e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
980e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    @Override
981e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public void requestLayout() {
982e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        super.requestLayout();
983b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        invalidateStructure();
984e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
985e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
986e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Layout container
987e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
988e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
989e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@inheritDoc}
990e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
991e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /*
992e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     The layout operation is implemented by delegating the heavy lifting to the
993e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     to the mHorizontalAxis and mVerticalAxis instances of the internal Axis class.
994e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     Together they compute the locations of the vertical and horizontal lines of
995e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     the grid (respectively!).
996e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
997e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     This method is then left with the simpler task of applying margins, gravity
998e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     and sizing to each child view and then placing it in its cell.
999e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
1000e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    @Override
1001e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
10022c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        consistencyCheck();
1003e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1004e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int targetWidth = right - left;
1005e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int targetHeight = bottom - top;
1006e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1007e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int paddingLeft = getPaddingLeft();
1008e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int paddingTop = getPaddingTop();
1009e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int paddingRight = getPaddingRight();
1010e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int paddingBottom = getPaddingBottom();
1011e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1012b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
1013b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom);
1014e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1015b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        int[] hLocations = mHorizontalAxis.getLocations();
1016b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell        int[] vLocations = mVerticalAxis.getLocations();
1017e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1018e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        for (int i = 0, N = getChildCount(); i < N; i++) {
1019e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            View c = getChildAt(i);
1020e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (c.getVisibility() == View.GONE) continue;
1021e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            LayoutParams lp = getLayoutParams(c);
1022e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Spec columnSpec = lp.columnSpec;
1023e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Spec rowSpec = lp.rowSpec;
1024e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1025e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Interval colSpan = columnSpec.span;
1026e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Interval rowSpan = rowSpec.span;
1027e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1028e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int x1 = hLocations[colSpan.min];
1029e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int y1 = vLocations[rowSpan.min];
1030e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1031e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int x2 = hLocations[colSpan.max];
1032e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int y2 = vLocations[rowSpan.max];
1033e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1034e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int cellWidth = x2 - x1;
1035e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int cellHeight = y2 - y1;
1036e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1037e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int pWidth = getMeasurement(c, true);
1038e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int pHeight = getMeasurement(c, false);
1039e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1040aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            Alignment hAlign = columnSpec.getAbsoluteAlignment(true);
1041aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            Alignment vAlign = rowSpec.getAbsoluteAlignment(false);
1042e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1043b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i);
1044b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i);
1045e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1046e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // Gravity offsets: the location of the alignment group relative to its cell group.
1047e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true));
1048e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int gravityOffsetY = vAlign.getGravityOffset(c, cellHeight - boundsY.size(true));
1049e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1050e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int leftMargin = getMargin(c, true, true);
1051e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int topMargin = getMargin(c, false, true);
1052e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int rightMargin = getMargin(c, true, false);
1053e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int bottomMargin = getMargin(c, false, false);
1054e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
10552c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            int sumMarginsX = leftMargin + rightMargin;
10562c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            int sumMarginsY = topMargin + bottomMargin;
10572c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio
1058e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // Alignment offsets: the location of the view relative to its alignment group.
10592c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true);
10602c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false);
1061e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
10622c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX);
10632c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY);
1064e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1065e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int dx = x1 + gravityOffsetX + alignmentOffsetX;
1066e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1067b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            int cx = !isLayoutRtlCompat() ? paddingLeft + leftMargin + dx :
1068e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    targetWidth - width - paddingRight - rightMargin - dx;
1069e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin;
1070e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1071e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) {
1072e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
1073e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1074e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            c.layout(cx, cy, cx + width, cy + height);
1075e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1076e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
1077e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1078e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // Inner classes
1079e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1080e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /*
1081e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     This internal class houses the algorithm for computing the locations of grid lines;
1082e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     along either the horizontal or vertical axis. A GridLayout uses two instances of this class -
1083e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     distinguished by the "horizontal" flag which is true for the horizontal axis and false
1084e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     for the vertical one.
1085e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
1086e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    final class Axis {
1087e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int NEW = 0;
1088e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int PENDING = 1;
1089e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int COMPLETE = 2;
1090e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1091e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public final boolean horizontal;
1092e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1093e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int definedCount = UNDEFINED;
1094e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private int maxIndex = UNDEFINED;
1095e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1096e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        PackedMap<Spec, Bounds> groupBounds;
1097e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean groupBoundsValid = false;
1098e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1099e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        PackedMap<Interval, MutableInt> forwardLinks;
1100e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean forwardLinksValid = false;
1101e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1102e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        PackedMap<Interval, MutableInt> backwardLinks;
1103e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean backwardLinksValid = false;
1104e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1105e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int[] leadingMargins;
1106e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean leadingMarginsValid = false;
1107e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1108e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int[] trailingMargins;
1109e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean trailingMarginsValid = false;
1110e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1111e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public Arc[] arcs;
1112e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean arcsValid = false;
1113e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1114e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int[] locations;
1115e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean locationsValid = false;
1116e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1117e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        public boolean hasWeights;
1118e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        public boolean hasWeightsValid = false;
1119e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        public int[] deltas;
1120e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
1121e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        boolean orderPreserved = DEFAULT_ORDER_PRESERVED;
1122e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1123e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private MutableInt parentMin = new MutableInt(0);
1124e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private MutableInt parentMax = new MutableInt(-MAX_SIZE);
1125e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1126e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private Axis(boolean horizontal) {
1127e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.horizontal = horizontal;
1128e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1129e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1130e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private int calculateMaxIndex() {
1131e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // the number Integer.MIN_VALUE + 1 comes up in undefined cells
1132e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int result = -1;
1133e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0, N = getChildCount(); i < N; i++) {
1134e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                View c = getChildAt(i);
1135e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                LayoutParams params = getLayoutParams(c);
1136e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Spec spec = horizontal ? params.columnSpec : params.rowSpec;
1137e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Interval span = spec.span;
1138e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                result = max(result, span.min);
1139e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                result = max(result, span.max);
11402c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                result = max(result, span.size());
1141e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1142e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return result == -1 ? UNDEFINED : result;
1143e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1144e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1145e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private int getMaxIndex() {
1146e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (maxIndex == UNDEFINED) {
1147e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                maxIndex = max(0, calculateMaxIndex()); // use zero when there are no children
1148e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1149e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return maxIndex;
1150e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1151e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1152e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int getCount() {
1153e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return max(definedCount, getMaxIndex());
1154e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1155e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1156e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public void setCount(int count) {
11572c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            if (count != UNDEFINED && count < getMaxIndex()) {
11582c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                handleInvalidParams((horizontal ? "column" : "row") +
11592c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                        "Count must be greater than or equal to the maximum of all grid indices " +
11602c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                        "(and spans) defined in the LayoutParams of each child");
11612c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            }
1162e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.definedCount = count;
1163e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1164e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1165e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean isOrderPreserved() {
1166e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return orderPreserved;
1167e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1168e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1169e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public void setOrderPreserved(boolean orderPreserved) {
1170e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.orderPreserved = orderPreserved;
1171e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            invalidateStructure();
1172e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1173e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1174e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private PackedMap<Spec, Bounds> createGroupBounds() {
1175e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class);
1176e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0, N = getChildCount(); i < N; i++) {
1177e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                View c = getChildAt(i);
11782c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                // we must include views that are GONE here, see introductory javadoc
1179e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                LayoutParams lp = getLayoutParams(c);
1180e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
1181aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                Bounds bounds = spec.getAbsoluteAlignment(horizontal).getBounds();
1182e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                assoc.put(spec, bounds);
1183e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1184e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return assoc.pack();
1185e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1186e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1187e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void computeGroupBounds() {
1188e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Bounds[] values = groupBounds.values;
1189e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0; i < values.length; i++) {
1190e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                values[i].reset();
1191e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1192e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0, N = getChildCount(); i < N; i++) {
1193e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                View c = getChildAt(i);
11942c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                // we must include views that are GONE here, see introductory javadoc
1195e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                LayoutParams lp = getLayoutParams(c);
1196e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
1197ee781a599830945fa4c3f78c8a7e99c971fe5524Yigit Boyar                int size = getMeasurementIncludingMargin(c, horizontal) +
1198ee781a599830945fa4c3f78c8a7e99c971fe5524Yigit Boyar                                ((spec.weight == 0) ? 0 : getDeltas()[i]);
1199e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                groupBounds.getValue(i).include(GridLayout.this, c, spec, this, size);
1200e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1201e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1202e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1203e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public PackedMap<Spec, Bounds> getGroupBounds() {
1204e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (groupBounds == null) {
1205e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                groupBounds = createGroupBounds();
1206e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1207e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!groupBoundsValid) {
1208e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                computeGroupBounds();
1209e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                groupBoundsValid = true;
1210e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1211e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return groupBounds;
1212e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1213e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1214e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Add values computed by alignment - taking the max of all alignments in each span
1215e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private PackedMap<Interval, MutableInt> createLinks(boolean min) {
1216e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class);
1217e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Spec[] keys = getGroupBounds().keys;
1218e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0, N = keys.length; i < N; i++) {
1219e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Interval span = min ? keys[i].span : keys[i].span.inverse();
1220e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                result.put(span, new MutableInt());
1221e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1222e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return result.pack();
1223e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1224e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1225e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void computeLinks(PackedMap<Interval, MutableInt> links, boolean min) {
1226e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            MutableInt[] spans = links.values;
1227e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0; i < spans.length; i++) {
1228e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                spans[i].reset();
1229e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1230e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1231e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // Use getter to trigger a re-evaluation
1232e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Bounds[] bounds = getGroupBounds().values;
1233e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0; i < bounds.length; i++) {
1234e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int size = bounds[i].size(min);
1235e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                MutableInt valueHolder = links.getValue(i);
1236e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                // this effectively takes the max() of the minima and the min() of the maxima
1237e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                valueHolder.value = max(valueHolder.value, min ? size : -size);
1238e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1239e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1240e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1241e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private PackedMap<Interval, MutableInt> getForwardLinks() {
1242e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (forwardLinks == null) {
1243e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                forwardLinks = createLinks(true);
1244e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1245e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!forwardLinksValid) {
1246e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                computeLinks(forwardLinks, true);
1247e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                forwardLinksValid = true;
1248e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1249e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return forwardLinks;
1250e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1251e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1252e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private PackedMap<Interval, MutableInt> getBackwardLinks() {
1253e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (backwardLinks == null) {
1254e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                backwardLinks = createLinks(false);
1255e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1256e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!backwardLinksValid) {
1257e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                computeLinks(backwardLinks, false);
1258e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                backwardLinksValid = true;
1259e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1260e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return backwardLinks;
1261e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1262e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1263e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void include(List<Arc> arcs, Interval key, MutableInt size,
1264e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                             boolean ignoreIfAlreadyPresent) {
1265e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            /*
1266e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Remove self referential links.
1267e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            These appear:
1268e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                . as parental constraints when GridLayout has no children
1269e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                . when components have been marked as GONE
1270e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            */
1271e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (key.size() == 0) {
1272e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return;
1273e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1274e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // this bit below should really be computed outside here -
1275e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // its just to stop default (row/col > 0) constraints obliterating valid entries
1276e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (ignoreIfAlreadyPresent) {
1277e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                for (Arc arc : arcs) {
1278e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    Interval span = arc.span;
1279e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    if (span.equals(key)) {
1280e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        return;
1281e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    }
1282e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1283e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1284e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            arcs.add(new Arc(key, size));
1285e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1286e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1287e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void include(List<Arc> arcs, Interval key, MutableInt size) {
1288e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            include(arcs, key, size, true);
1289e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1290e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1291e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Group arcs by their first vertex, returning an array of arrays.
1292e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // This is linear in the number of arcs.
1293e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        Arc[][] groupArcsByFirstVertex(Arc[] arcs) {
1294e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int N = getCount() + 1; // the number of vertices
1295e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Arc[][] result = new Arc[N][];
1296e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int[] sizes = new int[N];
1297e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (Arc arc : arcs) {
1298e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                sizes[arc.span.min]++;
1299e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1300e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0; i < sizes.length; i++) {
1301e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                result[i] = new Arc[sizes[i]];
1302e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1303e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // reuse the sizes array to hold the current last elements as we insert each arc
1304e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Arrays.fill(sizes, 0);
1305e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (Arc arc : arcs) {
1306e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int i = arc.span.min;
1307e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                result[i][sizes[i]++] = arc;
1308e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1309e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1310e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return result;
1311e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1312e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1313e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private Arc[] topologicalSort(final Arc[] arcs) {
1314e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return new Object() {
1315e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Arc[] result = new Arc[arcs.length];
1316e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int cursor = result.length - 1;
1317e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Arc[][] arcsByVertex = groupArcsByFirstVertex(arcs);
1318e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int[] visited = new int[getCount() + 1];
1319e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1320e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                void walk(int loc) {
1321e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    switch (visited[loc]) {
1322e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        case NEW: {
1323e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            visited[loc] = PENDING;
1324e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            for (Arc arc : arcsByVertex[loc]) {
1325e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                                walk(arc.span.max);
1326e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                                result[cursor--] = arc;
1327e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            }
1328e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            visited[loc] = COMPLETE;
1329e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            break;
1330e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        }
1331e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        case PENDING: {
13322c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                            // le singe est dans l'arbre
1333e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            assert false;
1334e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            break;
1335e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        }
1336e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        case COMPLETE: {
1337e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            break;
1338e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        }
1339e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    }
1340e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1341e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1342e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Arc[] sort() {
1343e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    for (int loc = 0, N = arcsByVertex.length; loc < N; loc++) {
1344e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        walk(loc);
1345e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    }
1346e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    assert cursor == -1;
1347e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    return result;
1348e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1349e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }.sort();
1350e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1351e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1352e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private Arc[] topologicalSort(List<Arc> arcs) {
1353e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return topologicalSort(arcs.toArray(new Arc[arcs.size()]));
1354e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1355e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1356e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void addComponentSizes(List<Arc> result, PackedMap<Interval, MutableInt> links) {
1357e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0; i < links.keys.length; i++) {
1358e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Interval key = links.keys[i];
1359e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                include(result, key, links.values[i], false);
1360e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1361e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1362e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1363e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private Arc[] createArcs() {
1364e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            List<Arc> mins = new ArrayList<Arc>();
1365e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            List<Arc> maxs = new ArrayList<Arc>();
1366e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1367e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // Add the minimum values from the components.
1368e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            addComponentSizes(mins, getForwardLinks());
1369e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // Add the maximum values from the components.
1370e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            addComponentSizes(maxs, getBackwardLinks());
1371e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1372e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // Add ordering constraints to prevent row/col sizes from going negative
1373e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (orderPreserved) {
1374e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                // Add a constraint for every row/col
1375e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                for (int i = 0; i < getCount(); i++) {
1376e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    include(mins, new Interval(i, i + 1), new MutableInt(0));
1377e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1378e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1379e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1380e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // Add the container constraints. Use the version of include that allows
1381e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // duplicate entries in case a child spans the entire grid.
1382e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int N = getCount();
1383e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            include(mins, new Interval(0, N), parentMin, false);
1384e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            include(maxs, new Interval(N, 0), parentMax, false);
1385e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1386e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // Sort
1387e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Arc[] sMins = topologicalSort(mins);
1388e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Arc[] sMaxs = topologicalSort(maxs);
1389e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1390e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return append(sMins, sMaxs);
1391e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1392e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1393e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void computeArcs() {
1394e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // getting the links validates the values that are shared by the arc list
1395e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            getForwardLinks();
1396e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            getBackwardLinks();
1397e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1398e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1399e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public Arc[] getArcs() {
1400e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (arcs == null) {
1401e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                arcs = createArcs();
1402e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1403e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!arcsValid) {
1404e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                computeArcs();
1405e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                arcsValid = true;
1406e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1407e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return arcs;
1408e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1409e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1410e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private boolean relax(int[] locations, Arc entry) {
1411e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!entry.valid) {
1412e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return false;
1413e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1414e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Interval span = entry.span;
1415e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int u = span.min;
1416e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int v = span.max;
1417e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int value = entry.value.value;
1418e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int candidate = locations[u] + value;
1419e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (candidate > locations[v]) {
1420e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                locations[v] = candidate;
1421e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return true;
1422e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1423e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return false;
1424e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1425e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1426e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void init(int[] locations) {
1427e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Arrays.fill(locations, 0);
1428e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1429e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1430e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private String arcsToString(List<Arc> arcs) {
1431e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            String var = horizontal ? "x" : "y";
1432e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            StringBuilder result = new StringBuilder();
1433e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            boolean first = true;
1434e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (Arc arc : arcs) {
1435e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                if (first) {
1436e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    first = false;
1437e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                } else {
1438e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    result = result.append(", ");
1439e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1440e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int src = arc.span.min;
1441e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int dst = arc.span.max;
1442e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int value = arc.value.value;
1443e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                result.append((src < dst) ?
14442c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                        var + dst + "-" + var + src + ">=" + value :
14452c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                        var + src + "-" + var + dst + "<=" + -value);
1446e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1447e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1448e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return result.toString();
1449e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1450e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1451e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void logError(String axisName, Arc[] arcs, boolean[] culprits0) {
1452e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            List<Arc> culprits = new ArrayList<Arc>();
1453e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            List<Arc> removed = new ArrayList<Arc>();
1454e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int c = 0; c < arcs.length; c++) {
1455e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Arc arc = arcs[c];
1456e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                if (culprits0[c]) {
1457e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    culprits.add(arc);
1458e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1459e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                if (!arc.valid) {
1460e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    removed.add(arc);
1461e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1462e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1463b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            mPrinter.println(axisName + " constraints: " + arcsToString(culprits) +
14642c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                    " are inconsistent; permanently removing: " + arcsToString(removed) + ". ");
1465e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1466e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1467e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /*
1468e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N)
1469e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1470e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        GridLayout converts its requirements into a system of linear constraints of the
1471e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        form:
1472e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1473e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        x[i] - x[j] < a[k]
1474e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1475e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        Where the x[i] are variables and the a[k] are constants.
1476e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1477e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        For example, if the variables were instead labeled x, y, z we might have:
1478e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1479e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            x - y < 17
1480e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            y - z < 23
1481e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            z - x < 42
1482e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1483e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        This is a special case of the Linear Programming problem that is, in turn,
1484e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        equivalent to the single-source shortest paths problem on a digraph, for
1485e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        which the O(n^2) Bellman-Ford algorithm the most commonly used general solution.
1486e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        */
14875f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar        private boolean solve(Arc[] arcs, int[] locations) {
14885f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            return solve(arcs, locations, true);
14895f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar        }
14905f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar
14915f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar        private boolean solve(Arc[] arcs, int[] locations, boolean modifyOnError) {
1492e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            String axisName = horizontal ? "horizontal" : "vertical";
1493e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
1494e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            boolean[] originalCulprits = null;
1495e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1496e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int p = 0; p < arcs.length; p++) {
1497e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                init(locations);
1498e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1499e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                // We take one extra pass over traditional Bellman-Ford (and omit their final step)
1500e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                for (int i = 0; i < N; i++) {
1501e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    boolean changed = false;
1502e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    for (int j = 0, length = arcs.length; j < length; j++) {
1503e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        changed |= relax(locations, arcs[j]);
1504e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    }
1505e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    if (!changed) {
1506e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        if (originalCulprits != null) {
1507e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            logError(axisName, arcs, originalCulprits);
1508e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        }
15095f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                        return true;
1510e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    }
1511e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1512e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
15135f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                if (!modifyOnError) {
15145f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                    return false; // cannot solve with these constraints
15155f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                }
15165f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar
1517e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                boolean[] culprits = new boolean[arcs.length];
1518e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                for (int i = 0; i < N; i++) {
1519e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    for (int j = 0, length = arcs.length; j < length; j++) {
1520e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        culprits[j] |= relax(locations, arcs[j]);
1521e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    }
1522e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1523e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1524e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                if (p == 0) {
1525e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    originalCulprits = culprits;
1526e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1527e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1528e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                for (int i = 0; i < arcs.length; i++) {
1529e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    if (culprits[i]) {
1530e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        Arc arc = arcs[i];
1531e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        // Only remove max values, min values alone cannot be inconsistent
1532e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        if (arc.span.min < arc.span.max) {
1533e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                            continue;
1534e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        }
1535e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        arc.valid = false;
1536e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                        break;
1537e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    }
1538e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1539e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
15405f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            return true;
1541e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1542e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1543e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void computeMargins(boolean leading) {
1544e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int[] margins = leading ? leadingMargins : trailingMargins;
1545e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0, N = getChildCount(); i < N; i++) {
1546e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                View c = getChildAt(i);
1547e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                if (c.getVisibility() == View.GONE) continue;
1548e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                LayoutParams lp = getLayoutParams(c);
1549e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
1550e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Interval span = spec.span;
1551e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int index = leading ? span.min : span.max;
1552e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                margins[index] = max(margins[index], getMargin1(c, horizontal, leading));
1553e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1554e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1555e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1556e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // External entry points
1557e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1558e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int[] getLeadingMargins() {
1559e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (leadingMargins == null) {
1560e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                leadingMargins = new int[getCount() + 1];
1561e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1562e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!leadingMarginsValid) {
1563e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                computeMargins(true);
1564e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                leadingMarginsValid = true;
1565e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1566e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return leadingMargins;
1567e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1568e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1569e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int[] getTrailingMargins() {
1570e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (trailingMargins == null) {
1571e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                trailingMargins = new int[getCount() + 1];
1572e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1573e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!trailingMarginsValid) {
1574e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                computeMargins(false);
1575e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                trailingMarginsValid = true;
1576e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1577e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return trailingMargins;
1578e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1579e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
15805f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar        private boolean solve(int[] a) {
15815f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            return solve(getArcs(), a);
1582e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        }
1583e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
1584e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        private boolean computeHasWeights() {
1585e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
1586aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                final View child = getChildAt(i);
1587aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                if (child.getVisibility() == View.GONE) {
1588aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                    continue;
1589aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                }
1590aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                LayoutParams lp = getLayoutParams(child);
1591e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
1592e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                if (spec.weight != 0) {
1593e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                    return true;
1594e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                }
1595e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            }
1596e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            return false;
1597e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        }
1598e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
1599e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        private boolean hasWeights() {
1600e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            if (!hasWeightsValid) {
1601e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                hasWeights = computeHasWeights();
1602e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                hasWeightsValid = true;
1603e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            }
1604e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            return hasWeights;
1605e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        }
1606e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
1607e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        public int[] getDeltas() {
1608e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            if (deltas == null) {
1609e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                deltas = new int[getChildCount()];
1610e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            }
1611e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            return deltas;
1612e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        }
1613e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
16145f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar        private void shareOutDelta(int totalDelta, float totalWeight) {
16155f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            Arrays.fill(deltas, 0);
1616e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
1617aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                final View c = getChildAt(i);
1618aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                if (c.getVisibility() == View.GONE) {
1619aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                    continue;
1620aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                }
1621e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                LayoutParams lp = getLayoutParams(c);
1622e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
1623e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                float weight = spec.weight;
1624e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                if (weight != 0) {
1625e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                    int delta = Math.round((weight * totalDelta / totalWeight));
1626e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                    deltas[i] = delta;
16275f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                    // the two adjustments below are to counter the above rounding and avoid
16285f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                    // off-by-ones at the end
1629e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                    totalDelta -= delta;
1630e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                    totalWeight -= weight;
1631e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                }
1632e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            }
1633e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        }
1634e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
1635e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        private void solveAndDistributeSpace(int[] a) {
1636e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            Arrays.fill(getDeltas(), 0);
1637e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            solve(a);
16385f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            int deltaMax = parentMin.value * getChildCount() + 1; //exclusive
16395f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            if (deltaMax < 2) {
16405f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                return; //don't have any delta to distribute
16415f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            }
16425f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            int deltaMin = 0; //inclusive
16435f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar
16445f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            float totalWeight = calculateTotalWeight();
16455f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar
16465f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            int validDelta = -1; //delta for which a solution exists
16475f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            boolean validSolution = true;
16485f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            // do a binary search to find the max delta that won't conflict with constraints
16495f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            while(deltaMin < deltaMax) {
16505f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                final int delta = (deltaMin + deltaMax) / 2;
16515f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                invalidateValues();
16525f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                shareOutDelta(delta, totalWeight);
16535f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                validSolution = solve(getArcs(), a, false);
16545f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                if (validSolution) {
16555f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                    validDelta = delta;
16565f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                    deltaMin = delta + 1;
16575f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                } else {
16585f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                    deltaMax = delta;
16595f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                }
16605f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            }
16615f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            if (validDelta > 0 && !validSolution) {
16625f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                // last solution was not successful but we have a successful one. Use it.
16635f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                invalidateValues();
16645f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                shareOutDelta(validDelta, totalWeight);
16655f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                solve(a);
16665f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            }
16675f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar        }
16685f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar
16695f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar        private float calculateTotalWeight() {
16705f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            float totalWeight = 0f;
16715f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            for (int i = 0, N = getChildCount(); i < N; i++) {
16725f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                View c = getChildAt(i);
1673aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                if (c.getVisibility() == View.GONE) {
1674aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                    continue;
1675aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                }
16765f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                LayoutParams lp = getLayoutParams(c);
16775f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
16785f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar                totalWeight += spec.weight;
16795f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            }
16805f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar            return totalWeight;
1681e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        }
1682e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
1683e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        private void computeLocations(int[] a) {
1684e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            if (!hasWeights()) {
1685e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                solve(a);
1686e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            } else {
1687e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                solveAndDistributeSpace(a);
1688e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            }
1689e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!orderPreserved) {
1690e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                // Solve returns the smallest solution to the constraint system for which all
1691e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                // values are positive. One value is therefore zero - though if the row/col
1692e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                // order is not preserved this may not be the first vertex. For consistency,
1693e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                // translate all the values so that they measure the distance from a[0]; the
1694e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                // leading edge of the parent. After this transformation some values may be
1695e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                // negative.
1696e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int a0 = a[0];
1697e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                for (int i = 0, N = a.length; i < N; i++) {
1698e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    a[i] = a[i] - a0;
1699e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1700e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1701e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1702e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1703e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int[] getLocations() {
1704e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (locations == null) {
1705e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int N = getCount() + 1;
1706e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                locations = new int[N];
1707e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1708e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!locationsValid) {
1709e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                computeLocations(locations);
1710e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                locationsValid = true;
1711e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1712e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return locations;
1713e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1714e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1715e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private int size(int[] locations) {
1716e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // The parental edges are attached to vertices 0 and N - even when order is not
1717e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // being preserved and other vertices fall outside this range. Measure the distance
1718e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // between vertices 0 and N, assuming that locations[0] = 0.
1719e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return locations[getCount()];
1720e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1721e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1722e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void setParentConstraints(int min, int max) {
1723e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            parentMin.value = min;
1724e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            parentMax.value = -max;
1725e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            locationsValid = false;
1726e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1727e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1728e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private int getMeasure(int min, int max) {
1729e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            setParentConstraints(min, max);
1730e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return size(getLocations());
1731e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1732e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1733e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int getMeasure(int measureSpec) {
1734e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int mode = MeasureSpec.getMode(measureSpec);
1735e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int size = MeasureSpec.getSize(measureSpec);
1736e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            switch (mode) {
1737e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                case MeasureSpec.UNSPECIFIED: {
1738e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    return getMeasure(0, MAX_SIZE);
1739e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1740e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                case MeasureSpec.EXACTLY: {
1741e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    return getMeasure(size, size);
1742e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1743e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                case MeasureSpec.AT_MOST: {
1744e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    return getMeasure(0, size);
1745e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1746e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                default: {
1747e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    assert false;
1748e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    return 0;
1749e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
1750e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
1751e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1752e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1753e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public void layout(int size) {
1754e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            setParentConstraints(size, size);
1755e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            getLocations();
1756e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1757e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1758e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public void invalidateStructure() {
1759e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            maxIndex = UNDEFINED;
1760e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1761e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            groupBounds = null;
1762e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            forwardLinks = null;
1763e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            backwardLinks = null;
1764e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1765e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            leadingMargins = null;
1766e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            trailingMargins = null;
1767e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            arcs = null;
1768e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1769e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            locations = null;
1770e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1771e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            deltas = null;
1772e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            hasWeightsValid = false;
1773e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
1774e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            invalidateValues();
1775e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1776e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1777e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public void invalidateValues() {
1778e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            groupBoundsValid = false;
1779e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            forwardLinksValid = false;
1780e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            backwardLinksValid = false;
1781e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1782e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            leadingMarginsValid = false;
1783e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            trailingMarginsValid = false;
1784e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            arcsValid = false;
1785e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1786e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            locationsValid = false;
1787e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1788e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
1789e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1790e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
1791e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Layout information associated with each of the children of a GridLayout.
1792e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
1793e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * GridLayout supports both row and column spanning and arbitrary forms of alignment within
1794e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * each cell group. The fundamental parameters associated with each cell group are
1795e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * gathered into their vertical and horizontal components and stored
1796e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * in the {@link #rowSpec} and {@link #columnSpec} layout parameters.
1797e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link GridLayout.Spec Specs} are immutable structures
1798e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * and may be shared between the layout parameters of different children.
1799e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
1800e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The row and column specs contain the leading and trailing indices along each axis
1801e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * and together specify the four grid indices that delimit the cells of this cell group.
1802e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
1803e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The  alignment properties of the row and column specs together specify
1804e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * both aspects of alignment within the cell group. It is also possible to specify a child's
1805e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
1806e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * method.
1807e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * <p>
1808e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * The weight property is also included in Spec and specifies the proportion of any
1809e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * excess space that is due to the associated view.
1810e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
1811e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <h4>WRAP_CONTENT and MATCH_PARENT</h4>
1812e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
1813e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Because the default values of the {@link #width} and {@link #height}
1814e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * properties are both {@link #WRAP_CONTENT}, this value never needs to be explicitly
1815e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * declared in the layout parameters of GridLayout's children. In addition,
1816e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * GridLayout does not distinguish the special size value {@link #MATCH_PARENT} from
1817e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link #WRAP_CONTENT}. A component's ability to expand to the size of the parent is
1818e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * instead controlled by the principle of <em>flexibility</em>,
1819e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * as discussed in {@link GridLayout}.
1820e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
1821e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <h4>Summary</h4>
1822e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
1823e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * You should not need to use either of the special size values:
1824e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@code WRAP_CONTENT} or {@code MATCH_PARENT} when configuring the children of
1825e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * a GridLayout.
1826e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
1827e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <h4>Default values</h4>
1828e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
1829e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <ul>
1830e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #width} = {@link #WRAP_CONTENT}</li>
1831e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #height} = {@link #WRAP_CONTENT}</li>
1832e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #topMargin} = 0 when
1833e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
1834e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          {@code false}; otherwise {@link #UNDEFINED}, to
1835e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          indicate that a default value should be computed on demand. </li>
1836e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #leftMargin} = 0 when
1837e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
1838e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          {@code false}; otherwise {@link #UNDEFINED}, to
1839e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          indicate that a default value should be computed on demand. </li>
1840e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #bottomMargin} = 0 when
1841e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
1842e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          {@code false}; otherwise {@link #UNDEFINED}, to
1843e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          indicate that a default value should be computed on demand. </li>
1844e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #rightMargin} = 0 when
1845e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
1846e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          {@code false}; otherwise {@link #UNDEFINED}, to
1847e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *          indicate that a default value should be computed on demand. </li>
1848e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li>
1849e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li>
1850e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li>
1851e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *     <li>{@link #rowSpec}<code>.weight</code> = 0 </li>
1852e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li>
1853e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li>
1854e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li>
1855e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *     <li>{@link #columnSpec}<code>.weight</code> = 0 </li>
1856e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * </ul>
1857e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
1858e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * See {@link GridLayout} for a more complete description of the conventions
1859e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * used by GridLayout in the interpretation of the properties of this class.
1860e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
1861e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_Layout_layout_row
1862e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan
1863e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_rowWeight
1864e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_Layout_layout_column
1865e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan
1866e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_columnWeight
1867e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
1868e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
1869e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static class LayoutParams extends MarginLayoutParams {
1870e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1871e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Default values
1872e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1873e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int DEFAULT_WIDTH = WRAP_CONTENT;
1874e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int DEFAULT_HEIGHT = WRAP_CONTENT;
1875e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int DEFAULT_MARGIN = UNDEFINED;
1876e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int DEFAULT_ROW = UNDEFINED;
1877e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int DEFAULT_COLUMN = UNDEFINED;
1878e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final Interval DEFAULT_SPAN = new Interval(UNDEFINED, UNDEFINED + 1);
1879e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int DEFAULT_SPAN_SIZE = DEFAULT_SPAN.size();
1880e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1881e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // TypedArray indices
1882e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1883e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int MARGIN = R.styleable.GridLayout_Layout_android_layout_margin;
1884e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int LEFT_MARGIN = R.styleable.GridLayout_Layout_android_layout_marginLeft;
1885e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int TOP_MARGIN = R.styleable.GridLayout_Layout_android_layout_marginTop;
1886e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int RIGHT_MARGIN = R.styleable.GridLayout_Layout_android_layout_marginRight;
1887e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int BOTTOM_MARGIN = R.styleable.GridLayout_Layout_android_layout_marginBottom;
1888e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1889e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
1890e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
1891e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight;
1892e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1893e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int ROW = R.styleable.GridLayout_Layout_layout_row;
1894e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan;
1895e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        private static final int ROW_WEIGHT = R.styleable.GridLayout_Layout_layout_rowWeight;
1896e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1897e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity;
1898e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1899e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Instance variables
1900e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1901e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
1902e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * The spec that defines the vertical characteristics of the cell group
1903e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * described by these layout parameters.
1904e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * If an assignment is made to this field after a measurement or layout operation
1905e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * has already taken place, a call to
1906e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
1907e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * must be made to notify GridLayout of the change. GridLayout is normally able
1908e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * to detect when code fails to observe this rule, issue a warning and take steps to
1909e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * compensate for the omission. This facility is implemented on a best effort basis
1910e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * and should not be relied upon in production code - so it is best to include the above
1911e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * calls to remove the warnings as soon as it is practical.
1912e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
1913e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public Spec rowSpec = Spec.UNDEFINED;
1914e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1915e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
1916e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * The spec that defines the horizontal characteristics of the cell group
1917e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * described by these layout parameters.
1918e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * If an assignment is made to this field after a measurement or layout operation
1919e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * has already taken place, a call to
1920e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
1921e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * must be made to notify GridLayout of the change. GridLayout is normally able
1922e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * to detect when code fails to observe this rule, issue a warning and take steps to
1923e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * compensate for the omission. This facility is implemented on a best effort basis
1924e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * and should not be relied upon in production code - so it is best to include the above
1925e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * calls to remove the warnings as soon as it is practical.
1926e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
1927e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public Spec columnSpec = Spec.UNDEFINED;
1928e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1929e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Constructors
1930e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1931e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private LayoutParams(
1932e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int width, int height,
1933e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int left, int top, int right, int bottom,
1934e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Spec rowSpec, Spec columnSpec) {
1935e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            super(width, height);
1936e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            setMargins(left, top, right, bottom);
1937e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.rowSpec = rowSpec;
1938e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.columnSpec = columnSpec;
1939e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1940e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1941e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
1942e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * Constructs a new LayoutParams instance for this <code>rowSpec</code>
1943e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * and <code>columnSpec</code>. All other fields are initialized with
1944e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * default values as defined in {@link LayoutParams}.
1945e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
1946e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param rowSpec    the rowSpec
1947e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param columnSpec the columnSpec
1948e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
1949e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public LayoutParams(Spec rowSpec, Spec columnSpec) {
1950e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
1951e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
1952e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    rowSpec, columnSpec);
1953e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1954e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1955e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
1956e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
1957e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
1958e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public LayoutParams() {
1959e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this(Spec.UNDEFINED, Spec.UNDEFINED);
1960e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1961e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1962e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Copying constructors
1963e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1964e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
1965e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * {@inheritDoc}
1966e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
1967e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public LayoutParams(ViewGroup.LayoutParams params) {
1968e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            super(params);
1969e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1970e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1971e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
1972e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * {@inheritDoc}
1973e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
1974e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public LayoutParams(MarginLayoutParams params) {
1975e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            super(params);
1976e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1977e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1978e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
1979e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne         * Copy constructor. Clones the width, height, margin values, row spec,
1980e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne         * and column spec of the source.
1981e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne         *
1982e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne         * @param source The layout params to copy from.
1983e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
1984e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        public LayoutParams(LayoutParams source) {
1985e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            super(source);
1986e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
1987e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            this.rowSpec = source.rowSpec;
1988e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            this.columnSpec = source.columnSpec;
1989e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
1990e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1991e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // AttributeSet constructors
1992e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
1993e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
1994e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * {@inheritDoc}
1995e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
1996e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * Values not defined in the attribute set take the default values
1997e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * defined in {@link LayoutParams}.
1998e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
1999e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public LayoutParams(Context context, AttributeSet attrs) {
2000e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            super(context, attrs);
2001e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            reInitSuper(context, attrs);
2002e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            init(context, attrs);
2003e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2004e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2005e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Implementation
2006e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2007e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Reinitialise the margins using a different default policy than MarginLayoutParams.
2008e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // Here we use the value UNDEFINED (as distinct from zero) to represent the undefined state
2009e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // so that a layout manager default can be accessed post set up. We need this as, at the
2010e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // point of installation, we do not know how many rows/cols there are and therefore
2011e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // which elements are positioned next to the container's trailing edges. We need to
2012e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // know this as margins around the container's boundary should have different
2013e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // defaults to those between peers.
2014e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2015e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        // This method could be parametrized and moved into MarginLayout.
2016e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void reInitSuper(Context context, AttributeSet attrs) {
2017e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            TypedArray a =
2018e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout);
2019e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            try {
2020e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN);
2021e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2022e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                this.leftMargin = a.getDimensionPixelSize(LEFT_MARGIN, margin);
2023e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                this.topMargin = a.getDimensionPixelSize(TOP_MARGIN, margin);
2024e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                this.rightMargin = a.getDimensionPixelSize(RIGHT_MARGIN, margin);
2025e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                this.bottomMargin = a.getDimensionPixelSize(BOTTOM_MARGIN, margin);
2026e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            } finally {
2027e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                a.recycle();
2028e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2029e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2030e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2031e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private void init(Context context, AttributeSet attrs) {
2032e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout);
2033e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            try {
2034e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int gravity = a.getInt(GRAVITY, Gravity.NO_GRAVITY);
2035e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2036e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int column = a.getInt(COLUMN, DEFAULT_COLUMN);
2037e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int colSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
2038e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                float colWeight = a.getFloat(COLUMN_WEIGHT, Spec.DEFAULT_WEIGHT);
2039e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                this.columnSpec = spec(column, colSpan, getAlignment(gravity, true), colWeight);
2040e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2041e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int row = a.getInt(ROW, DEFAULT_ROW);
2042e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
2043e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                float rowWeight = a.getFloat(ROW_WEIGHT, Spec.DEFAULT_WEIGHT);
2044e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne                this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false), rowWeight);
2045e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            } finally {
2046e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                a.recycle();
2047e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2048e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2049e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2050e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
2051e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}.
2052e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * See {@link Gravity}.
2053e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
2054e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param gravity the new gravity value
2055e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
2056e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
2057e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
2058e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public void setGravity(int gravity) {
2059e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            rowSpec = rowSpec.copyWriteAlignment(getAlignment(gravity, false));
2060e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            columnSpec = columnSpec.copyWriteAlignment(getAlignment(gravity, true));
2061e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2062e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2063e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2064e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        protected void setBaseAttributes(TypedArray attributes, int widthAttr, int heightAttr) {
2065e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.width = attributes.getLayoutDimension(widthAttr, DEFAULT_WIDTH);
2066e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT);
2067e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2068e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2069e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        final void setRowSpecSpan(Interval span) {
2070e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            rowSpec = rowSpec.copyWriteSpan(span);
2071e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2072e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2073e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        final void setColumnSpecSpan(Interval span) {
2074e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            columnSpec = columnSpec.copyWriteSpan(span);
2075e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2076e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2077e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2078e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean equals(Object o) {
2079e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (this == o) return true;
2080e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (o == null || getClass() != o.getClass()) return false;
2081e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2082e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            LayoutParams that = (LayoutParams) o;
2083e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2084e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!columnSpec.equals(that.columnSpec)) return false;
2085e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!rowSpec.equals(that.rowSpec)) return false;
2086e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2087e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return true;
2088e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2089e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2090e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2091e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int hashCode() {
2092e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int result = rowSpec.hashCode();
2093e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            result = 31 * result + columnSpec.hashCode();
2094e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return result;
2095e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2096e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2097e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2098e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /*
2099e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs.
2100e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles.
2101e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2102e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    final static class Arc {
2103e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public final Interval span;
2104e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public final MutableInt value;
2105e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean valid = true;
2106e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2107e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public Arc(Interval span, MutableInt value) {
2108e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.span = span;
2109e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.value = value;
2110e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2111e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2112e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2113e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public String toString() {
2114e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return span + " " + (!valid ? "+>" : "->") + " " + value;
2115e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2116e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2117e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2118e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    // A mutable Integer - used to avoid heap allocation during the layout operation
2119e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2120e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    final static class MutableInt {
2121e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int value;
2122e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2123e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public MutableInt() {
2124e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            reset();
2125e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2126e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2127e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public MutableInt(int value) {
2128e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.value = value;
2129e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2130e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2131e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public void reset() {
2132e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            value = Integer.MIN_VALUE;
2133e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2134e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2135e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2136e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public String toString() {
2137e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return Integer.toString(value);
2138e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2139e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2140e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2141e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    final static class Assoc<K, V> extends ArrayList<Pair<K, V>> {
2142e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private final Class<K> keyType;
2143e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private final Class<V> valueType;
2144e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2145e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private Assoc(Class<K> keyType, Class<V> valueType) {
2146e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.keyType = keyType;
2147e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.valueType = valueType;
2148e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2149e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2150e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) {
2151e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return new Assoc<K, V>(keyType, valueType);
2152e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2153e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2154e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public void put(K key, V value) {
2155e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            add(Pair.create(key, value));
2156e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2157e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2158e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @SuppressWarnings(value = "unchecked")
2159e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public PackedMap<K, V> pack() {
2160e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int N = size();
2161e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            K[] keys = (K[]) Array.newInstance(keyType, N);
2162e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            V[] values = (V[]) Array.newInstance(valueType, N);
2163e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0; i < N; i++) {
2164e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                keys[i] = get(i).first;
2165e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                values[i] = get(i).second;
2166e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2167e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return new PackedMap<K, V>(keys, values);
2168e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2169e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2170e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2171e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /*
2172e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    This data structure is used in place of a Map where we have an index that refers to the order
2173e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    in which each key/value pairs were added to the map. In this case we store keys and values
2174e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    in arrays of a length that is equal to the number of unique keys. We also maintain an
2175e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    array of indexes from insertion order to the compacted arrays of keys and values.
2176e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2177e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    Note that behavior differs from that of a LinkedHashMap in that repeated entries
2178e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    *do* get added multiples times. So the length of index is equals to the number of
2179e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    items added.
2180e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2181e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    This is useful in the GridLayout class where we can rely on the order of children not
2182e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    changing during layout - to use integer-based lookup for our internal structures
2183e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    rather than using (and storing) an implementation of Map<Key, ?>.
2184e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2185e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    @SuppressWarnings(value = "unchecked")
2186e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    final static class PackedMap<K, V> {
2187e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public final int[] index;
2188e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public final K[] keys;
2189e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public final V[] values;
2190e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2191e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private PackedMap(K[] keys, V[] values) {
2192e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.index = createIndex(keys);
2193e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2194e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.keys = compact(keys, index);
2195e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.values = compact(values, index);
2196e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2197e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2198e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public V getValue(int i) {
2199e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return values[index[i]];
2200e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2201e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2202e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static <K> int[] createIndex(K[] keys) {
2203e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int size = keys.length;
2204e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int[] result = new int[size];
2205e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2206e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Map<K, Integer> keyToIndex = new HashMap<K, Integer>();
2207e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0; i < size; i++) {
2208e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                K key = keys[i];
2209e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                Integer index = keyToIndex.get(key);
2210e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                if (index == null) {
2211e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    index = keyToIndex.size();
2212e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    keyToIndex.put(key, index);
2213e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
2214e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                result[i] = index;
2215e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2216e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return result;
2217e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2218e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2219e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /*
2220e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        Create a compact array of keys or values using the supplied index.
2221e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
2222e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private static <K> K[] compact(K[] a, int[] index) {
2223e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int size = a.length;
2224e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Class<?> componentType = a.getClass().getComponentType();
2225e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            K[] result = (K[]) Array.newInstance(componentType, max2(index, -1) + 1);
2226e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2227e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // this overwrite duplicates, retaining the last equivalent entry
2228e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            for (int i = 0; i < size; i++) {
2229e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                result[index[i]] = a[i];
2230e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2231e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return result;
2232e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2233e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2234e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2235e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /*
2236e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    For each group (with a given alignment) we need to store the amount of space required
2237e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    before the alignment point and the amount of space required after it. One side of this
2238e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    calculation is always 0 for START and END alignments but we don't make use of this.
2239e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
2240e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    simple optimisations are possible.
2241e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2242e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    The general algorithm therefore is to create a Map (actually a PackedMap) from
2243e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    group to Bounds and to loop through all Views in the group taking the maximum
2244e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    of the values for each View.
2245e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    */
2246e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    static class Bounds {
2247e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int before;
2248e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int after;
2249e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int flexibility; // we're flexible iff all included specs are flexible
2250e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2251e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        private Bounds() {
2252e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            reset();
2253e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2254e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2255e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        protected void reset() {
2256e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            before = Integer.MIN_VALUE;
2257e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            after = Integer.MIN_VALUE;
2258e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            flexibility = CAN_STRETCH; // from the above, we're flexible when empty
2259e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2260e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2261e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        protected void include(int before, int after) {
2262e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.before = max(this.before, before);
2263e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.after = max(this.after, after);
2264e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2265e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2266e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        protected int size(boolean min) {
2267e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!min) {
2268e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                if (canStretch(flexibility)) {
2269e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    return MAX_SIZE;
2270e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
2271e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2272e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return before + after;
2273e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2274e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
22752c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
2276b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            return before - a.getAlignmentValue(c, size, ViewGroupCompat.getLayoutMode(gl));
2277e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2278e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2279e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        protected final void include(GridLayout gl, View c, Spec spec, Axis axis, int size) {
2280e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.flexibility &= spec.getFlexibility();
22812c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            boolean horizontal = axis.horizontal;
2282aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            Alignment alignment = spec.getAbsoluteAlignment(horizontal);
2283e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            // todo test this works correctly when the returned value is UNDEFINED
2284b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell            int before = alignment.getAlignmentValue(c, size, ViewGroupCompat.getLayoutMode(gl));
2285e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            include(before, size - before);
2286e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2287e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2288e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2289e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public String toString() {
2290e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return "Bounds{" +
2291e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    "before=" + before +
2292e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    ", after=" + after +
2293e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    '}';
2294e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2295e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2296e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2297e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2298e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * An Interval represents a contiguous range of values that lie between
2299e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * the interval's {@link #min} and {@link #max} values.
2300e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
2301e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Intervals are immutable so may be passed as values and used as keys in hash tables.
2302e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * It is not necessary to have multiple instances of Intervals which have the same
2303e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link #min} and {@link #max} values.
2304e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
2305e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Intervals are often written as {@code [min, max]} and represent the set of values
2306e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@code x} such that {@code min <= x < max}.
2307e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2308e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    final static class Interval {
2309e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
2310e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * The minimum value.
2311e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
2312e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public final int min;
2313e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2314e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
2315e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * The maximum value.
2316e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
2317e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public final int max;
2318e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2319e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
2320e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * Construct a new Interval, {@code interval}, where:
2321e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * <ul>
2322e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *     <li> {@code interval.min = min} </li>
2323e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *     <li> {@code interval.max = max} </li>
2324e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * </ul>
2325e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
2326e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param min the minimum value.
2327e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param max the maximum value.
2328e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
2329e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public Interval(int min, int max) {
2330e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.min = min;
2331e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.max = max;
2332e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2333e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2334e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int size() {
2335e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return max - min;
2336e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2337e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2338e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        Interval inverse() {
2339e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return new Interval(max, min);
2340e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2341e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2342e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
2343e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * Returns {@code true} if the {@link #getClass class},
2344e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * {@link #min} and {@link #max} properties of this Interval and the
2345e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * supplied parameter are pairwise equal; {@code false} otherwise.
2346e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
2347e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param that the object to compare this interval with
2348e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
2349e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @return {@code true} if the specified object is equal to this
2350e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *         {@code Interval}, {@code false} otherwise.
2351e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
2352e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2353e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean equals(Object that) {
2354e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (this == that) {
2355e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return true;
2356e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2357e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (that == null || getClass() != that.getClass()) {
2358e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return false;
2359e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2360e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2361e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Interval interval = (Interval) that;
2362e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2363e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (max != interval.max) {
2364e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return false;
2365e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2366e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            //noinspection RedundantIfStatement
2367e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (min != interval.min) {
2368e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return false;
2369e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2370e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2371e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return true;
2372e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2373e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2374e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2375e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int hashCode() {
2376e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int result = min;
2377e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            result = 31 * result + max;
2378e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return result;
2379e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2380e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2381e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2382e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public String toString() {
2383e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return "[" + min + ", " + max + "]";
2384e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2385e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2386e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2387e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2388e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * A Spec defines the horizontal or vertical characteristics of a group of
2389e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * cells. Each spec. defines the <em>grid indices</em> and <em>alignment</em>
2390e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * along the appropriate axis.
2391e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
2392e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The <em>grid indices</em> are the leading and trailing edges of this cell group.
2393e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * See {@link GridLayout} for a description of the conventions used by GridLayout
2394e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * for grid indices.
2395e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
2396e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The <em>alignment</em> property specifies how cells should be aligned in this group.
2397e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * For row groups, this specifies the vertical alignment.
2398e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * For column groups, this specifies the horizontal alignment.
2399e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
2400e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Use the following static methods to create specs:
2401e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <ul>
2402e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *   <li>{@link #spec(int)}</li>
2403e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *   <li>{@link #spec(int, int)}</li>
2404e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *   <li>{@link #spec(int, Alignment)}</li>
2405e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *   <li>{@link #spec(int, int, Alignment)}</li>
2406e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *   <li>{@link #spec(int, float)}</li>
2407e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *   <li>{@link #spec(int, int, float)}</li>
2408e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *   <li>{@link #spec(int, Alignment, float)}</li>
2409e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *   <li>{@link #spec(int, int, Alignment, float)}</li>
2410e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * </ul>
2411e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
2412e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2413e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static class Spec {
2414e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        static final Spec UNDEFINED = spec(GridLayout.UNDEFINED);
2415e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        static final float DEFAULT_WEIGHT = 0;
2416e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2417e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        final boolean startDefined;
2418e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        final Interval span;
2419e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        final Alignment alignment;
2420e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        final float weight;
2421e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2422e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        private Spec(boolean startDefined, Interval span, Alignment alignment, float weight) {
2423e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.startDefined = startDefined;
2424e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.span = span;
2425e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            this.alignment = alignment;
2426e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            this.weight = weight;
2427e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2428e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2429e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        private Spec(boolean startDefined, int start, int size, Alignment alignment, float weight) {
2430e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            this(startDefined, new Interval(start, start + size), alignment, weight);
2431e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2432e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2433aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        public Alignment getAbsoluteAlignment(boolean horizontal) {
2434aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            if (alignment != UNDEFINED_ALIGNMENT) {
2435aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                return alignment;
2436aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            }
2437aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            if (weight == 0f) {
2438aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                return horizontal ? START : BASELINE;
2439aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            }
2440aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            return FILL;
2441aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        }
2442aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar
2443e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        final Spec copyWriteSpan(Interval span) {
2444e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            return new Spec(startDefined, span, alignment, weight);
2445e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2446e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2447e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        final Spec copyWriteAlignment(Alignment alignment) {
2448e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            return new Spec(startDefined, span, alignment, weight);
2449e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2450e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2451e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        final int getFlexibility() {
2452e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne            return (alignment == UNDEFINED_ALIGNMENT && weight == 0) ? INFLEXIBLE : CAN_STRETCH;
2453e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2454e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2455e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
2456e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * Returns {@code true} if the {@code class}, {@code alignment} and {@code span}
2457e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * properties of this Spec and the supplied parameter are pairwise equal,
2458e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * {@code false} otherwise.
2459e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
2460e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param that the object to compare this spec with
2461e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
2462e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @return {@code true} if the specified object is equal to this
2463e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *         {@code Spec}; {@code false} otherwise
2464e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
2465e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2466e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public boolean equals(Object that) {
2467e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (this == that) {
2468e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return true;
2469e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2470e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (that == null || getClass() != that.getClass()) {
2471e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return false;
2472e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2473e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2474e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            Spec spec = (Spec) that;
2475e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2476e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!alignment.equals(spec.alignment)) {
2477e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return false;
2478e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2479e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            //noinspection RedundantIfStatement
2480e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            if (!span.equals(spec.span)) {
2481e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                return false;
2482e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2483e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2484e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return true;
2485e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2486e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2487e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2488e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int hashCode() {
2489e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int result = span.hashCode();
2490e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            result = 31 * result + alignment.hashCode();
2491e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return result;
2492e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2493e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2494e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2495e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2496e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Return a Spec, {@code spec}, where:
2497e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <ul>
2498e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li> {@code spec.span = [start, start + size]} </li>
2499e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li> {@code spec.alignment = alignment} </li>
2500e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *     <li> {@code spec.weight = weight} </li>
2501e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * </ul>
25022c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * <p>
25032c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * To leave the start index undefined, use the value {@link #UNDEFINED}.
2504e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
2505e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param start     the start
2506e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param size      the size
2507e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param alignment the alignment
2508e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param weight    the weight
2509e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     */
2510e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    public static Spec spec(int start, int size, Alignment alignment, float weight) {
2511e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        return new Spec(start != UNDEFINED, start, size, alignment, weight);
2512e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    }
2513e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
2514e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    /**
2515e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * Equivalent to: {@code spec(start, 1, alignment, weight)}.
2516e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *
2517e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param start     the start
2518e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param alignment the alignment
2519e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param weight    the weight
2520e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     */
2521e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    public static Spec spec(int start, Alignment alignment, float weight) {
2522e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        return spec(start, 1, alignment, weight);
2523e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    }
2524e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
2525e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    /**
2526e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * Equivalent to: {@code spec(start, 1, default_alignment, weight)} -
2527e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * where {@code default_alignment} is specified in
2528e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * {@link android.widget.GridLayout.LayoutParams}.
2529e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *
2530e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param start  the start
2531e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param size   the size
2532e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param weight the weight
2533e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     */
2534e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    public static Spec spec(int start, int size, float weight) {
2535e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        return spec(start, size, UNDEFINED_ALIGNMENT, weight);
2536e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    }
2537e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
2538e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    /**
2539e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * Equivalent to: {@code spec(start, 1, weight)}.
2540e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *
2541e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param start  the start
2542e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param weight the weight
2543e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     */
2544e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    public static Spec spec(int start, float weight) {
2545e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        return spec(start, 1, weight);
2546e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    }
2547e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne
2548e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne    /**
2549e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * Equivalent to: {@code spec(start, size, alignment, 0f)}.
2550e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     *
2551e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param start     the start
2552e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param size      the size
2553e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne     * @param alignment the alignment
2554e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2555e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static Spec spec(int start, int size, Alignment alignment) {
2556e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne        return spec(start, size, alignment, Spec.DEFAULT_WEIGHT);
2557e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2558e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2559e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2560e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Return a Spec, {@code spec}, where:
2561e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <ul>
2562e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li> {@code spec.span = [start, start + 1]} </li>
2563e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li> {@code spec.alignment = alignment} </li>
2564e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * </ul>
25652c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * <p>
25662c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * To leave the start index undefined, use the value {@link #UNDEFINED}.
2567e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
2568e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param start     the start index
2569e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param alignment the alignment
25702c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *
25712c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * @see #spec(int, int, Alignment)
2572e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2573e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static Spec spec(int start, Alignment alignment) {
2574e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return spec(start, 1, alignment);
2575e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2576e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2577e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2578e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Return a Spec, {@code spec}, where:
2579e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <ul>
2580e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li> {@code spec.span = [start, start + size]} </li>
2581e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * </ul>
25822c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * <p>
25832c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * To leave the start index undefined, use the value {@link #UNDEFINED}.
2584e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
2585e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param start     the start
2586e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param size      the size
25872c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *
25882c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * @see #spec(int, Alignment)
2589e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2590e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static Spec spec(int start, int size) {
2591e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return spec(start, size, UNDEFINED_ALIGNMENT);
2592e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2593e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2594e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2595e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Return a Spec, {@code spec}, where:
2596e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <ul>
2597e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *     <li> {@code spec.span = [start, start + 1]} </li>
2598e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * </ul>
25992c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * <p>
26002c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * To leave the start index undefined, use the value {@link #UNDEFINED}.
2601e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
2602e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @param start     the start index
26032c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     *
26042c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio     * @see #spec(int, int)
2605e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2606e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static Spec spec(int start) {
2607e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return spec(start, 1);
2608e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2609e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2610e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2611e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Alignments specify where a view should be placed within a cell group and
2612e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * what size it should be.
2613e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
2614e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec}
2615e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an
2616e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@code alignment}. Overall placement of the view in the cell
2617e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * group is specified by the two alignments which act along each axis independently.
2618e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
2619e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *  The GridLayout class defines the most common alignments used in general layout:
2620e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #START},
2621e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link #END}, {@link #CENTER}, {@link #BASELINE} and {@link #FILL}.
2622e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2623e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /*
2624e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)},
2625e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * to return the appropriate value for the type of alignment being defined.
2626e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * The enclosing algorithms position the children
2627e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * so that the locations defined by the alignment values
2628e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * are the same for all of the views in a group.
2629e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * <p>
2630e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2631e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static abstract class Alignment {
2632e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        Alignment() {
2633e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2634e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2635e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        abstract int getGravityOffset(View view, int cellDelta);
2636e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2637e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
2638e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * Returns an alignment value. In the case of vertical alignments the value
2639e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * returned should indicate the distance from the top of the view to the
2640e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * alignment location.
2641e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * For horizontal alignments measurement is made from the left edge of the component.
2642e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
2643e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param view              the view to which this alignment should be applied
2644e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param viewSize          the measured size of the view
26452c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio         * @param mode              the basis of alignment: CLIP or OPTICAL
2646e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @return the alignment value
2647e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
26482c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        abstract int getAlignmentValue(View view, int viewSize, int mode);
2649e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2650e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        /**
2651e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * Returns the size of the view specified by this alignment.
2652e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * In the case of vertical alignments this method should return a height; for
2653e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * horizontal alignments this method should return the width.
2654e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * <p>
2655e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * The default implementation returns {@code viewSize}.
2656e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         *
2657e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param view              the view to which this alignment should be applied
2658e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param viewSize          the measured size of the view
2659e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @param cellSize          the size of the cell into which this view will be placed
2660e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         * @return the aligned size
2661e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet         */
2662e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int getSizeInCell(View view, int viewSize, int cellSize) {
2663e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return viewSize;
2664e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2665e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2666e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        Bounds getBounds() {
2667e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return new Bounds();
2668e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2669aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar
2670aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        abstract String getDebugString();
2671aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar
2672aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        @Override
2673aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        public String toString() {
2674aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            return "Alignment:" + getDebugString();
2675aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        }
2676e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2677e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2678e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    static final Alignment UNDEFINED_ALIGNMENT = new Alignment() {
2679e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2680e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int getGravityOffset(View view, int cellDelta) {
2681e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return UNDEFINED;
2682e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2683e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2684e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
26852c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        public int getAlignmentValue(View view, int viewSize, int mode) {
2686e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return UNDEFINED;
2687e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2688aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar
2689aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        @Override
2690aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        String getDebugString() {
2691aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            return "UNDEFINED";
2692aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        }
2693e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    };
2694e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2695e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2696e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should be aligned with the <em>start</em>
2697e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * edges of the other views in its cell group.
2698e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2699e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final Alignment LEADING = new Alignment() {
2700e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2701e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int getGravityOffset(View view, int cellDelta) {
2702e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return 0;
2703e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2704e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2705e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
27062c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        public int getAlignmentValue(View view, int viewSize, int mode) {
2707e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return 0;
2708e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2709aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar
2710aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        @Override
2711aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        String getDebugString() {
2712aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            return "LEADING";
2713aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        }
2714e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    };
2715e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2716e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2717e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should be aligned with the <em>end</em>
2718e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * edges of the other views in its cell group.
2719e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2720e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final Alignment TRAILING = new Alignment() {
2721e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2722e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int getGravityOffset(View view, int cellDelta) {
2723e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return cellDelta;
2724e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2725e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2726e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
27272c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        public int getAlignmentValue(View view, int viewSize, int mode) {
2728e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return viewSize;
2729e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2730aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar
2731aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        @Override
2732aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        String getDebugString() {
2733aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            return "TRAILING";
2734aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        }
2735e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    };
2736e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2737e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2738e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should be aligned with the <em>top</em>
2739e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * edges of the other views in its cell group.
2740e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2741e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final Alignment TOP = LEADING;
2742e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2743e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2744e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should be aligned with the <em>bottom</em>
2745e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * edges of the other views in its cell group.
2746e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2747e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final Alignment BOTTOM = TRAILING;
2748e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2749e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2750e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should be aligned with the <em>start</em>
2751e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * edges of the other views in its cell group.
2752e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2753e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final Alignment START = LEADING;
2754e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2755e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2756e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should be aligned with the <em>end</em>
2757e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * edges of the other views in its cell group.
2758e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2759e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final Alignment END = TRAILING;
2760e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2761e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static Alignment createSwitchingAlignment(final Alignment ltr, final Alignment rtl) {
2762e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return new Alignment() {
2763e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            @Override
2764e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int getGravityOffset(View view, int cellDelta) {
2765b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell                boolean isLayoutRtl = ViewCompat.getLayoutDirection(view) ==
2766b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell                        ViewCompat.LAYOUT_DIRECTION_RTL;
2767b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell                return (!isLayoutRtl ? ltr : rtl).getGravityOffset(view, cellDelta);
2768e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2769e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2770e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            @Override
27712c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            public int getAlignmentValue(View view, int viewSize, int mode) {
2772b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell                boolean isLayoutRtl = ViewCompat.getLayoutDirection(view) ==
2773b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell                        ViewCompat.LAYOUT_DIRECTION_RTL;
2774b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell                return (!isLayoutRtl ? ltr : rtl).getAlignmentValue(view, viewSize, mode);
2775e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            }
2776aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar
2777aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            @Override
2778aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            String getDebugString() {
2779aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar                return "SWITCHING[L:" + ltr.getDebugString() + ", R:" + rtl.getDebugString() + "]";
2780aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            }
2781e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        };
2782e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2783e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2784e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2785e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should be aligned with the <em>left</em>
2786e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * edges of the other views in its cell group.
2787e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2788e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final Alignment LEFT = createSwitchingAlignment(START, END);
2789e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2790e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2791e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should be aligned with the <em>right</em>
2792e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * edges of the other views in its cell group.
2793e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2794e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final Alignment RIGHT = createSwitchingAlignment(END, START);
2795e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2796e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2797e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should be <em>centered</em> with the other views in its cell group.
2798e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link
2799e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * LayoutParams#columnSpec columnSpecs}.
2800e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2801e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final Alignment CENTER = new Alignment() {
2802e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2803e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int getGravityOffset(View view, int cellDelta) {
2804e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return cellDelta >> 1;
2805e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2806e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2807e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
28082c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        public int getAlignmentValue(View view, int viewSize, int mode) {
2809e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return viewSize >> 1;
2810e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2811aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar
2812aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        @Override
2813aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        String getDebugString() {
2814aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            return "CENTER";
2815aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        }
2816e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    };
2817e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2818e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2819e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should be aligned with the <em>baselines</em>
2820e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * of the other views in its cell group.
2821e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}.
2822e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     *
2823e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * @see View#getBaseline()
2824e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2825e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final Alignment BASELINE = new Alignment() {
2826e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2827e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int getGravityOffset(View view, int cellDelta) {
2828e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return 0; // baseline gravity is top
2829e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2830e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2831e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
28322c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        public int getAlignmentValue(View view, int viewSize, int mode) {
28332c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            if (view.getVisibility() == GONE) {
28342c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                return 0;
28352c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            }
2836e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            int baseline = view.getBaseline();
28372c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio            return baseline == -1 ? UNDEFINED : baseline;
2838e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2839e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2840e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2841e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public Bounds getBounds() {
2842e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return new Bounds() {
2843e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                /*
2844e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                In a baseline aligned row in which some components define a baseline
2845e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                and some don't, we need a third variable to properly account for all
2846e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                the sizes. This tracks the maximum size of all the components -
2847e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                including those that don't define a baseline.
2848e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                */
2849e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                private int size;
2850e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2851e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                @Override
2852e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                protected void reset() {
2853e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    super.reset();
2854e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    size = Integer.MIN_VALUE;
2855e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
2856e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2857e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                @Override
2858e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                protected void include(int before, int after) {
2859e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    super.include(before, after);
2860e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    size = max(size, before + after);
2861e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
2862e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2863e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                @Override
2864e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                protected int size(boolean min) {
2865e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                    return max(super.size(min), size);
2866e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
2867e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2868e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                @Override
28692c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) {
28702c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio                    return max(0, super.getOffset(gl, c, a, size, hrz));
2871e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet                }
2872e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            };
2873e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2874aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar
2875aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        @Override
2876aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        String getDebugString() {
2877aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            return "BASELINE";
2878aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        }
2879e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    };
2880e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2881e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    /**
2882e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * Indicates that a view should expanded to fit the boundaries of its cell group.
2883e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and
2884e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     * {@link LayoutParams#columnSpec columnSpecs}.
2885e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet     */
2886e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    public static final Alignment FILL = new Alignment() {
2887e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2888e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        int getGravityOffset(View view, int cellDelta) {
2889e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return 0;
2890e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2891e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2892e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
28932c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio        public int getAlignmentValue(View view, int viewSize, int mode) {
2894e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return UNDEFINED;
2895e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2896e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2897e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        @Override
2898e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        public int getSizeInCell(View view, int viewSize, int cellSize) {
2899e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet            return cellSize;
2900e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        }
2901aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar
2902aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        @Override
2903aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        String getDebugString() {
2904aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar            return "FILL";
2905aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar        }
2906e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    };
2907e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2908e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    static boolean canStretch(int flexibility) {
2909e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet        return (flexibility & CAN_STRETCH) != 0;
2910e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    }
2911e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet
2912e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int INFLEXIBLE = 0;
2913e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet    private static final int CAN_STRETCH = 2;
2914e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet}
2915