13f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/*
23f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Copyright (C) 2011 The Android Open Source Project
33f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
43f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Licensed under the Apache License, Version 2.0 (the "License");
53f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * you may not use this file except in compliance with the License.
63f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * You may obtain a copy of the License at
73f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
83f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *      http://www.apache.org/licenses/LICENSE-2.0
93f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Unless required by applicable law or agreed to in writing, software
113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * distributed under the License is distributed on an "AS IS" BASIS,
123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See the License for the specific language governing permissions and
143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * limitations under the License.
153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */
163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepackage android.widget;
183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.content.Context;
203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.content.res.TypedArray;
213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Canvas;
223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Color;
231557fd7809078e421f751efc7d2539b3efdc54b2Philip Milneimport android.graphics.Insets;
243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Paint;
253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.AttributeSet;
263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.Log;
27211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milneimport android.util.LogPrinter;
2848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milneimport android.util.Pair;
29211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milneimport android.util.Printer;
303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.Gravity;
313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.View;
323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.ViewGroup;
338a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
348a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
35edd69518ffec87fb7b1931e708678ef441152cdePhilip Milneimport android.widget.RemoteViews.RemoteView;
3610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milneimport com.android.internal.R;
373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.lang.reflect.Array;
393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.ArrayList;
403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Arrays;
413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.HashMap;
423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.List;
433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Map;
443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
455125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milneimport static android.view.Gravity.*;
46899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.EXACTLY;
47899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.makeMeasureSpec;
483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.max;
493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.min;
503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/**
523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * A layout that places its children in a rectangular <em>grid</em>.
533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p>
543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The grid is composed of a set of infinitely thin lines that separate the
553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * viewing area into <em>cells</em>. Throughout the API, grid lines are referenced
567fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * by grid <em>indices</em>. A grid with {@code N} columns
577fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * has {@code N + 1} grid indices that run from {@code 0}
587fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * through {@code N} inclusive. Regardless of how GridLayout is
597fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * configured, grid index {@code 0} is fixed to the leading edge of the
607fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * container and grid index {@code N} is fixed to its trailing edge
613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * (after padding is taken into account).
623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
6393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <h4>Row and Column Specs</h4>
643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Children occupy one or more contiguous cells, as defined
6693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and
6793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters.
6893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Each spec defines the set of rows or columns that are to be
693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * occupied; and how children should be aligned within the resulting group of cells.
703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Although cells do not normally overlap in a GridLayout, GridLayout does
713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * not prevent children being defined to occupy the same cell or group of cells.
723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * In this case however, there is no guarantee that children will not themselves
733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * overlap after the layout operation completes.
743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Default Cell Assignment</h4>
763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
7748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne * If a child does not specify the row and column indices of the cell it
783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * wishes to occupy, GridLayout assigns cell locations automatically using its:
793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setOrientation(int) orientation},
803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setRowCount(int) rowCount} and
813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setColumnCount(int) columnCount} properties.
823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Space</h4>
843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Space between children may be specified either by using instances of the
863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * dedicated {@link Space} view or by setting the
873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#leftMargin leftMargin},
893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#topMargin topMargin},
903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#rightMargin rightMargin} and
913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#bottomMargin bottomMargin}
923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters. When the
943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins}
953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * property is set, default margins around children are automatically
96f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * allocated based on the prevailing UI style guide for the platform.
97f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Each of the margins so defined may be independently overridden by an assignment
983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to the appropriate layout parameter.
99f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Default values will generally produce a reasonable spacing between components
100f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * but values may change between different releases of the platform.
1013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
1023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Excess Space Distribution</h4>
1033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
104f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout's distribution of excess space is based on <em>priority</em>
105f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * rather than <em>weight</em>.
106f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p>
107899d5922870c78e0e663bc5661849eb468afc984Philip Milne * A child's ability to stretch is inferred from the alignment properties of
108899d5922870c78e0e663bc5661849eb468afc984Philip Milne * its row and column groups (which are typically set by setting the
109899d5922870c78e0e663bc5661849eb468afc984Philip Milne * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters).
110899d5922870c78e0e663bc5661849eb468afc984Philip Milne * If alignment was defined along a given axis then the component
111f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * is taken as <em>flexible</em> in that direction. If no alignment was set,
112f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * the component is instead assumed to be <em>inflexible</em>.
113f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p>
114f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Multiple components in the same row or column group are
115f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * considered to act in <em>parallel</em>. Such a
116899d5922870c78e0e663bc5661849eb468afc984Philip Milne * group is flexible only if <em>all</em> of the components
117899d5922870c78e0e663bc5661849eb468afc984Philip Milne * within it are flexible. Row and column groups that sit either side of a common boundary
118899d5922870c78e0e663bc5661849eb468afc984Philip Milne * are instead considered to act in <em>series</em>. The composite group made of these two
119899d5922870c78e0e663bc5661849eb468afc984Philip Milne * elements is flexible if <em>one</em> of its elements is flexible.
120899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p>
121899d5922870c78e0e663bc5661849eb468afc984Philip Milne * To make a column stretch, make sure all of the components inside it define a
122899d5922870c78e0e663bc5661849eb468afc984Philip Milne * gravity. To prevent a column from stretching, ensure that one of the components
123899d5922870c78e0e663bc5661849eb468afc984Philip Milne * in the column does not define a gravity.
1243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p>
125f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * When the principle of flexibility does not provide complete disambiguation,
126f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em>
127f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * and <em>bottom</em> edges.
128f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne *
129a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * <h4>Interpretation of GONE</h4>
130a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne *
131a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * For layout purposes, GridLayout treats views whose visibility status is
132a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * {@link View#GONE GONE}, as having zero width and height. This is subtly different from
133a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * the policy of ignoring views that are marked as GONE outright. If, for example, a gone-marked
134a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * view was alone in a column, that column would itself collapse to zero width if and only if
135a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * no gravity was defined on the view. If gravity was defined, then the gone-marked
136a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * view has no effect on the layout and the container should be laid out as if the view
137a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * had never been added to it.
138a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * These statements apply equally to rows as well as columns, and to groups of rows or columns.
139a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne *
140f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <h5>Limitations</h5>
141f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne *
142f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout does not provide support for the principle of <em>weight</em>, as defined in
143f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible
1446216e87fe8ad3273855233965b34049d22763e94Philip Milne * to configure a GridLayout to distribute excess space between multiple components.
145f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p>
146f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Some common use-cases may nevertheless be accommodated as follows.
147f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * To place equal amounts of space around a component in a cell group;
148f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * use {@link #CENTER} alignment (or {@link LayoutParams#setGravity(int) gravity}).
149f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * For complete control over excess space distribution in a row or column;
150f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * use a {@link LinearLayout} subview to hold the components in the associated cell group.
151f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * When using either of these techniques, bear in mind that cell groups may be defined to overlap.
1523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p>
1533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See {@link GridLayout.LayoutParams} for a full description of the
1543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters used by GridLayout.
1553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne *
1563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation
1573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount
1583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount
1593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins
1603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
1613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
1623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */
163edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne@RemoteView
1643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepublic class GridLayout extends ViewGroup {
1653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Public constants
1673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
1693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * The horizontal orientation.
1703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
1713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
172aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
1743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * The vertical orientation.
1753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
1763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final int VERTICAL = LinearLayout.VERTICAL;
1773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
178aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
179aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * The constant used to indicate that a value is undefined.
180aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * Fields can use this value to indicate that their values
181aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * have not yet been set. Similarly, methods can return this value
182aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * to indicate that there is no suitable value that the implementation
183aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * can return.
184aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * The value used for the constant (currently {@link Integer#MIN_VALUE}) is
185aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * intended to avoid confusion between valid values whose sign may not be known.
186aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
187aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    public static final int UNDEFINED = Integer.MIN_VALUE;
188aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1891e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    /**
1901e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * This constant is an {@link #setAlignmentMode(int) alignmentMode}.
1911e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * When the {@code alignmentMode} is set to {@link #ALIGN_BOUNDS}, alignment
1921e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * is made between the edges of each component's raw
1931e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * view boundary: i.e. the area delimited by the component's:
1941e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getTop() top},
1951e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getLeft() left},
1961e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getBottom() bottom} and
1971e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link android.view.View#getRight() right} properties.
1981e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * <p>
1991e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * For example, when {@code GridLayout} is in {@link #ALIGN_BOUNDS} mode,
2001e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * children that belong to a row group that uses {@link #TOP} alignment will
2011e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * all return the same value when their {@link android.view.View#getTop()}
2021e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * method is called.
2031e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
2041e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
2051e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     */
2061e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public static final int ALIGN_BOUNDS = 0;
2071e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne
2081e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    /**
2091e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * This constant is an {@link #setAlignmentMode(int) alignmentMode}.
2101e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * When the {@code alignmentMode} is set to {@link #ALIGN_MARGINS},
2111e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * the bounds of each view are extended outwards, according
2121e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * to their margins, before the edges of the resulting rectangle are aligned.
2131e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * <p>
2141e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * For example, when {@code GridLayout} is in {@link #ALIGN_MARGINS} mode,
2151e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * the quantity {@code top - layoutParams.topMargin} is the same for all children that
2161e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * belong to a row group that uses {@link #TOP} alignment.
2171e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
2181e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
2191e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     */
2201e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public static final int ALIGN_MARGINS = 1;
2211e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne
2223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Misc constants
2233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
224f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final int MAX_SIZE = 100000;
225f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final int DEFAULT_CONTAINER_MARGIN = 0;
226d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    static final int UNINITIALIZED_HASH = 0;
227a2353621524472f71850a54b5a41188dd8281039Philip Milne    static final Printer LOG_PRINTER = new LogPrinter(Log.DEBUG, GridLayout.class.getName());
228a2353621524472f71850a54b5a41188dd8281039Philip Milne    static final Printer NO_PRINTER = new Printer() {
229a2353621524472f71850a54b5a41188dd8281039Philip Milne        @Override
230a2353621524472f71850a54b5a41188dd8281039Philip Milne        public void println(String x) {
231a2353621524472f71850a54b5a41188dd8281039Philip Milne        }
232a2353621524472f71850a54b5a41188dd8281039Philip Milne    };
2333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Defaults
2353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private static final int DEFAULT_ORIENTATION = HORIZONTAL;
2373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private static final int DEFAULT_COUNT = UNDEFINED;
2383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false;
239899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static final boolean DEFAULT_ORDER_PRESERVED = true;
2401e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
2413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // TypedArray indices
2433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
244b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ORIENTATION = R.styleable.GridLayout_orientation;
245b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ROW_COUNT = R.styleable.GridLayout_rowCount;
246b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount;
247b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins;
248b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode;
249b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved;
250b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved;
2513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Instance variables
2533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
254465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    final Axis mHorizontalAxis = new Axis(true);
255465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    final Axis mVerticalAxis = new Axis(false);
256465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    int mOrientation = DEFAULT_ORIENTATION;
257465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
258465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
259465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    int mDefaultGap;
260465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    int mLastLayoutParamsHashCode = UNINITIALIZED_HASH;
261465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell    Printer mPrinter = LOG_PRINTER;
262aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
2633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Constructors
2643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
2663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * {@inheritDoc}
2673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public GridLayout(Context context, AttributeSet attrs, int defStyle) {
2693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        super(context, attrs, defStyle);
270465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
271b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout);
2723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        try {
2731e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne            setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
2741e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne            setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT));
2755125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            setOrientation(a.getInt(ORIENTATION, DEFAULT_ORIENTATION));
2765125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            setUseDefaultMargins(a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS));
2775125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            setAlignmentMode(a.getInt(ALIGNMENT_MODE, DEFAULT_ALIGNMENT_MODE));
2783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
2793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
2803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        } finally {
2813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            a.recycle();
2823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
2833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
2843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
28548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    /**
28648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne     * {@inheritDoc}
28748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne     */
28848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    public GridLayout(Context context, AttributeSet attrs) {
28948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        this(context, attrs, 0);
29048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    }
29148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
29248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    /**
29348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne     * {@inheritDoc}
29448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne     */
29548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    public GridLayout(Context context) {
2964c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        //noinspection NullableProblems
29748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        this(context, null);
29848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    }
29948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
3003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Implementation
3013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
3033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns the current orientation.
3043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3057fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
3063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setOrientation(int)
3083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_orientation
3103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public int getOrientation() {
312465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mOrientation;
3133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
316b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *
317b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * GridLayout uses the orientation property for two purposes:
318b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * <ul>
319b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *  <li>
320b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *      To control the 'direction' in which default row/column indices are generated
321b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *      when they are not specified in a component's layout parameters.
322b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *  </li>
323b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *  <li>
324b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *      To control which axis should be processed first during the layout operation:
325b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *      when orientation is {@link #HORIZONTAL} the horizontal axis is laid out first.
326b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *  </li>
327b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * </ul>
328b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     *
329b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * The order in which axes are laid out is important if, for example, the height of
330b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * one of GridLayout's children is dependent on its width - and its width is, in turn,
331b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * dependent on the widths of other components.
332b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * <p>
333b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * If your layout contains a {@link TextView} (or derivative:
334b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * {@code Button}, {@code EditText}, {@code CheckBox}, etc.) which is
335b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * in multi-line mode (the default) it is normally best to leave GridLayout's
336b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * orientation as {@code HORIZONTAL} - because {@code TextView} is capable of
337b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * deriving its height for a given width, but not the other way around.
338b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * <p>
339b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * Other than the effects above, orientation does not affect the actual layout operation of
340b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * GridLayout, so it's fine to leave GridLayout in {@code HORIZONTAL} mode even if
341b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne     * the height of the intended layout greatly exceeds its width.
3427fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
3437fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * The default value of this property is {@link #HORIZONTAL}.
3443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3457fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param orientation either {@link #HORIZONTAL} or {@link #VERTICAL}
3463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getOrientation()
3483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_orientation
3503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setOrientation(int orientation) {
352465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (this.mOrientation != orientation) {
353465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            this.mOrientation = orientation;
354f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            invalidateStructure();
3553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            requestLayout();
3563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
3573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
3603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns the current number of rows. This is either the last value that was set
3613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * with {@link #setRowCount(int)} or, if no such value was set, the maximum
36293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * value of each the upper bounds defined in {@link LayoutParams#rowSpec}.
3633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @return the current number of rows
3653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setRowCount(int)
36793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#rowSpec
3683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowCount
3703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public int getRowCount() {
372465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mVerticalAxis.getCount();
3733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
376f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * RowCount is used only to generate default row/column indices when
377f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * they are not specified by a component's layout parameters.
3783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3797fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param rowCount the number of rows
3803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getRowCount()
38293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#rowSpec
3833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowCount
3853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
3863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setRowCount(int rowCount) {
387465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mVerticalAxis.setCount(rowCount);
388f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        invalidateStructure();
389f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        requestLayout();
3903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
3913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
3923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
3933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns the current number of columns. This is either the last value that was set
3943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * with {@link #setColumnCount(int)} or, if no such value was set, the maximum
39593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * value of each the upper bounds defined in {@link LayoutParams#columnSpec}.
3963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @return the current number of columns
3983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
3993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setColumnCount(int)
40093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#columnSpec
4013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnCount
4033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public int getColumnCount() {
405465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mHorizontalAxis.getCount();
4063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
4073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
4083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
409f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * ColumnCount is used only to generate default column/column indices when
410f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * they are not specified by a component's layout parameters.
4113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @param columnCount the number of columns.
4133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getColumnCount()
41593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @see LayoutParams#columnSpec
4163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnCount
4183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setColumnCount(int columnCount) {
420465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mHorizontalAxis.setCount(columnCount);
421f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        invalidateStructure();
422f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        requestLayout();
4233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
4243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
4253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
4263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns whether or not this GridLayout will allocate default margins when no
4273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * corresponding layout parameters are defined.
4283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4297fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return {@code true} if default margins should be allocated
4303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setUseDefaultMargins(boolean)
4323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_useDefaultMargins
4343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public boolean getUseDefaultMargins() {
436465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mUseDefaultMargins;
4373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
4383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
4393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
4407fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When {@code true}, GridLayout allocates default margins around children
4413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * based on the child's visual characteristics. Each of the
4423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * margins so defined may be independently overridden by an assignment
4433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * to the appropriate layout parameter.
4443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
4457fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When {@code false}, the default value of all margins is zero.
446aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * <p>
4477fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When setting to {@code true}, consider setting the value of the
4481e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * {@link #setAlignmentMode(int) alignmentMode}
4491e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * property to {@link #ALIGN_BOUNDS}.
4507fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
4517fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * The default value of this property is {@code false}.
4523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4537fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param useDefaultMargins use {@code true} to make GridLayout allocate default margins
4543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #getUseDefaultMargins()
4561e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
4573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#leftMargin
4593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#topMargin
4603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#rightMargin
4613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see MarginLayoutParams#bottomMargin
4623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
4633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_useDefaultMargins
4643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
4653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setUseDefaultMargins(boolean useDefaultMargins) {
466465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        this.mUseDefaultMargins = useDefaultMargins;
467aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
468aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
469aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
470aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
4711e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * Returns the alignment mode.
4721e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
4731e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @return the alignment mode; either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS}
474aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4751e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_BOUNDS
4761e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_MARGINS
477aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4781e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #setAlignmentMode(int)
479aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4801e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @attr ref android.R.styleable#GridLayout_alignmentMode
481aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
4821e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public int getAlignmentMode() {
483465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mAlignmentMode;
484aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
485aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
486aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
4871e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * Sets the alignment mode to be used for all of the alignments between the
4881e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * children of this container.
4897fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
4901e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * The default value of this property is {@link #ALIGN_MARGINS}.
4911e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     *
4921e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @param alignmentMode either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS}
493aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4941e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_BOUNDS
4951e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #ALIGN_MARGINS
496aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4971e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @see #getAlignmentMode()
498aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     *
4991e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * @attr ref android.R.styleable#GridLayout_alignmentMode
500aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
5011e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne    public void setAlignmentMode(int alignmentMode) {
502465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        this.mAlignmentMode = alignmentMode;
503aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
5043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
5073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns whether or not row boundaries are ordered by their grid indices.
5083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5097fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return {@code true} if row boundaries must appear in the order of their indices,
5107fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *         {@code false} otherwise
5113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setRowOrderPreserved(boolean)
5133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
5153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
5163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public boolean isRowOrderPreserved() {
517465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mVerticalAxis.isOrderPreserved();
5183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
5217fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When this property is {@code true}, GridLayout is forced to place the row boundaries
522aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * so that their associated grid indices are in ascending order in the view.
5233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
524899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * When this property is {@code false} GridLayout is at liberty to place the vertical row
525899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * boundaries in whatever order best fits the given constraints.
5267fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
527899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The default value of this property is {@code true}.
5287fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
5297fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param rowOrderPreserved {@code true} to force GridLayout to respect the order
5307fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *        of row boundaries
5313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #isRowOrderPreserved()
5333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
5353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
5363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setRowOrderPreserved(boolean rowOrderPreserved) {
537465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mVerticalAxis.setOrderPreserved(rowOrderPreserved);
538aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        invalidateStructure();
539aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
5403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
5433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Returns whether or not column boundaries are ordered by their grid indices.
5443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5457fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @return {@code true} if column boundaries must appear in the order of their indices,
5467fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *         {@code false} otherwise
5473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #setColumnOrderPreserved(boolean)
5493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
5513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
5523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public boolean isColumnOrderPreserved() {
553465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mHorizontalAxis.isOrderPreserved();
5543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
5563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
5577fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * When this property is {@code true}, GridLayout is forced to place the column boundaries
558aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * so that their associated grid indices are in ascending order in the view.
5593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
560899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * When this property is {@code false} GridLayout is at liberty to place the horizontal column
561899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * boundaries in whatever order best fits the given constraints.
5627fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * <p>
563899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The default value of this property is {@code true}.
5643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5657fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * @param columnOrderPreserved use {@code true} to force GridLayout to respect the order
5663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *        of column boundaries.
5673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see #isColumnOrderPreserved()
5693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
5703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
5713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
5723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public void setColumnOrderPreserved(boolean columnOrderPreserved) {
573465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mHorizontalAxis.setOrderPreserved(columnOrderPreserved);
574aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        invalidateStructure();
575aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        requestLayout();
5763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
5773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
578211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    /**
579211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * Return the printer that will log diagnostics from this layout.
580211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     *
581211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * @see #setPrinter(android.util.Printer)
582211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     *
583211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * @return the printer associated with this view
584465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell     *
585465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell     * @hide
586211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     */
587211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    public Printer getPrinter() {
588465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mPrinter;
589211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    }
590211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne
591211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    /**
592211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * Set the printer that will log diagnostics from this layout.
593211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * The default value is created by {@link android.util.LogPrinter}.
594211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     *
595211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * @param printer the printer associated with this layout
596211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     *
597211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     * @see #getPrinter()
598465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell     *
599465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell     * @hide
600211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne     */
601211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    public void setPrinter(Printer printer) {
602465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        this.mPrinter = (printer == null) ? NO_PRINTER : printer;
603211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne    }
604211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne
6055125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    // Static utility methods
6065125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
607f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static int max2(int[] a, int valueIfEmpty) {
60851f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        int result = valueIfEmpty;
60951f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        for (int i = 0, N = a.length; i < N; i++) {
61051f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne            result = Math.max(result, a[i]);
61151f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        }
61251f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne        return result;
61351f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne    }
61451f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne
615899d5922870c78e0e663bc5661849eb468afc984Philip Milne    @SuppressWarnings("unchecked")
616f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static <T> T[] append(T[] a, T[] b) {
61748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
61848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        System.arraycopy(a, 0, result, 0, a.length);
61948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        System.arraycopy(b, 0, result, a.length, b.length);
6203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return result;
6213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
623f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static Alignment getAlignment(int gravity, boolean horizontal) {
6245125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        int mask = horizontal ? HORIZONTAL_GRAVITY_MASK : VERTICAL_GRAVITY_MASK;
6255125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        int shift = horizontal ? AXIS_X_SHIFT : AXIS_Y_SHIFT;
6265125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        int flags = (gravity & mask) >> shift;
6275125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        switch (flags) {
6285125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE):
6291557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne                return horizontal ? LEFT : TOP;
6305125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case (AXIS_SPECIFIED | AXIS_PULL_AFTER):
6311557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne                return horizontal ? RIGHT : BOTTOM;
6325125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER):
6335125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return FILL;
6345125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            case AXIS_SPECIFIED:
6355125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return CENTER;
63647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | RELATIVE_LAYOUT_DIRECTION):
63747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio                return START;
63847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio            case (AXIS_SPECIFIED | AXIS_PULL_AFTER | RELATIVE_LAYOUT_DIRECTION):
63947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio                return END;
6405125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            default:
6415125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                return UNDEFINED_ALIGNMENT;
6425125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
6435125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
6445125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
6454c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    /** @noinspection UnusedParameters*/
6461fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
647899d5922870c78e0e663bc5661849eb468afc984Philip Milne        if (c.getClass() == Space.class) {
648899d5922870c78e0e663bc5661849eb468afc984Philip Milne            return 0;
649899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
650465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        return mDefaultGap / 2;
6513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
6531fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
6547b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        return /*isAtEdge ? DEFAULT_CONTAINER_MARGIN :*/ getDefaultMargin(c, horizontal, leading);
6553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
6577a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne    private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) {
658465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (!mUseDefaultMargins) {
6593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return 0;
6603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
66193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        Spec spec = horizontal ? p.columnSpec : p.rowSpec;
662465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
66393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        Interval span = spec.span;
66447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        boolean leading1 = (horizontal && isLayoutRtl()) ? !leading : leading;
66547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount());
6663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
6671fd16378812792913a6aa6923acbec20037e09ffPhilip Milne        return getDefaultMargin(c, isAtEdge, horizontal, leading);
6683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
670f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    int getMargin1(View view, boolean horizontal, boolean leading) {
6713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        LayoutParams lp = getLayoutParams(view);
6723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int margin = horizontal ?
673aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                (leading ? lp.leftMargin : lp.rightMargin) :
674aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                (leading ? lp.topMargin : lp.bottomMargin);
6757a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        return margin == UNDEFINED ? getDefaultMargin(view, lp, horizontal, leading) : margin;
6761fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    }
6771fd16378812792913a6aa6923acbec20037e09ffPhilip Milne
6784c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    private int getMargin(View view, boolean horizontal, boolean leading) {
679465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (mAlignmentMode == ALIGN_MARGINS) {
6804c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            return getMargin1(view, horizontal, leading);
6814c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        } else {
682465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
6834c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins();
6844c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            LayoutParams lp = getLayoutParams(view);
6854c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
6864c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int index = leading ? spec.span.min : spec.span.max;
6874c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            return margins[index];
6884c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        }
6894c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    }
6904c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne
6911fd16378812792913a6aa6923acbec20037e09ffPhilip Milne    private int getTotalMargin(View child, boolean horizontal) {
6921fd16378812792913a6aa6923acbec20037e09ffPhilip Milne        return getMargin(child, horizontal, true) + getMargin(child, horizontal, false);
6933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
6943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
695899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static boolean fits(int[] a, int value, int start, int end) {
696899d5922870c78e0e663bc5661849eb468afc984Philip Milne        if (end > a.length) {
697899d5922870c78e0e663bc5661849eb468afc984Philip Milne            return false;
698899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
699899d5922870c78e0e663bc5661849eb468afc984Philip Milne        for (int i = start; i < end; i++) {
700899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (a[i] > value) {
701899d5922870c78e0e663bc5661849eb468afc984Philip Milne                return false;
7023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
703899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
704899d5922870c78e0e663bc5661849eb468afc984Philip Milne        return true;
705899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
7063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
707899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static void procrusteanFill(int[] a, int start, int end, int value) {
708899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int length = a.length;
709899d5922870c78e0e663bc5661849eb468afc984Philip Milne        Arrays.fill(a, Math.min(start, length), Math.min(end, length), value);
710899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
7113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
712899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static void setCellGroup(LayoutParams lp, int row, int rowSpan, int col, int colSpan) {
713899d5922870c78e0e663bc5661849eb468afc984Philip Milne        lp.setRowSpecSpan(new Interval(row, row + rowSpan));
714899d5922870c78e0e663bc5661849eb468afc984Philip Milne        lp.setColumnSpecSpan(new Interval(col, col + colSpan));
715899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
7163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
717899d5922870c78e0e663bc5661849eb468afc984Philip Milne    // Logic to avert infinite loops by ensuring that the cells can be placed somewhere.
718899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private static int clip(Interval minorRange, boolean minorWasDefined, int count) {
719899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int size = minorRange.size();
720899d5922870c78e0e663bc5661849eb468afc984Philip Milne        if (count == 0) {
721899d5922870c78e0e663bc5661849eb468afc984Philip Milne            return size;
722899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
723899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int min = minorWasDefined ? min(minorRange.min, count) : 0;
724899d5922870c78e0e663bc5661849eb468afc984Philip Milne        return min(size, count - min);
725899d5922870c78e0e663bc5661849eb468afc984Philip Milne    }
726f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne
727899d5922870c78e0e663bc5661849eb468afc984Philip Milne    // install default indices for cells that don't define them
728899d5922870c78e0e663bc5661849eb468afc984Philip Milne    private void validateLayoutParams() {
729465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        final boolean horizontal = (mOrientation == HORIZONTAL);
730465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        final Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
731782c04b864dc5f71f7ec0c8e36cbaf5b838dc69cJim Miller        final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0;
732f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne
733899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int major = 0;
734899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int minor = 0;
735899d5922870c78e0e663bc5661849eb468afc984Philip Milne        int[] maxSizes = new int[count];
736f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne
737899d5922870c78e0e663bc5661849eb468afc984Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
738d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
739899d5922870c78e0e663bc5661849eb468afc984Philip Milne
740f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec;
741f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Interval majorRange = majorSpec.span;
742f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final boolean majorWasDefined = majorSpec.startDefined;
743899d5922870c78e0e663bc5661849eb468afc984Philip Milne            final int majorSpan = majorRange.size();
744899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (majorWasDefined) {
745899d5922870c78e0e663bc5661849eb468afc984Philip Milne                major = majorRange.min;
746899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
747899d5922870c78e0e663bc5661849eb468afc984Philip Milne
748f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Spec minorSpec = horizontal ? lp.columnSpec : lp.rowSpec;
749f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final Interval minorRange = minorSpec.span;
750f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            final boolean minorWasDefined = minorSpec.startDefined;
751899d5922870c78e0e663bc5661849eb468afc984Philip Milne            final int minorSpan = clip(minorRange, minorWasDefined, count);
752899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (minorWasDefined) {
753899d5922870c78e0e663bc5661849eb468afc984Philip Milne                minor = minorRange.min;
754899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
755899d5922870c78e0e663bc5661849eb468afc984Philip Milne
756899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (count != 0) {
757899d5922870c78e0e663bc5661849eb468afc984Philip Milne                // Find suitable row/col values when at least one is undefined.
758899d5922870c78e0e663bc5661849eb468afc984Philip Milne                if (!majorWasDefined || !minorWasDefined) {
759899d5922870c78e0e663bc5661849eb468afc984Philip Milne                    while (!fits(maxSizes, major, minor, minor + minorSpan)) {
760899d5922870c78e0e663bc5661849eb468afc984Philip Milne                        if (minorWasDefined) {
761899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            major++;
762899d5922870c78e0e663bc5661849eb468afc984Philip Milne                        } else {
763899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            if (minor + minorSpan <= count) {
764899d5922870c78e0e663bc5661849eb468afc984Philip Milne                                minor++;
765899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            } else {
766899d5922870c78e0e663bc5661849eb468afc984Philip Milne                                minor = 0;
767899d5922870c78e0e663bc5661849eb468afc984Philip Milne                                major++;
768899d5922870c78e0e663bc5661849eb468afc984Philip Milne                            }
769f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne                        }
770f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne                    }
7713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
772899d5922870c78e0e663bc5661849eb468afc984Philip Milne                procrusteanFill(maxSizes, minor, minor + minorSpan, major + majorSpan);
7733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
774899d5922870c78e0e663bc5661849eb468afc984Philip Milne
775899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (horizontal) {
776899d5922870c78e0e663bc5661849eb468afc984Philip Milne                setCellGroup(lp, major, majorSpan, minor, minorSpan);
777899d5922870c78e0e663bc5661849eb468afc984Philip Milne            } else {
778899d5922870c78e0e663bc5661849eb468afc984Philip Milne                setCellGroup(lp, minor, minorSpan, major, majorSpan);
779899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
780899d5922870c78e0e663bc5661849eb468afc984Philip Milne
781899d5922870c78e0e663bc5661849eb468afc984Philip Milne            minor = minor + minorSpan;
782899d5922870c78e0e663bc5661849eb468afc984Philip Milne        }
7833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private void invalidateStructure() {
786465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mLastLayoutParamsHashCode = UNINITIALIZED_HASH;
787465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mHorizontalAxis.invalidateStructure();
788465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mVerticalAxis.invalidateStructure();
789899d5922870c78e0e663bc5661849eb468afc984Philip Milne        // This can end up being done twice. Better twice than not at all.
7903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        invalidateValues();
7913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
7923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
7933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private void invalidateValues() {
794aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        // Need null check because requestLayout() is called in View's initializer,
795aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        // before we are set up.
796465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (mHorizontalAxis != null && mVerticalAxis != null) {
797465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            mHorizontalAxis.invalidateValues();
798465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            mVerticalAxis.invalidateValues();
799aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
8003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
802d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    /** @hide */
803d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    @Override
804d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    protected void onSetLayoutParams(View child, ViewGroup.LayoutParams layoutParams) {
805d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        super.onSetLayoutParams(child, layoutParams);
8060f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8070f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        if (!checkLayoutParams(layoutParams)) {
8080f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            handleInvalidParams("supplied LayoutParams are of the wrong type");
8090f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        }
8100f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
811d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        invalidateStructure();
8123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
814f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final LayoutParams getLayoutParams(View c) {
815d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        return (LayoutParams) c.getLayoutParams();
8163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8180f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    private static void handleInvalidParams(String msg) {
8190f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        throw new IllegalArgumentException(msg + ". ");
8200f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    }
8210f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8220f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    private void checkLayoutParams(LayoutParams lp, boolean horizontal) {
8230f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        String groupName = horizontal ? "column" : "row";
8240f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
8250f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        Interval span = spec.span;
8260f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        if (span.min != UNDEFINED && span.min < 0) {
8270f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            handleInvalidParams(groupName + " indices must be positive");
8280f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        }
829465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
8300f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        int count = axis.definedCount;
8310f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        if (count != UNDEFINED) {
8320f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            if (span.max > count) {
8330f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                handleInvalidParams(groupName +
8340f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                        " indices (start + span) mustn't exceed the " + groupName + " count");
8350f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            }
8360f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            if (span.size() > count) {
8370f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                handleInvalidParams(groupName + " span mustn't exceed the " + groupName + " count");
8380f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            }
8390f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        }
8400f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    }
8410f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8420f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    @Override
8430f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
8440f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        if (!(p instanceof LayoutParams)) {
8450f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            return false;
8460f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        }
8470f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        LayoutParams lp = (LayoutParams) p;
8480f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8490f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        checkLayoutParams(lp, true);
8500f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        checkLayoutParams(lp, false);
8510f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8520f57cea8989cc03bcae19b621096e50b035b7308Philip Milne        return true;
8530f57cea8989cc03bcae19b621096e50b035b7308Philip Milne    }
8540f57cea8989cc03bcae19b621096e50b035b7308Philip Milne
8553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
8563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    protected LayoutParams generateDefaultLayoutParams() {
8573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return new LayoutParams();
8583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
8613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public LayoutParams generateLayoutParams(AttributeSet attrs) {
8625125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return new LayoutParams(getContext(), attrs);
8633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
8663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
8673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        return new LayoutParams(p);
8683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Draw grid
8713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
8723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
87347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        if (isLayoutRtl()) {
87447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio            int width = getWidth();
8757b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne            graphics.drawLine(width - x1, y1, width - x2, y2, paint);
87647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        } else {
8777b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne            graphics.drawLine(x1, y1, x2, y2, paint);
87847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        }
8793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
8803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
88110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne    /**
88210ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne     * @hide
88310ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne     */
88410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne    @Override
8857b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne    protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
88610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        // Apply defaults, so as to remove UNDEFINED values
88710ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        LayoutParams lp = new LayoutParams();
88810ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        for (int i = 0; i < getChildCount(); i++) {
88910ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne            View c = getChildAt(i);
89010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne            lp.setMargins(
8917b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                    getMargin1(c, true, true),
8927b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                    getMargin1(c, false, true),
8937b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                    getMargin1(c, true, false),
8947b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                    getMargin1(c, false, false));
8957b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne            lp.onDebugDraw(c, canvas, paint);
89610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        }
897b559976a50c34848d602cc7138859507a379893cPhilip Milne    }
898b559976a50c34848d602cc7138859507a379893cPhilip Milne
89910ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne    /**
90010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne     * @hide
90110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne     */
9023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
90310ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne    protected void onDebugDraw(Canvas canvas) {
90410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        Paint paint = new Paint();
90510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        paint.setStyle(Paint.Style.STROKE);
90610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        paint.setColor(Color.argb(50, 255, 255, 255));
90710ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne
9087b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        Insets insets = getOpticalInsets();
9097b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne
9107b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        int top    =               getPaddingTop()    + insets.top;
9117b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        int left   =               getPaddingLeft()   + insets.left;
9127b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        int right  = getWidth()  - getPaddingRight()  - insets.right;
9137b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        int bottom = getHeight() - getPaddingBottom() - insets.bottom;
9147b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne
915465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        int[] xs = mHorizontalAxis.locations;
91610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        if (xs != null) {
91710ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne            for (int i = 0, length = xs.length; i < length; i++) {
9187b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                int x = left + xs[i];
9197b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                drawLine(canvas, x, top, x, bottom, paint);
920b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            }
92110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        }
922b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
923465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        int[] ys = mVerticalAxis.locations;
92410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        if (ys != null) {
92510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne            for (int i = 0, length = ys.length; i < length; i++) {
9267b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                int y = top + ys[i];
9277b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne                drawLine(canvas, left, y, right, y, paint);
9283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
9293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
93010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne
93110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne        super.onDebugDraw(canvas);
9323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
9333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
9343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Add/remove
9353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
936e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne    /**
937e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     * @hide
938e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     */
9393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
940f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne    protected void onViewAdded(View child) {
941f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne        super.onViewAdded(child);
9423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        invalidateStructure();
9433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
9443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
945e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne    /**
946e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     * @hide
947e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne     */
9483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
949f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne    protected void onViewRemoved(View child) {
950f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne        super.onViewRemoved(child);
951b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        invalidateStructure();
952350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne    }
953350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne
954350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne    /**
955350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     * We need to call invalidateStructure() when a child's GONE flag changes state.
956350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     * This implementation is a catch-all, invalidating on any change in the visibility flags.
957350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     *
958350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     * @hide
959350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne     */
960350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne    @Override
9610d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
9620d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        super.onChildVisibilityChanged(child, oldVisibility, newVisibility);
9630d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        if (oldVisibility == GONE || newVisibility == GONE) {
964a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne        invalidateStructure();
9650d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        }
966b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne    }
967b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne
968d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    private int computeLayoutParamsHashCode() {
969d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        int result = 1;
970d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
971d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            View c = getChildAt(i);
972d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (c.getVisibility() == View.GONE) continue;
973d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            LayoutParams lp = (LayoutParams) c.getLayoutParams();
974d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            result = 31 * result + lp.hashCode();
975d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        }
976d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        return result;
977d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    }
9783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
979edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne    private void consistencyCheck() {
980465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (mLastLayoutParamsHashCode == UNINITIALIZED_HASH) {
981edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne            validateLayoutParams();
982465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            mLastLayoutParamsHashCode = computeLayoutParamsHashCode();
983465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        } else if (mLastLayoutParamsHashCode != computeLayoutParamsHashCode()) {
984465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            mPrinter.println("The fields of some layout parameters were modified in between "
985211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne                    + "layout operations. Check the javadoc for GridLayout.LayoutParams#rowSpec.");
986edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne            invalidateStructure();
987edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne            consistencyCheck();
988d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        }
989b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne    }
990b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
991d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne    // Measurement
992d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
993e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne    // Note: padding has already been removed from the supplied specs
9944a145d72622772b920f60195e80942058984259cPhilip Milne    private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec,
995edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne            int childWidth, int childHeight) {
9964a145d72622772b920f60195e80942058984259cPhilip Milne        int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
997e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne                getTotalMargin(child, true), childWidth);
9984a145d72622772b920f60195e80942058984259cPhilip Milne        int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
999e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne                getTotalMargin(child, false), childHeight);
10004a145d72622772b920f60195e80942058984259cPhilip Milne        child.measure(childWidthSpec, childHeightSpec);
1001b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne    }
1002b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
1003e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne    // Note: padding has already been removed from the supplied specs
10044a145d72622772b920f60195e80942058984259cPhilip Milne    private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) {
1005b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
1006b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            View c = getChildAt(i);
1007d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (c.getVisibility() == View.GONE) continue;
10084a145d72622772b920f60195e80942058984259cPhilip Milne            LayoutParams lp = getLayoutParams(c);
10094a145d72622772b920f60195e80942058984259cPhilip Milne            if (firstPass) {
10104a145d72622772b920f60195e80942058984259cPhilip Milne                measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
10114a145d72622772b920f60195e80942058984259cPhilip Milne            } else {
1012465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell                boolean horizontal = (mOrientation == HORIZONTAL);
1013ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
10144a145d72622772b920f60195e80942058984259cPhilip Milne                if (spec.alignment == FILL) {
10154a145d72622772b920f60195e80942058984259cPhilip Milne                    Interval span = spec.span;
1016465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell                    Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
10174a145d72622772b920f60195e80942058984259cPhilip Milne                    int[] locations = axis.getLocations();
1018ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                    int cellSize = locations[span.max] - locations[span.min];
1019ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                    int viewSize = cellSize - getTotalMargin(c, horizontal);
1020ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                    if (horizontal) {
1021ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                        measureChildWithMargins2(c, widthSpec, heightSpec, viewSize, lp.height);
10224a145d72622772b920f60195e80942058984259cPhilip Milne                    } else {
1023ecab1178648670f2c72b47faf250040fcded3d13Philip Milne                        measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, viewSize);
10244a145d72622772b920f60195e80942058984259cPhilip Milne                    }
10254a145d72622772b920f60195e80942058984259cPhilip Milne                }
10264a145d72622772b920f60195e80942058984259cPhilip Milne            }
1027b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        }
1028b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne    }
1029b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne
1030e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne    static int adjust(int measureSpec, int delta) {
1031e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        return makeMeasureSpec(
1032e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne                MeasureSpec.getSize(measureSpec + delta),  MeasureSpec.getMode(measureSpec));
1033e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne    }
1034e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne
1035aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    @Override
1036aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    protected void onMeasure(int widthSpec, int heightSpec) {
1037edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne        consistencyCheck();
1038d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
10394a145d72622772b920f60195e80942058984259cPhilip Milne        /** If we have been called by {@link View#measure(int, int)}, one of width or height
10404a145d72622772b920f60195e80942058984259cPhilip Milne         *  is  likely to have changed. We must invalidate if so. */
10414a145d72622772b920f60195e80942058984259cPhilip Milne        invalidateValues();
10424a145d72622772b920f60195e80942058984259cPhilip Milne
1043e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int hPadding = getPaddingLeft() + getPaddingRight();
1044e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int vPadding = getPaddingTop()  + getPaddingBottom();
1045e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne
1046e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int widthSpecSansPadding =  adjust( widthSpec, -hPadding);
1047e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int heightSpecSansPadding = adjust(heightSpec, -vPadding);
10484a145d72622772b920f60195e80942058984259cPhilip Milne
1049e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, true);
1050e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne
1051e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int widthSansPadding;
1052e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int heightSansPadding;
10534a145d72622772b920f60195e80942058984259cPhilip Milne
10544a145d72622772b920f60195e80942058984259cPhilip Milne        // Use the orientation property to decide which axis should be laid out first.
1055465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        if (mOrientation == HORIZONTAL) {
1056465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding);
1057e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne            measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
1058465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding);
10594a145d72622772b920f60195e80942058984259cPhilip Milne        } else {
1060465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding);
1061e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne            measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
1062465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding);
10634a145d72622772b920f60195e80942058984259cPhilip Milne        }
1064aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1065e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int measuredWidth  = Math.max(widthSansPadding  + hPadding, getSuggestedMinimumWidth());
1066e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne        int measuredHeight = Math.max(heightSansPadding + vPadding, getSuggestedMinimumHeight());
106709e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne
10683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        setMeasuredDimension(
1069e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne                resolveSizeAndState(measuredWidth,   widthSpec, 0),
107009e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne                resolveSizeAndState(measuredHeight, heightSpec, 0));
10713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
10723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
107348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    private int getMeasurement(View c, boolean horizontal) {
10747b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne        return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
10753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
10763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1077f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final int getMeasurementIncludingMargin(View c, boolean horizontal) {
1078d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        if (c.getVisibility() == View.GONE) {
10795125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            return 0;
10805125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
10814c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne        return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal);
1082aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
10833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1084aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    @Override
1085aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    public void requestLayout() {
1086aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        super.requestLayout();
1087aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        invalidateValues();
1088aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    }
1089aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1090f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final Alignment getAlignment(Alignment alignment, boolean horizontal) {
10915125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return (alignment != UNDEFINED_ALIGNMENT) ? alignment :
109247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio                (horizontal ? START : BASELINE);
10935125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
10945125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
10953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Layout container
10963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1097aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /**
1098aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * {@inheritDoc}
1099aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
1100aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
1101aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     The layout operation is implemented by delegating the heavy lifting to the
1102aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     to the mHorizontalAxis and mVerticalAxis instances of the internal Axis class.
1103aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     Together they compute the locations of the vertical and horizontal lines of
1104aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     the grid (respectively!).
1105aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1106aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     This method is then left with the simpler task of applying margins, gravity
1107aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     and sizing to each child view and then placing it in its cell.
1108aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
11093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @Override
111009e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1111edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne        consistencyCheck();
1112d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
111309e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne        int targetWidth = right - left;
111409e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne        int targetHeight = bottom - top;
11153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingLeft = getPaddingLeft();
11173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingTop = getPaddingTop();
11183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingRight = getPaddingRight();
11193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        int paddingBottom = getPaddingBottom();
11203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1121465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
1122465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom);
11233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1124465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        int[] hLocations = mHorizontalAxis.getLocations();
1125465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell        int[] vLocations = mVerticalAxis.getLocations();
11264c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne
1127b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne        for (int i = 0, N = getChildCount(); i < N; i++) {
1128b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            View c = getChildAt(i);
1129d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (c.getVisibility() == View.GONE) continue;
1130b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            LayoutParams lp = getLayoutParams(c);
113193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec columnSpec = lp.columnSpec;
113293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec rowSpec = lp.rowSpec;
1133aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
113493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Interval colSpan = columnSpec.span;
113593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Interval rowSpan = rowSpec.span;
11363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11374c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int x1 = hLocations[colSpan.min];
11384c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int y1 = vLocations[rowSpan.min];
11393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11404c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int x2 = hLocations[colSpan.max];
11414c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int y2 = vLocations[rowSpan.max];
11423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int cellWidth = x2 - x1;
11443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int cellHeight = y2 - y1;
11453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
114648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int pWidth = getMeasurement(c, true);
114748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int pHeight = getMeasurement(c, false);
11483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11495125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            Alignment hAlign = getAlignment(columnSpec.alignment, true);
11505125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            Alignment vAlign = getAlignment(rowSpec.alignment, false);
1151aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1152465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i);
1153465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i);
11547fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
11557fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            // Gravity offsets: the location of the alignment group relative to its cell group.
11566216e87fe8ad3273855233965b34049d22763e94Philip Milne            int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true));
11576216e87fe8ad3273855233965b34049d22763e94Philip Milne            int gravityOffsetY = vAlign.getGravityOffset(c, cellHeight - boundsY.size(true));
11586216e87fe8ad3273855233965b34049d22763e94Philip Milne
11596216e87fe8ad3273855233965b34049d22763e94Philip Milne            int leftMargin = getMargin(c, true, true);
11604c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int topMargin = getMargin(c, false, true);
11616216e87fe8ad3273855233965b34049d22763e94Philip Milne            int rightMargin = getMargin(c, true, false);
11624c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            int bottomMargin = getMargin(c, false, false);
11637fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
11641557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int sumMarginsX = leftMargin + rightMargin;
11651557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int sumMarginsY = topMargin + bottomMargin;
11661557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne
11674c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            // Alignment offsets: the location of the view relative to its alignment group.
11681557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true);
11691557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false);
11707fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
11711557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX);
11721557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY);
11737fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne
11746216e87fe8ad3273855233965b34049d22763e94Philip Milne            int dx = x1 + gravityOffsetX + alignmentOffsetX;
11753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11766216e87fe8ad3273855233965b34049d22763e94Philip Milne            int cx = !isLayoutRtl() ? paddingLeft + leftMargin + dx :
11776216e87fe8ad3273855233965b34049d22763e94Philip Milne                    targetWidth - width - paddingRight - rightMargin - dx;
11786216e87fe8ad3273855233965b34049d22763e94Philip Milne            int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin;
11793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1180899d5922870c78e0e663bc5661849eb468afc984Philip Milne            if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) {
1181899d5922870c78e0e663bc5661849eb468afc984Philip Milne                c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
1182899d5922870c78e0e663bc5661849eb468afc984Philip Milne            }
1183b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            c.layout(cx, cy, cx + width, cy + height);
11843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
11853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
11863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
11878a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
11888a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
11898a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
11908a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(GridLayout.class.getName());
11918a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
11928a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
11938a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
11948a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
11958a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
11968a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(GridLayout.class.getName());
11978a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
11988a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
11993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // Inner classes
12003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1201aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
1202aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     This internal class houses the algorithm for computing the locations of grid lines;
1203aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     along either the horizontal or vertical axis. A GridLayout uses two instances of this class -
1204aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     distinguished by the "horizontal" flag which is true for the horizontal axis and false
1205aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     for the vertical one.
1206aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
1207f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final class Axis {
120848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private static final int NEW = 0;
12093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int PENDING = 1;
12103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int COMPLETE = 2;
12113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final boolean horizontal;
12133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1214f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int definedCount = UNDEFINED;
12154a145d72622772b920f60195e80942058984259cPhilip Milne        private int maxIndex = UNDEFINED;
12163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
121793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        PackedMap<Spec, Bounds> groupBounds;
12183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean groupBoundsValid = false;
12193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
122048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        PackedMap<Interval, MutableInt> forwardLinks;
122148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean forwardLinksValid = false;
122248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
122348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        PackedMap<Interval, MutableInt> backwardLinks;
122448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean backwardLinksValid = false;
12253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int[] leadingMargins;
1227aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public boolean leadingMarginsValid = false;
1228aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
12293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int[] trailingMargins;
1230aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public boolean trailingMarginsValid = false;
12313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public Arc[] arcs;
12333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean arcsValid = false;
12343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1235aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public int[] locations;
123648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean locationsValid = false;
1237aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1238f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        boolean orderPreserved = DEFAULT_ORDER_PRESERVED;
12393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
124048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private MutableInt parentMin = new MutableInt(0);
124148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private MutableInt parentMax = new MutableInt(-MAX_SIZE);
124248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
12433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private Axis(boolean horizontal) {
12443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.horizontal = horizontal;
12453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12474a145d72622772b920f60195e80942058984259cPhilip Milne        private int calculateMaxIndex() {
12484a145d72622772b920f60195e80942058984259cPhilip Milne            // the number Integer.MIN_VALUE + 1 comes up in undefined cells
12494a145d72622772b920f60195e80942058984259cPhilip Milne            int result = -1;
1250b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
1251b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                View c = getChildAt(i);
1252b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                LayoutParams params = getLayoutParams(c);
125393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec spec = horizontal ? params.columnSpec : params.rowSpec;
12544a145d72622772b920f60195e80942058984259cPhilip Milne                Interval span = spec.span;
12554a145d72622772b920f60195e80942058984259cPhilip Milne                result = max(result, span.min);
12564a145d72622772b920f60195e80942058984259cPhilip Milne                result = max(result, span.max);
12570f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                result = max(result, span.size());
12583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
12594a145d72622772b920f60195e80942058984259cPhilip Milne            return result == -1 ? UNDEFINED : result;
12603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12624a145d72622772b920f60195e80942058984259cPhilip Milne        private int getMaxIndex() {
12634a145d72622772b920f60195e80942058984259cPhilip Milne            if (maxIndex == UNDEFINED) {
12644a145d72622772b920f60195e80942058984259cPhilip Milne                maxIndex = max(0, calculateMaxIndex()); // use zero when there are no children
12653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
12664a145d72622772b920f60195e80942058984259cPhilip Milne            return maxIndex;
1267f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1268f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1269f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int getCount() {
12704a145d72622772b920f60195e80942058984259cPhilip Milne            return max(definedCount, getMaxIndex());
12713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public void setCount(int count) {
12740f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            if (count != UNDEFINED && count < getMaxIndex()) {
12750f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                handleInvalidParams((horizontal ? "column" : "row") +
12760f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                        "Count must be greater than or equal to the maximum of all grid indices " +
12770f57cea8989cc03bcae19b621096e50b035b7308Philip Milne                        "(and spans) defined in the LayoutParams of each child");
12780f57cea8989cc03bcae19b621096e50b035b7308Philip Milne            }
1279f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.definedCount = count;
12803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean isOrderPreserved() {
1283f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return orderPreserved;
12843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
12863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public void setOrderPreserved(boolean orderPreserved) {
1287f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.orderPreserved = orderPreserved;
12883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            invalidateStructure();
12893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
12903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
129193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        private PackedMap<Spec, Bounds> createGroupBounds() {
129293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class);
129348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
1294b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                View c = getChildAt(i);
1295a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne                // we must include views that are GONE here, see introductory javadoc
12965125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                LayoutParams lp = getLayoutParams(c);
12975125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
12985125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds();
12995125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                assoc.put(spec, bounds);
13003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
130148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return assoc.pack();
13023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
13043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private void computeGroupBounds() {
1305b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            Bounds[] values = groupBounds.values;
1306b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0; i < values.length; i++) {
1307b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne                values[i].reset();
13083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
1309aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
13103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                View c = getChildAt(i);
1311a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne                // we must include views that are GONE here, see introductory javadoc
13123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                LayoutParams lp = getLayoutParams(c);
131393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
13141557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne                groupBounds.getValue(i).include(GridLayout.this, c, spec, this);
13153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1318f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public PackedMap<Spec, Bounds> getGroupBounds() {
13193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (groupBounds == null) {
13203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                groupBounds = createGroupBounds();
13213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (!groupBoundsValid) {
13233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                computeGroupBounds();
13243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                groupBoundsValid = true;
13253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return groupBounds;
13273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
13293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Add values computed by alignment - taking the max of all alignments in each span
133048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private PackedMap<Interval, MutableInt> createLinks(boolean min) {
133148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class);
133293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec[] keys = getGroupBounds().keys;
133348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0, N = keys.length; i < N; i++) {
133448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Interval span = min ? keys[i].span : keys[i].span.inverse();
133548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                result.put(span, new MutableInt());
13363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
133748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return result.pack();
13383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
134048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void computeLinks(PackedMap<Interval, MutableInt> links, boolean min) {
134148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            MutableInt[] spans = links.values;
13423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < spans.length; i++) {
13433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                spans[i].reset();
13443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
13465d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            // Use getter to trigger a re-evaluation
134748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Bounds[] bounds = getGroupBounds().values;
13483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < bounds.length; i++) {
134948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                int size = bounds[i].size(min);
135048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                MutableInt valueHolder = links.getValue(i);
13515125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                // this effectively takes the max() of the minima and the min() of the maxima
13525125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                valueHolder.value = max(valueHolder.value, min ? size : -size);
13533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
13543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
135648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private PackedMap<Interval, MutableInt> getForwardLinks() {
135748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (forwardLinks == null) {
135848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                forwardLinks = createLinks(true);
13593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
136048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!forwardLinksValid) {
136148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeLinks(forwardLinks, true);
136248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                forwardLinksValid = true;
13633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
136448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return forwardLinks;
13653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
136748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private PackedMap<Interval, MutableInt> getBackwardLinks() {
136848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (backwardLinks == null) {
136948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                backwardLinks = createLinks(false);
13703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
137148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!backwardLinksValid) {
137248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeLinks(backwardLinks, false);
137348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                backwardLinksValid = true;
137448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
137548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return backwardLinks;
13763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
13773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
137848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void include(List<Arc> arcs, Interval key, MutableInt size,
1379edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne                boolean ignoreIfAlreadyPresent) {
138048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            /*
138148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Remove self referential links.
138248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            These appear:
138348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                . as parental constraints when GridLayout has no children
138448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                . when components have been marked as GONE
138548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            */
138648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (key.size() == 0) {
138748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                return;
13883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
138948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // this bit below should really be computed outside here -
139048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // its just to stop default (row/col > 0) constraints obliterating valid entries
139148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (ignoreIfAlreadyPresent) {
139248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                for (Arc arc : arcs) {
139348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    Interval span = arc.span;
139448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    if (span.equals(key)) {
139548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        return;
139648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    }
139748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
139848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
139948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            arcs.add(new Arc(key, size));
14003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
14013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
140248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void include(List<Arc> arcs, Interval key, MutableInt size) {
140348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(arcs, key, size, true);
14043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
14053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1406aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        // Group arcs by their first vertex, returning an array of arrays.
14073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // This is linear in the number of arcs.
1408f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        Arc[][] groupArcsByFirstVertex(Arc[] arcs) {
140948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int N = getCount() + 1; // the number of vertices
14103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Arc[][] result = new Arc[N][];
14113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int[] sizes = new int[N];
14123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (Arc arc : arcs) {
14133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                sizes[arc.span.min]++;
14145d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            }
14153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < sizes.length; i++) {
14163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                result[i] = new Arc[sizes[i]];
14173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
14183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            // reuse the sizes array to hold the current last elements as we insert each arc
14193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Arrays.fill(sizes, 0);
14203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (Arc arc : arcs) {
14213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int i = arc.span.min;
14223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                result[i][sizes[i]++] = arc;
14233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
14243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
14253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
14263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
14273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
142848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private Arc[] topologicalSort(final Arc[] arcs) {
142948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return new Object() {
143048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Arc[] result = new Arc[arcs.length];
143148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                int cursor = result.length - 1;
143248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Arc[][] arcsByVertex = groupArcsByFirstVertex(arcs);
14333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int[] visited = new int[getCount() + 1];
14343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
143548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                void walk(int loc) {
143648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    switch (visited[loc]) {
143748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        case NEW: {
143848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            visited[loc] = PENDING;
143948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            for (Arc arc : arcsByVertex[loc]) {
144048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                                walk(arc.span.max);
144148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                                result[cursor--] = arc;
14423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                            }
144348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            visited[loc] = COMPLETE;
144448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            break;
144548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        }
144648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        case PENDING: {
1447b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne                            // le singe est dans l'arbre
144848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            assert false;
144948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            break;
145048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        }
145148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        case COMPLETE: {
145248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                            break;
14533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                        }
14543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    }
14553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
145648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
145748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Arc[] sort() {
145848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    for (int loc = 0, N = arcsByVertex.length; loc < N; loc++) {
145948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                        walk(loc);
146048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    }
146148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    assert cursor == -1;
146248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return result;
146348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
146448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }.sort();
146548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
146648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
146748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private Arc[] topologicalSort(List<Arc> arcs) {
146848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return topologicalSort(arcs.toArray(new Arc[arcs.size()]));
14693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
14703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
147148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void addComponentSizes(List<Arc> result, PackedMap<Interval, MutableInt> links) {
147248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0; i < links.keys.length; i++) {
147348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                Interval key = links.keys[i];
147448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                include(result, key, links.values[i], false);
147548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
147648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
147748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1478aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private Arc[] createArcs() {
147948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            List<Arc> mins = new ArrayList<Arc>();
148048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            List<Arc> maxs = new ArrayList<Arc>();
14813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
148248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add the minimum values from the components.
148348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            addComponentSizes(mins, getForwardLinks());
148448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add the maximum values from the components.
148548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            addComponentSizes(maxs, getBackwardLinks());
14863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
148748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add ordering constraints to prevent row/col sizes from going negative
1488f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            if (orderPreserved) {
148948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                // Add a constraint for every row/col
14903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                for (int i = 0; i < getCount(); i++) {
1491899d5922870c78e0e663bc5661849eb468afc984Philip Milne                    include(mins, new Interval(i, i + 1), new MutableInt(0));
14923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
14933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
149448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
149548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Add the container constraints. Use the version of include that allows
149648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // duplicate entries in case a child spans the entire grid.
149748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int N = getCount();
149848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(mins, new Interval(0, N), parentMin, false);
149948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(maxs, new Interval(N, 0), parentMax, false);
150048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
150148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // Sort
150248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Arc[] sMins = topologicalSort(mins);
150348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            Arc[] sMaxs = topologicalSort(maxs);
150448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
150548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return append(sMins, sMaxs);
150648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
150748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
150848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void computeArcs() {
150948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            // getting the links validates the values that are shared by the arc list
151048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            getForwardLinks();
151148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            getBackwardLinks();
15123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1514aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public Arc[] getArcs() {
15153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (arcs == null) {
1516aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                arcs = createArcs();
15173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
15183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (!arcsValid) {
151948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeArcs();
15203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                arcsValid = true;
15213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
15223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return arcs;
15233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1525aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private boolean relax(int[] locations, Arc entry) {
152648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!entry.valid) {
152748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                return false;
152848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
15293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Interval span = entry.span;
15303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int u = span.min;
15313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int v = span.max;
15323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int value = entry.value.value;
15333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int candidate = locations[u] + value;
1534aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (candidate > locations[v]) {
15353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                locations[v] = candidate;
15363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return true;
15373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
15383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return false;
15393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
15403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1541f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private void init(int[] locations) {
15424a145d72622772b920f60195e80942058984259cPhilip Milne            Arrays.fill(locations, 0);
1543f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1544f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1545f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private String arcsToString(List<Arc> arcs) {
15464a145d72622772b920f60195e80942058984259cPhilip Milne            String var = horizontal ? "x" : "y";
1547f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            StringBuilder result = new StringBuilder();
15484a145d72622772b920f60195e80942058984259cPhilip Milne            boolean first = true;
15494a145d72622772b920f60195e80942058984259cPhilip Milne            for (Arc arc : arcs) {
15504a145d72622772b920f60195e80942058984259cPhilip Milne                if (first) {
15514a145d72622772b920f60195e80942058984259cPhilip Milne                    first = false;
1552f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                } else {
15534a145d72622772b920f60195e80942058984259cPhilip Milne                    result = result.append(", ");
1554f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
1555f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                int src = arc.span.min;
1556f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                int dst = arc.span.max;
1557f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                int value = arc.value.value;
1558f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                result.append((src < dst) ?
1559edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne                        var + dst + "-" + var + src + ">=" + value :
1560edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne                        var + src + "-" + var + dst + "<=" + -value);
1561f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1562f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            }
1563f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return result.toString();
1564f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1565f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1566f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private void logError(String axisName, Arc[] arcs, boolean[] culprits0) {
1567f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            List<Arc> culprits = new ArrayList<Arc>();
1568f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            List<Arc> removed = new ArrayList<Arc>();
1569f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            for (int c = 0; c < arcs.length; c++) {
1570f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                Arc arc = arcs[c];
1571f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                if (culprits0[c]) {
1572f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    culprits.add(arc);
1573f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
1574f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                if (!arc.valid) {
1575f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    removed.add(arc);
1576f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
1577f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            }
1578465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell            mPrinter.println(axisName + " constraints: " + arcsToString(culprits) +
1579211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne                    " are inconsistent; permanently removing: " + arcsToString(removed) + ". ");
1580f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        }
1581f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1582aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        /*
1583aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N)
1584aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1585aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        GridLayout converts its requirements into a system of linear constraints of the
1586aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        form:
1587aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1588aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        x[i] - x[j] < a[k]
1589aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1590aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Where the x[i] are variables and the a[k] are constants.
1591aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1592aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        For example, if the variables were instead labeled x, y, z we might have:
1593aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1594aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            x - y < 17
1595aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            y - z < 23
1596aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            z - x < 42
1597aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1598aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        This is a special case of the Linear Programming problem that is, in turn,
1599aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        equivalent to the single-source shortest paths problem on a digraph, for
1600aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        which the O(n^2) Bellman-Ford algorithm the most commonly used general solution.
1601aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        */
160248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void solve(Arc[] arcs, int[] locations) {
1603f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            String axisName = horizontal ? "horizontal" : "vertical";
16043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
1605f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            boolean[] originalCulprits = null;
16063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1607f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            for (int p = 0; p < arcs.length; p++) {
1608f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                init(locations);
1609f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1610f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                // We take one extra pass over traditional Bellman-Ford (and omit their final step)
1611f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                for (int i = 0; i < N; i++) {
1612f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    boolean changed = false;
1613f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    for (int j = 0, length = arcs.length; j < length; j++) {
1614f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        changed |= relax(locations, arcs[j]);
1615f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    }
1616f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    if (!changed) {
1617f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        if (originalCulprits != null) {
1618f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                            logError(axisName, arcs, originalCulprits);
1619f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        }
1620f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        return;
16213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    }
16223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
162348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1624f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                boolean[] culprits = new boolean[arcs.length];
1625f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                for (int i = 0; i < N; i++) {
1626f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    for (int j = 0, length = arcs.length; j < length; j++) {
1627f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        culprits[j] |= relax(locations, arcs[j]);
1628f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    }
1629f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                }
163048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1631f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                if (p == 0) {
1632f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    originalCulprits = culprits;
163348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
1634f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1635f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                for (int i = 0; i < arcs.length; i++) {
1636f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                    if (culprits[i]) {
1637f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        Arc arc = arcs[i];
1638f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        // Only remove max values, min values alone cannot be inconsistent
1639f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        if (arc.span.min < arc.span.max) {
1640f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                            continue;
1641f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        }
1642f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        arc.valid = false;
1643f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne                        break;
164448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    }
164548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
164648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
16473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
16483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1649aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private void computeMargins(boolean leading) {
1650aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            int[] margins = leading ? leadingMargins : trailingMargins;
1651b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne            for (int i = 0, N = getChildCount(); i < N; i++) {
16523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                View c = getChildAt(i);
1653d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne                if (c.getVisibility() == View.GONE) continue;
16543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                LayoutParams lp = getLayoutParams(c);
165593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
165693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Interval span = spec.span;
16573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int index = leading ? span.min : span.max;
16584c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne                margins[index] = max(margins[index], getMargin1(c, horizontal, leading));
16593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
16603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
16613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1662f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        // External entry points
1663f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
1664f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int[] getLeadingMargins() {
1665aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (leadingMargins == null) {
1666aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                leadingMargins = new int[getCount() + 1];
1667aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1668aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (!leadingMarginsValid) {
1669aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                computeMargins(true);
1670aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                leadingMarginsValid = true;
1671aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1672aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            return leadingMargins;
1673aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
1674aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1675f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int[] getTrailingMargins() {
1676aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (trailingMargins == null) {
1677aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                trailingMargins = new int[getCount() + 1];
1678aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1679aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (!trailingMarginsValid) {
1680aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                computeMargins(false);
1681aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                trailingMarginsValid = true;
1682aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
1683aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            return trailingMargins;
1684aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
16853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
168648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void computeLocations(int[] a) {
1687f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            solve(getArcs(), a);
16884a145d72622772b920f60195e80942058984259cPhilip Milne            if (!orderPreserved) {
16894a145d72622772b920f60195e80942058984259cPhilip Milne                // Solve returns the smallest solution to the constraint system for which all
16904a145d72622772b920f60195e80942058984259cPhilip Milne                // values are positive. One value is therefore zero - though if the row/col
16914a145d72622772b920f60195e80942058984259cPhilip Milne                // order is not preserved this may not be the first vertex. For consistency,
16924a145d72622772b920f60195e80942058984259cPhilip Milne                // translate all the values so that they measure the distance from a[0]; the
16934a145d72622772b920f60195e80942058984259cPhilip Milne                // leading edge of the parent. After this transformation some values may be
16944a145d72622772b920f60195e80942058984259cPhilip Milne                // negative.
16954a145d72622772b920f60195e80942058984259cPhilip Milne                int a0 = a[0];
16964a145d72622772b920f60195e80942058984259cPhilip Milne                for (int i = 0, N = a.length; i < N; i++) {
16974a145d72622772b920f60195e80942058984259cPhilip Milne                    a[i] = a[i] - a0;
16984a145d72622772b920f60195e80942058984259cPhilip Milne                }
16994a145d72622772b920f60195e80942058984259cPhilip Milne            }
17003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1702f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int[] getLocations() {
1703aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            if (locations == null) {
1704aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                int N = getCount() + 1;
1705aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                locations = new int[N];
1706aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            }
170748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            if (!locationsValid) {
170848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                computeLocations(locations);
170948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                locationsValid = true;
171048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
1711aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            return locations;
17123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1714aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private int size(int[] locations) {
17154a145d72622772b920f60195e80942058984259cPhilip Milne            // The parental edges are attached to vertices 0 and N - even when order is not
17164a145d72622772b920f60195e80942058984259cPhilip Milne            // being preserved and other vertices fall outside this range. Measure the distance
17174a145d72622772b920f60195e80942058984259cPhilip Milne            // between vertices 0 and N, assuming that locations[0] = 0.
17184a145d72622772b920f60195e80942058984259cPhilip Milne            return locations[getCount()];
1719aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        }
1720aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
172148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private void setParentConstraints(int min, int max) {
172248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            parentMin.value = min;
172348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            parentMax.value = -max;
172448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            locationsValid = false;
17253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
172748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private int getMeasure(int min, int max) {
172848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            setParentConstraints(min, max);
172948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return size(getLocations());
173048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
1731aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1732f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public int getMeasure(int measureSpec) {
173348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int mode = MeasureSpec.getMode(measureSpec);
173448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int size = MeasureSpec.getSize(measureSpec);
173548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            switch (mode) {
173648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                case MeasureSpec.UNSPECIFIED: {
173793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                    return getMeasure(0, MAX_SIZE);
173848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
173948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                case MeasureSpec.EXACTLY: {
174048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return getMeasure(size, size);
174148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
174248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                case MeasureSpec.AT_MOST: {
174348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return getMeasure(0, size);
174448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
174548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                default: {
174648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    assert false;
174748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return 0;
174848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                }
17493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
175048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
1751aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
1752f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void layout(int size) {
175348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            setParentConstraints(size, size);
175448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            getLocations();
17553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1757f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void invalidateStructure() {
17584a145d72622772b920f60195e80942058984259cPhilip Milne            maxIndex = UNDEFINED;
1759aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
17603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            groupBounds = null;
176148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            forwardLinks = null;
176248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            backwardLinks = null;
176348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1764aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            leadingMargins = null;
1765aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            trailingMargins = null;
1766c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne            arcs = null;
176748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1768aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            locations = null;
17693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            invalidateValues();
17713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1773f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void invalidateValues() {
17743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            groupBoundsValid = false;
177548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            forwardLinksValid = false;
177648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            backwardLinksValid = false;
177748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
1778aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            leadingMarginsValid = false;
1779aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            trailingMarginsValid = false;
178048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            arcsValid = false;
178148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
178248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            locationsValid = false;
17833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
17843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
17853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
17863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
17873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Layout information associated with each of the children of a GridLayout.
17883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
17893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * GridLayout supports both row and column spanning and arbitrary forms of alignment within
17903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * each cell group. The fundamental parameters associated with each cell group are
17913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * gathered into their vertical and horizontal components and stored
179293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * in the {@link #rowSpec} and {@link #columnSpec} layout parameters.
17936216e87fe8ad3273855233965b34049d22763e94Philip Milne     * {@link GridLayout.Spec Specs} are immutable structures
1794b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne     * and may be shared between the layout parameters of different children.
17953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
179693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * The row and column specs contain the leading and trailing indices along each axis
1797aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     * and together specify the four grid indices that delimit the cells of this cell group.
17983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
179993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * The  alignment properties of the row and column specs together specify
18003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * both aspects of alignment within the cell group. It is also possible to specify a child's
18013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
18023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * method.
1803f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1804f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * <h4>WRAP_CONTENT and MATCH_PARENT</h4>
1805f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1806f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * Because the default values of the {@link #width} and {@link #height}
1807f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * properties are both {@link #WRAP_CONTENT}, this value never needs to be explicitly
1808f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * declared in the layout parameters of GridLayout's children. In addition,
1809f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * GridLayout does not distinguish the special size value {@link #MATCH_PARENT} from
1810f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * {@link #WRAP_CONTENT}. A component's ability to expand to the size of the parent is
1811f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * instead controlled by the principle of <em>flexibility</em>,
1812f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * as discussed in {@link GridLayout}.
1813f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1814f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * <h4>Summary</h4>
1815f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
1816f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * You should not need to use either of the special size values:
1817f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * {@code WRAP_CONTENT} or {@code MATCH_PARENT} when configuring the children of
1818f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * a GridLayout.
18193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
18203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <h4>Default values</h4>
18213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
18223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <ul>
18233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #width} = {@link #WRAP_CONTENT}</li>
18243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #height} = {@link #WRAP_CONTENT}</li>
18253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #topMargin} = 0 when
18263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
18277fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
18283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
18293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #leftMargin} = 0 when
18303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
18317fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
18323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
18333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #bottomMargin} = 0 when
18343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
18357fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
18363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
18373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *     <li>{@link #rightMargin} = 0 when
18383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
18397fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     *          {@code false}; otherwise {@link #UNDEFINED}, to
18403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *          indicate that a default value should be computed on demand. </li>
1841f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li>
1842f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li>
1843f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li>
1844f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li>
1845f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *     <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li>
18466216e87fe8ad3273855233965b34049d22763e94Philip Milne     *     <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li>
18473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * </ul>
18483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
1849f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * See {@link GridLayout} for a more complete description of the conventions
1850f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     * used by GridLayout in the interpretation of the properties of this class.
1851f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne     *
18523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_row
18533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan
18543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_column
18553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan
18563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
18573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
18583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static class LayoutParams extends MarginLayoutParams {
18593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Default values
18613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_WIDTH = WRAP_CONTENT;
18633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_HEIGHT = WRAP_CONTENT;
18643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_MARGIN = UNDEFINED;
18653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_ROW = UNDEFINED;
18663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_COLUMN = UNDEFINED;
1867f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne        private static final Interval DEFAULT_SPAN = new Interval(UNDEFINED, UNDEFINED + 1);
18683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int DEFAULT_SPAN_SIZE = DEFAULT_SPAN.size();
18693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // TypedArray indices
18713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1872b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int MARGIN = R.styleable.ViewGroup_MarginLayout_layout_margin;
1873b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int LEFT_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginLeft;
1874b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int TOP_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginTop;
1875b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int RIGHT_MARGIN =
1876b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne                R.styleable.ViewGroup_MarginLayout_layout_marginRight;
18773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static final int BOTTOM_MARGIN =
1878b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne                R.styleable.ViewGroup_MarginLayout_layout_marginBottom;
18793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
1880b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
1881b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
18825d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
1883b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int ROW = R.styleable.GridLayout_Layout_layout_row;
1884b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan;
18855d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
1886b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne        private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity;
18873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Instance variables
18893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
18903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
1891f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne         * The spec that defines the vertical characteristics of the cell group
18923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * described by these layout parameters.
1893d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * If an assignment is made to this field after a measurement or layout operation
1894d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * has already taken place, a call to
1895d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
1896d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * must be made to notify GridLayout of the change. GridLayout is normally able
1897d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * to detect when code fails to observe this rule, issue a warning and take steps to
1898d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * compensate for the omission. This facility is implemented on a best effort basis
1899d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * and should not be relied upon in production code - so it is best to include the above
1900d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * calls to remove the warnings as soon as it is practical.
19013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
1902f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public Spec rowSpec = Spec.UNDEFINED;
1903f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
19043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
1905f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne         * The spec that defines the horizontal characteristics of the cell group
19063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * described by these layout parameters.
1907d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * If an assignment is made to this field after a measurement or layout operation
1908d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * has already taken place, a call to
1909d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
1910d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * must be made to notify GridLayout of the change. GridLayout is normally able
1911d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * to detect when code fails to observe this rule, issue a warning and take steps to
1912d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * compensate for the omission. This facility is implemented on a best effort basis
1913d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * and should not be relied upon in production code - so it is best to include the above
1914d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne         * calls to remove the warnings as soon as it is practical.
19153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
1916f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public Spec columnSpec = Spec.UNDEFINED;
19173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Constructors
19193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private LayoutParams(
19213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int width, int height,
19223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int left, int top, int right, int bottom,
192393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                Spec rowSpec, Spec columnSpec) {
19243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            super(width, height);
19253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            setMargins(left, top, right, bottom);
192693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            this.rowSpec = rowSpec;
192793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            this.columnSpec = columnSpec;
19283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
193193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * Constructs a new LayoutParams instance for this <code>rowSpec</code>
193293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * and <code>columnSpec</code>. All other fields are initialized with
19333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * default values as defined in {@link LayoutParams}.
19343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
193593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * @param rowSpec    the rowSpec
193693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * @param columnSpec the columnSpec
19373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
193893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        public LayoutParams(Spec rowSpec, Spec columnSpec) {
19393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
19403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
194193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne                    rowSpec, columnSpec);
19423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
19453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
19463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
19473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams() {
1948f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this(Spec.UNDEFINED, Spec.UNDEFINED);
19493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Copying constructors
19523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
19543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * {@inheritDoc}
19553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
19563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams(ViewGroup.LayoutParams params) {
19573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            super(params);
19583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
19613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * {@inheritDoc}
19623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
19633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams(MarginLayoutParams params) {
19643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            super(params);
19653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
19680a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette         * Copy constructor. Clones the width, height, margin values, row spec,
19690a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette         * and column spec of the source.
19700a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette         *
19710a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette         * @param source The layout params to copy from.
19723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
19730a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette        public LayoutParams(LayoutParams source) {
19740a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette            super(source);
19750a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette
19760a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette            this.rowSpec = source.rowSpec;
19770a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette            this.columnSpec = source.columnSpec;
19783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // AttributeSet constructors
19813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
19833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * {@inheritDoc}
19843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
19853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Values not defined in the attribute set take the default values
19863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * defined in {@link LayoutParams}.
19873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
19883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public LayoutParams(Context context, AttributeSet attrs) {
19895125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            super(context, attrs);
19905125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            reInitSuper(context, attrs);
19915125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            init(context, attrs);
19923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
19933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Implementation
19953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
19963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Reinitialise the margins using a different default policy than MarginLayoutParams.
19973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // Here we use the value UNDEFINED (as distinct from zero) to represent the undefined state
19983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // so that a layout manager default can be accessed post set up. We need this as, at the
19993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // point of installation, we do not know how many rows/cols there are and therefore
20003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // which elements are positioned next to the container's trailing edges. We need to
20013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // know this as margins around the container's boundary should have different
20023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // defaults to those between peers.
20033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        // This method could be parametrized and moved into MarginLayout.
20053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private void reInitSuper(Context context, AttributeSet attrs) {
2006b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne            TypedArray a =
2007b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne                    context.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
20083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            try {
20093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN);
20103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.leftMargin = a.getDimensionPixelSize(LEFT_MARGIN, margin);
20123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.topMargin = a.getDimensionPixelSize(TOP_MARGIN, margin);
20133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.rightMargin = a.getDimensionPixelSize(RIGHT_MARGIN, margin);
20143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                this.bottomMargin = a.getDimensionPixelSize(BOTTOM_MARGIN, margin);
20153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            } finally {
20163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                a.recycle();
20173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
20183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20205125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        private void init(Context context, AttributeSet attrs) {
2021b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout);
20223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            try {
20235125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                int gravity = a.getInt(GRAVITY, Gravity.NO_GRAVITY);
20243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20251e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne                int column = a.getInt(COLUMN, DEFAULT_COLUMN);
20265125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                int colSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
2027899d5922870c78e0e663bc5661849eb468afc984Philip Milne                this.columnSpec = spec(column, colSpan, getAlignment(gravity, true));
20283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20291e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne                int row = a.getInt(ROW, DEFAULT_ROW);
20301e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne                int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
2031899d5922870c78e0e663bc5661849eb468afc984Philip Milne                this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false));
20323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            } finally {
20333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                a.recycle();
20343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
20353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
20387fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}.
20396216e87fe8ad3273855233965b34049d22763e94Philip Milne         * See {@link Gravity}.
20403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
20417fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * @param gravity the new gravity value
20423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
20433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
20443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
20453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public void setGravity(int gravity) {
20465125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            rowSpec = rowSpec.copyWriteAlignment(getAlignment(gravity, false));
20475125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            columnSpec = columnSpec.copyWriteAlignment(getAlignment(gravity, true));
20483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
20513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        protected void setBaseAttributes(TypedArray attributes, int widthAttr, int heightAttr) {
20523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.width = attributes.getLayoutDimension(widthAttr, DEFAULT_WIDTH);
20533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT);
20543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2056f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final void setRowSpecSpan(Interval span) {
205793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            rowSpec = rowSpec.copyWriteSpan(span);
20583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2060f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final void setColumnSpecSpan(Interval span) {
206193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            columnSpec = columnSpec.copyWriteSpan(span);
20623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
2063d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
2064d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        @Override
2065d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        public boolean equals(Object o) {
2066d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (this == o) return true;
2067d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (o == null || getClass() != o.getClass()) return false;
2068d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
2069d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            LayoutParams that = (LayoutParams) o;
2070d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
2071d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (!columnSpec.equals(that.columnSpec)) return false;
2072d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            if (!rowSpec.equals(that.rowSpec)) return false;
2073d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
2074d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            return true;
2075d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        }
2076d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne
2077d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        @Override
2078d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        public int hashCode() {
2079d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            int result = rowSpec.hashCode();
2080d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            result = 31 * result + columnSpec.hashCode();
2081d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne            return result;
2082d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne        }
20833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
20843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2085aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
2086aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs.
2087aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles.
2088aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
2089f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class Arc {
20903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final Interval span;
2091aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public final MutableInt value;
209248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public boolean valid = true;
20933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2094aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        public Arc(Interval span, MutableInt value) {
20953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.span = span;
20963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.value = value;
20973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
20983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
20993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
21003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public String toString() {
210148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return span + " " + (!valid ? "+>" : "->") + " " + value;
21023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
21043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    // A mutable Integer - used to avoid heap allocation during the layout operation
21063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2107f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class MutableInt {
21083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int value;
21093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2110f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public MutableInt() {
21113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            reset();
21123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2114f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public MutableInt(int value) {
21153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.value = value;
21163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2118f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public void reset() {
21193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            value = Integer.MIN_VALUE;
21203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
212148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
212248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        @Override
212348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public String toString() {
212448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return Integer.toString(value);
212548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
212648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne    }
212748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
2128f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class Assoc<K, V> extends ArrayList<Pair<K, V>> {
212948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private final Class<K> keyType;
213048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private final Class<V> valueType;
213148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
213248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        private Assoc(Class<K> keyType, Class<V> valueType) {
213348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            this.keyType = keyType;
213448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            this.valueType = valueType;
213548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
213648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
2137f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) {
213848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return new Assoc<K, V>(keyType, valueType);
213948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
214048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
214148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public void put(K key, V value) {
214248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            add(Pair.create(key, value));
214348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
214448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
214548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        @SuppressWarnings(value = "unchecked")
214648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        public PackedMap<K, V> pack() {
214748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            int N = size();
214848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            K[] keys = (K[]) Array.newInstance(keyType, N);
214948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            V[] values = (V[]) Array.newInstance(valueType, N);
215048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            for (int i = 0; i < N; i++) {
215148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                keys[i] = get(i).first;
215248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                values[i] = get(i).second;
215348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
215448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            return new PackedMap<K, V>(keys, values);
215548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
21563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
21573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2158aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
2159aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    This data structure is used in place of a Map where we have an index that refers to the order
2160aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    in which each key/value pairs were added to the map. In this case we store keys and values
2161aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    in arrays of a length that is equal to the number of unique keys. We also maintain an
2162aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    array of indexes from insertion order to the compacted arrays of keys and values.
2163aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
2164aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    Note that behavior differs from that of a LinkedHashMap in that repeated entries
2165aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    *do* get added multiples times. So the length of index is equals to the number of
2166aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    items added.
2167aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
2168aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    This is useful in the GridLayout class where we can rely on the order of children not
2169aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    changing during layout - to use integer-based lookup for our internal structures
2170aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    rather than using (and storing) an implementation of Map<Key, ?>.
2171aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne     */
21723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    @SuppressWarnings(value = "unchecked")
2173f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class PackedMap<K, V> {
21743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final int[] index;
21753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final K[] keys;
21763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final V[] values;
21773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private PackedMap(K[] keys, V[] values) {
21793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.index = createIndex(keys);
21803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2181aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            this.keys = compact(keys, index);
2182aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            this.values = compact(values, index);
21833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2185f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        public V getValue(int i) {
21863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return values[index[i]];
21873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
21883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private static <K> int[] createIndex(K[] keys) {
21903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int size = keys.length;
21913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int[] result = new int[size];
21923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
21933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Map<K, Integer> keyToIndex = new HashMap<K, Integer>();
21943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < size; i++) {
21953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                K key = keys[i];
21963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                Integer index = keyToIndex.get(key);
21973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                if (index == null) {
21983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    index = keyToIndex.size();
21993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    keyToIndex.put(key, index);
22003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                }
22013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                result[i] = index;
22023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
22033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
22043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2206aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        /*
2207aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        Create a compact array of keys or values using the supplied index.
2208aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne         */
2209aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne        private static <K> K[] compact(K[] a, int[] index) {
2210aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            int size = a.length;
2211aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne            Class<?> componentType = a.getClass().getComponentType();
221251f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne            K[] result = (K[]) Array.newInstance(componentType, max2(index, -1) + 1);
22133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
22143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            // this overwrite duplicates, retaining the last equivalent entry
22153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            for (int i = 0; i < size; i++) {
2216aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne                result[index[i]] = a[i];
22173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
22183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
22193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
22213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2222aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    /*
222393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    For each group (with a given alignment) we need to store the amount of space required
22247fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne    before the alignment point and the amount of space required after it. One side of this
222547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    calculation is always 0 for START and END alignments but we don't make use of this.
2226aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
2227aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    simple optimisations are possible.
2228aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
2229aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    The general algorithm therefore is to create a Map (actually a PackedMap) from
223093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    group to Bounds and to loop through all Views in the group taking the maximum
2231aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    of the values for each View.
2232aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne    */
2233f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static class Bounds {
22347fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne        public int before;
22357fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne        public int after;
22365125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        public int flexibility; // we're flexible iff all included specs are flexible
22373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
22383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        private Bounds() {
22393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            reset();
22403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2242a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        protected void reset() {
22437fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            before = Integer.MIN_VALUE;
22447fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            after = Integer.MIN_VALUE;
22455125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            flexibility = CAN_STRETCH; // from the above, we're flexible when empty
22463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2248a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        protected void include(int before, int after) {
22497fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            this.before = max(this.before, before);
22507fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            this.after = max(this.after, after);
22513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
225348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        protected int size(boolean min) {
22545d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            if (!min) {
22555125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne                if (canStretch(flexibility)) {
22565d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne                    return MAX_SIZE;
22575d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne                }
225848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            }
22597fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne            return before + after;
22603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
22621557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne        protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
22637a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne            return before - a.getAlignmentValue(c, size, gl.getLayoutMode());
226448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        }
226548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
22661557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne        protected final void include(GridLayout gl, View c, Spec spec, Axis axis) {
22675125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            this.flexibility &= spec.getFlexibility();
22681557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            boolean horizontal = axis.horizontal;
22691557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            int size = gl.getMeasurementIncludingMargin(c, horizontal);
22701557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne            Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
22714c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            // todo test this works correctly when the returned value is UNDEFINED
22727a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne            int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode());
227348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne            include(before, size - before);
2274a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
2275a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
22763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
22773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public String toString() {
22783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return "Bounds{" +
22797fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne                    "before=" + before +
22807fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne                    ", after=" + after +
22813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                    '}';
22823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
22833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
22843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
22853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
22863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * An Interval represents a contiguous range of values that lie between
22873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * the interval's {@link #min} and {@link #max} values.
22883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
22893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Intervals are immutable so may be passed as values and used as keys in hash tables.
22903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * It is not necessary to have multiple instances of Intervals which have the same
22913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * {@link #min} and {@link #max} values.
22923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
22937fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * Intervals are often written as {@code [min, max]} and represent the set of values
22947fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne     * {@code x} such that {@code min <= x < max}.
22953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2296f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    final static class Interval {
22973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
22983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * The minimum value.
22993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
23003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final int min;
2301aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne
23023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
23033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * The maximum value.
23043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
23053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public final int max;
23063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
23087fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * Construct a new Interval, {@code interval}, where:
23093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * <ul>
23107fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         *     <li> {@code interval.min = min} </li>
23117fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         *     <li> {@code interval.max = max} </li>
23123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * </ul>
23133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
23143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @param min the minimum value.
23153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @param max the maximum value.
23163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
23173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public Interval(int min, int max) {
23183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.min = min;
23193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            this.max = max;
23203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2322f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        int size() {
23233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return max - min;
23243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2326f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        Interval inverse() {
23273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return new Interval(max, min);
23283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
23317fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * Returns {@code true} if the {@link #getClass class},
23327fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * {@link #min} and {@link #max} properties of this Interval and the
23337fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * supplied parameter are pairwise equal; {@code false} otherwise.
23343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
23357fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * @param that the object to compare this interval with
23363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
23373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @return {@code true} if the specified object is equal to this
23387fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         *         {@code Interval}, {@code false} otherwise.
23393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
23403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
23413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean equals(Object that) {
23423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (this == that) {
23433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return true;
23443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
23453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (that == null || getClass() != that.getClass()) {
23463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
23473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
23483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            Interval interval = (Interval) that;
23503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (max != interval.max) {
23523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
23533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
23544c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            //noinspection RedundantIfStatement
23553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (min != interval.min) {
23563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
23573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
23583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return true;
23603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
23633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int hashCode() {
23643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int result = min;
23653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            result = 31 * result + max;
23663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
23673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
23693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
23703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public String toString() {
23713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return "[" + min + ", " + max + "]";
23723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
23733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
23743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2375899d5922870c78e0e663bc5661849eb468afc984Philip Milne    /**
2376899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * A Spec defines the horizontal or vertical characteristics of a group of
23774a145d72622772b920f60195e80942058984259cPhilip Milne     * cells. Each spec. defines the <em>grid indices</em> and <em>alignment</em>
23784a145d72622772b920f60195e80942058984259cPhilip Milne     * along the appropriate axis.
2379899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * <p>
2380899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The <em>grid indices</em> are the leading and trailing edges of this cell group.
2381899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * See {@link GridLayout} for a description of the conventions used by GridLayout
2382899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * for grid indices.
2383899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * <p>
2384899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * The <em>alignment</em> property specifies how cells should be aligned in this group.
2385899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * For row groups, this specifies the vertical alignment.
2386899d5922870c78e0e663bc5661849eb468afc984Philip Milne     * For column groups, this specifies the horizontal alignment.
23874a145d72622772b920f60195e80942058984259cPhilip Milne     * <p>
23884a145d72622772b920f60195e80942058984259cPhilip Milne     * Use the following static methods to create specs:
23894a145d72622772b920f60195e80942058984259cPhilip Milne     * <ul>
23904a145d72622772b920f60195e80942058984259cPhilip Milne     *   <li>{@link #spec(int)}</li>
23914a145d72622772b920f60195e80942058984259cPhilip Milne     *   <li>{@link #spec(int, int)}</li>
23924a145d72622772b920f60195e80942058984259cPhilip Milne     *   <li>{@link #spec(int, Alignment)}</li>
23934a145d72622772b920f60195e80942058984259cPhilip Milne     *   <li>{@link #spec(int, int, Alignment)}</li>
23944a145d72622772b920f60195e80942058984259cPhilip Milne     * </ul>
23954a145d72622772b920f60195e80942058984259cPhilip Milne     *
2396899d5922870c78e0e663bc5661849eb468afc984Philip Milne     */
239793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    public static class Spec {
2398f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        static final Spec UNDEFINED = spec(GridLayout.UNDEFINED);
2399f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne
2400f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final boolean startDefined;
240148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        final Interval span;
240293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        final Alignment alignment;
24033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2404f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private Spec(boolean startDefined, Interval span, Alignment alignment) {
2405f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this.startDefined = startDefined;
24065d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            this.span = span;
24075d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne            this.alignment = alignment;
24085d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne        }
24095d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
2410f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        private Spec(boolean startDefined, int start, int size, Alignment alignment) {
2411f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            this(startDefined, new Interval(start, start + size), alignment);
24123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2414f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final Spec copyWriteSpan(Interval span) {
2415f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return new Spec(startDefined, span, alignment);
24163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2418f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final Spec copyWriteAlignment(Alignment alignment) {
2419f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne            return new Spec(startDefined, span, alignment);
24205125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
24215125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
2422f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        final int getFlexibility() {
24234c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH;
24243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
242793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * Returns {@code true} if the {@code class}, {@code alignment} and {@code span}
242893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * properties of this Spec and the supplied parameter are pairwise equal,
24297fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne         * {@code false} otherwise.
24303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
243193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         * @param that the object to compare this spec with
24323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
24333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * @return {@code true} if the specified object is equal to this
243493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne         *         {@code Spec}; {@code false} otherwise
24353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
24363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
24373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public boolean equals(Object that) {
24383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (this == that) {
24393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return true;
24403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
24413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            if (that == null || getClass() != that.getClass()) {
24423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
24433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
24443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
244593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            Spec spec = (Spec) that;
24463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
244793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            if (!alignment.equals(spec.alignment)) {
24483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
24493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
24504c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne            //noinspection RedundantIfStatement
245193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne            if (!span.equals(spec.span)) {
24523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne                return false;
24533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            }
24543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return true;
24563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        @Override
24593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        public int hashCode() {
24603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int result = span.hashCode();
24613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            result = 31 * result + alignment.hashCode();
24623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return result;
24633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
24643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
24653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
24663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
246793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * Return a Spec, {@code spec}, where:
246893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * <ul>
246993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.span = [start, start + size]} </li>
247093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.alignment = alignment} </li>
247193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * </ul>
24727b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * <p>
24737b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * To leave the start index undefined, use the value {@link #UNDEFINED}.
247493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *
247593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param start     the start
247693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param size      the size
247793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param alignment the alignment
247893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     */
247993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    public static Spec spec(int start, int size, Alignment alignment) {
2480f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne        return new Spec(start != UNDEFINED, start, size, alignment);
248193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    }
248293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne
248393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    /**
248493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * Return a Spec, {@code spec}, where:
248593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * <ul>
248693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.span = [start, start + 1]} </li>
248793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *     <li> {@code spec.alignment = alignment} </li>
248893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * </ul>
24897b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * <p>
24907b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * To leave the start index undefined, use the value {@link #UNDEFINED}.
249193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     *
249293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param start     the start index
249393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * @param alignment the alignment
24947b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     *
24957b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * @see #spec(int, int, Alignment)
249693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     */
249793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    public static Spec spec(int start, Alignment alignment) {
249893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne        return spec(start, 1, alignment);
249993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    }
250093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne
250193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne    /**
25025125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * Return a Spec, {@code spec}, where:
25035125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * <ul>
25045125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *     <li> {@code spec.span = [start, start + size]} </li>
25055125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * </ul>
25067b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * <p>
25077b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * To leave the start index undefined, use the value {@link #UNDEFINED}.
25085125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *
25095125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * @param start     the start
25105125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * @param size      the size
25117b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     *
25127b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * @see #spec(int, Alignment)
25135125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     */
25145125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    public static Spec spec(int start, int size) {
25155125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return spec(start, size, UNDEFINED_ALIGNMENT);
25165125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
25175125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
25185125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    /**
25195125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * Return a Spec, {@code spec}, where:
25205125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * <ul>
25215125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *     <li> {@code spec.span = [start, start + 1]} </li>
25225125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * </ul>
25237b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * <p>
25247b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * To leave the start index undefined, use the value {@link #UNDEFINED}.
25255125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     *
25265125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     * @param start     the start index
25277b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     *
25287b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne     * @see #spec(int, int)
25295125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne     */
25305125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    public static Spec spec(int start) {
25315125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        return spec(start, 1);
25325125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    }
25335125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
25345125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    /**
25353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Alignments specify where a view should be placed within a cell group and
25363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * what size it should be.
25373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
253893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec}
253993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an
254093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * {@code alignment}. Overall placement of the view in the cell
25413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * group is specified by the two alignments which act along each axis independently.
25423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
2543a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne     *  The GridLayout class defines the most common alignments used in general layout:
25446216e87fe8ad3273855233965b34049d22763e94Philip Milne     * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #START},
25456216e87fe8ad3273855233965b34049d22763e94Philip Milne     * {@link #END}, {@link #CENTER}, {@link #BASELINE} and {@link #FILL}.
2546a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne     */
2547a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne    /*
2548c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne     * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)},
25493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * to return the appropriate value for the type of alignment being defined.
25503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * The enclosing algorithms position the children
25511e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne     * so that the locations defined by the alignment values
25523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * are the same for all of the views in a group.
25533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * <p>
25543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2555c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    public static abstract class Alignment {
255648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        Alignment() {
2557a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
2558a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
25596216e87fe8ad3273855233965b34049d22763e94Philip Milne        abstract int getGravityOffset(View view, int cellDelta);
25606216e87fe8ad3273855233965b34049d22763e94Philip Milne
25613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
25623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Returns an alignment value. In the case of vertical alignments the value
25633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * returned should indicate the distance from the top of the view to the
25643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * alignment location.
25653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * For horizontal alignments measurement is made from the left edge of the component.
25663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         *
2567c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param view              the view to which this alignment should be applied
2568c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param viewSize          the measured size of the view
25697a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne         * @param mode              the basis of alignment: CLIP or OPTICAL
2570b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne         * @return the alignment value
25713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
25727a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        abstract int getAlignmentValue(View view, int viewSize, int mode);
25733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
25743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        /**
25753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * Returns the size of the view specified by this alignment.
25763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * In the case of vertical alignments this method should return a height; for
25773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         * horizontal alignments this method should return the width.
2578c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * <p>
2579c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * The default implementation returns {@code viewSize}.
2580c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         *
2581c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param view              the view to which this alignment should be applied
2582c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param viewSize          the measured size of the view
2583c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne         * @param cellSize          the size of the cell into which this view will be placed
2584b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne         * @return the aligned size
25853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne         */
25866216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getSizeInCell(View view, int viewSize, int cellSize) {
25873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return viewSize;
25883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
2589a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
259048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne        Bounds getBounds() {
2591a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne            return new Bounds();
2592a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
25933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    }
25943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2595f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static final Alignment UNDEFINED_ALIGNMENT = new Alignment() {
259647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
25976216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
25986216e87fe8ad3273855233965b34049d22763e94Philip Milne            return UNDEFINED;
25996216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
26006216e87fe8ad3273855233965b34049d22763e94Philip Milne
26016216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
26027a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
26035125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne            return UNDEFINED;
26045125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne        }
26055125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    };
26065125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne
260747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    /**
260847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * Indicates that a view should be aligned with the <em>start</em>
260947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * edges of the other views in its cell group.
261047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     */
2611c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    private static final Alignment LEADING = new Alignment() {
261247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
26136216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
26146216e87fe8ad3273855233965b34049d22763e94Philip Milne            return 0;
26156216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
26166216e87fe8ad3273855233965b34049d22763e94Philip Milne
26176216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
26187a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
26193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return 0;
26203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
26213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
26223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
262347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    /**
262447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * Indicates that a view should be aligned with the <em>end</em>
262547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * edges of the other views in its cell group.
262647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     */
2627c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    private static final Alignment TRAILING = new Alignment() {
262847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
26296216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
26306216e87fe8ad3273855233965b34049d22763e94Philip Milne            return cellDelta;
26316216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
26326216e87fe8ad3273855233965b34049d22763e94Philip Milne
26336216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
26347a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
26353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return viewSize;
26363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
26373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
26383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
26393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
26403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>top</em>
26413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
26423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
26433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment TOP = LEADING;
26443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
26453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
26463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>bottom</em>
26473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
26483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
26493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment BOTTOM = TRAILING;
26503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
26513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
265247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * Indicates that a view should be aligned with the <em>start</em>
26533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
26543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
265547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    public static final Alignment START = LEADING;
265647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio
265747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    /**
265847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * Indicates that a view should be aligned with the <em>end</em>
265947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * edges of the other views in its cell group.
266047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     */
266147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    public static final Alignment END = TRAILING;
266247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio
26636216e87fe8ad3273855233965b34049d22763e94Philip Milne    private static Alignment createSwitchingAlignment(final Alignment ltr, final Alignment rtl) {
266447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        return new Alignment() {
266547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio            @Override
26666216e87fe8ad3273855233965b34049d22763e94Philip Milne            int getGravityOffset(View view, int cellDelta) {
26676216e87fe8ad3273855233965b34049d22763e94Philip Milne                return (!view.isLayoutRtl() ? ltr : rtl).getGravityOffset(view, cellDelta);
26686216e87fe8ad3273855233965b34049d22763e94Philip Milne            }
26696216e87fe8ad3273855233965b34049d22763e94Philip Milne
26706216e87fe8ad3273855233965b34049d22763e94Philip Milne            @Override
26717a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne            public int getAlignmentValue(View view, int viewSize, int mode) {
26727a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne                return (!view.isLayoutRtl() ? ltr : rtl).getAlignmentValue(view, viewSize, mode);
267347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio            }
267447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        };
267547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    }
26763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
26773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
26783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>left</em>
26793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * edges of the other views in its cell group.
26803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
26816216e87fe8ad3273855233965b34049d22763e94Philip Milne    public static final Alignment LEFT = createSwitchingAlignment(START, END);
268247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio
268347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio    /**
268447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * Indicates that a view should be aligned with the <em>right</em>
268547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     * edges of the other views in its cell group.
268647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio     */
26876216e87fe8ad3273855233965b34049d22763e94Philip Milne    public static final Alignment RIGHT = createSwitchingAlignment(END, START);
26883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
26893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
26903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be <em>centered</em> with the other views in its cell group.
269193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link
269293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * LayoutParams#columnSpec columnSpecs}.
26933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2694c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    public static final Alignment CENTER = new Alignment() {
269547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
26966216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
26976216e87fe8ad3273855233965b34049d22763e94Philip Milne            return cellDelta >> 1;
26986216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
26996216e87fe8ad3273855233965b34049d22763e94Philip Milne
27006216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
27017a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
27023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return viewSize >> 1;
27033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
27043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
27053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
27063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
27073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should be aligned with the <em>baselines</em>
27083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * of the other views in its cell group.
270993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}.
27103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     *
27113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * @see View#getBaseline()
27123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
2713c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne    public static final Alignment BASELINE = new Alignment() {
271447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
27156216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
27166216e87fe8ad3273855233965b34049d22763e94Philip Milne            return 0; // baseline gravity is top
27176216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
27186216e87fe8ad3273855233965b34049d22763e94Philip Milne
27196216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
27207a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
2721a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne            if (view.getVisibility() == GONE) {
2722a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne                return 0;
2723a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne            }
27243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            int baseline = view.getBaseline();
27257b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne            return baseline == -1 ? UNDEFINED : baseline;
2726a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        }
2727a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2728a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        @Override
2729a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne        public Bounds getBounds() {
2730a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne            return new Bounds() {
2731a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                /*
2732a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                In a baseline aligned row in which some components define a baseline
2733a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                and some don't, we need a third variable to properly account for all
2734a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                the sizes. This tracks the maximum size of all the components -
2735a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                including those that don't define a baseline.
2736a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                */
2737a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                private int size;
2738a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2739a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
2740a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                protected void reset() {
2741a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                    super.reset();
274248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    size = Integer.MIN_VALUE;
2743a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2744a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2745a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
2746a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                protected void include(int before, int after) {
2747a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                    super.include(before, after);
2748a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                    size = max(size, before + after);
2749a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2750a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2751a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
275248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                protected int size(boolean min) {
275348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne                    return max(super.size(min), size);
2754a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2755a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne
2756a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                @Override
27571557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne                protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) {
27581557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne                    return max(0, super.getOffset(gl, c, a, size, hrz));
2759a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne                }
2760a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne            };
27613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
27623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
27633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
27643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    /**
27653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     * Indicates that a view should expanded to fit the boundaries of its cell group.
276693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and
276793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne     * {@link LayoutParams#columnSpec columnSpecs}.
27683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne     */
27693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    public static final Alignment FILL = new Alignment() {
277047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio        @Override
27716216e87fe8ad3273855233965b34049d22763e94Philip Milne        int getGravityOffset(View view, int cellDelta) {
27726216e87fe8ad3273855233965b34049d22763e94Philip Milne            return 0;
27736216e87fe8ad3273855233965b34049d22763e94Philip Milne        }
27746216e87fe8ad3273855233965b34049d22763e94Philip Milne
27756216e87fe8ad3273855233965b34049d22763e94Philip Milne        @Override
27767a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne        public int getAlignmentValue(View view, int viewSize, int mode) {
27773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return UNDEFINED;
27783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
27793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne
2780c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne        @Override
27816216e87fe8ad3273855233965b34049d22763e94Philip Milne        public int getSizeInCell(View view, int viewSize, int cellSize) {
27823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne            return cellSize;
27833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne        }
27843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne    };
278548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne
2786f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne    static boolean canStretch(int flexibility) {
27875d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne        return (flexibility & CAN_STRETCH) != 0;
27885d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne    }
27895d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne
27905125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne    private static final int INFLEXIBLE = 0;
27914c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne    private static final int CAN_STRETCH = 2;
2792452eec33d667f9e705b57e60948b070536fbc1b4Jim Miller}
2793