Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.widget;
     18 
     19 import com.android.internal.R;
     20 
     21 import android.content.Context;
     22 import android.content.res.TypedArray;
     23 import android.graphics.Canvas;
     24 import android.graphics.drawable.Drawable;
     25 import android.util.AttributeSet;
     26 import android.view.Gravity;
     27 import android.view.View;
     28 import android.view.ViewDebug;
     29 import android.view.ViewGroup;
     30 import android.view.accessibility.AccessibilityEvent;
     31 import android.view.accessibility.AccessibilityNodeInfo;
     32 import android.widget.RemoteViews.RemoteView;
     33 
     34 
     35 /**
     36  * A Layout that arranges its children in a single column or a single row. The direction of
     37  * the row can be set by calling {@link #setOrientation(int) setOrientation()}.
     38  * You can also specify gravity, which specifies the alignment of all the child elements by
     39  * calling {@link #setGravity(int) setGravity()} or specify that specific children
     40  * grow to fill up any remaining space in the layout by setting the <em>weight</em> member of
     41  * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}.
     42  * The default orientation is horizontal.
     43  *
     44  * <p>See the <a href="{@docRoot}guide/topics/ui/layout/linear.html">Linear Layout</a>
     45  * guide.</p>
     46  *
     47  * <p>
     48  * Also see {@link LinearLayout.LayoutParams android.widget.LinearLayout.LayoutParams}
     49  * for layout attributes </p>
     50  *
     51  * @attr ref android.R.styleable#LinearLayout_baselineAligned
     52  * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
     53  * @attr ref android.R.styleable#LinearLayout_gravity
     54  * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
     55  * @attr ref android.R.styleable#LinearLayout_orientation
     56  * @attr ref android.R.styleable#LinearLayout_weightSum
     57  */
     58 @RemoteView
     59 public class LinearLayout extends ViewGroup {
     60     public static final int HORIZONTAL = 0;
     61     public static final int VERTICAL = 1;
     62 
     63     /**
     64      * Don't show any dividers.
     65      */
     66     public static final int SHOW_DIVIDER_NONE = 0;
     67     /**
     68      * Show a divider at the beginning of the group.
     69      */
     70     public static final int SHOW_DIVIDER_BEGINNING = 1;
     71     /**
     72      * Show dividers between each item in the group.
     73      */
     74     public static final int SHOW_DIVIDER_MIDDLE = 2;
     75     /**
     76      * Show a divider at the end of the group.
     77      */
     78     public static final int SHOW_DIVIDER_END = 4;
     79 
     80     /**
     81      * Whether the children of this layout are baseline aligned.  Only applicable
     82      * if {@link #mOrientation} is horizontal.
     83      */
     84     @ViewDebug.ExportedProperty(category = "layout")
     85     private boolean mBaselineAligned = true;
     86 
     87     /**
     88      * If this layout is part of another layout that is baseline aligned,
     89      * use the child at this index as the baseline.
     90      *
     91      * Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
     92      * with whether the children of this layout are baseline aligned.
     93      */
     94     @ViewDebug.ExportedProperty(category = "layout")
     95     private int mBaselineAlignedChildIndex = -1;
     96 
     97     /**
     98      * The additional offset to the child's baseline.
     99      * We'll calculate the baseline of this layout as we measure vertically; for
    100      * horizontal linear layouts, the offset of 0 is appropriate.
    101      */
    102     @ViewDebug.ExportedProperty(category = "measurement")
    103     private int mBaselineChildTop = 0;
    104 
    105     @ViewDebug.ExportedProperty(category = "measurement")
    106     private int mOrientation;
    107 
    108     @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
    109             @ViewDebug.FlagToString(mask = -1,
    110                 equals = -1, name = "NONE"),
    111             @ViewDebug.FlagToString(mask = Gravity.NO_GRAVITY,
    112                 equals = Gravity.NO_GRAVITY,name = "NONE"),
    113             @ViewDebug.FlagToString(mask = Gravity.TOP,
    114                 equals = Gravity.TOP, name = "TOP"),
    115             @ViewDebug.FlagToString(mask = Gravity.BOTTOM,
    116                 equals = Gravity.BOTTOM, name = "BOTTOM"),
    117             @ViewDebug.FlagToString(mask = Gravity.LEFT,
    118                 equals = Gravity.LEFT, name = "LEFT"),
    119             @ViewDebug.FlagToString(mask = Gravity.RIGHT,
    120                 equals = Gravity.RIGHT, name = "RIGHT"),
    121             @ViewDebug.FlagToString(mask = Gravity.START,
    122                 equals = Gravity.START, name = "START"),
    123             @ViewDebug.FlagToString(mask = Gravity.END,
    124                 equals = Gravity.END, name = "END"),
    125             @ViewDebug.FlagToString(mask = Gravity.CENTER_VERTICAL,
    126                 equals = Gravity.CENTER_VERTICAL, name = "CENTER_VERTICAL"),
    127             @ViewDebug.FlagToString(mask = Gravity.FILL_VERTICAL,
    128                 equals = Gravity.FILL_VERTICAL, name = "FILL_VERTICAL"),
    129             @ViewDebug.FlagToString(mask = Gravity.CENTER_HORIZONTAL,
    130                 equals = Gravity.CENTER_HORIZONTAL, name = "CENTER_HORIZONTAL"),
    131             @ViewDebug.FlagToString(mask = Gravity.FILL_HORIZONTAL,
    132                 equals = Gravity.FILL_HORIZONTAL, name = "FILL_HORIZONTAL"),
    133             @ViewDebug.FlagToString(mask = Gravity.CENTER,
    134                 equals = Gravity.CENTER, name = "CENTER"),
    135             @ViewDebug.FlagToString(mask = Gravity.FILL,
    136                 equals = Gravity.FILL, name = "FILL"),
    137             @ViewDebug.FlagToString(mask = Gravity.RELATIVE_LAYOUT_DIRECTION,
    138                 equals = Gravity.RELATIVE_LAYOUT_DIRECTION, name = "RELATIVE")
    139         })
    140     private int mGravity = Gravity.START | Gravity.TOP;
    141 
    142     @ViewDebug.ExportedProperty(category = "measurement")
    143     private int mTotalLength;
    144 
    145     @ViewDebug.ExportedProperty(category = "layout")
    146     private float mWeightSum;
    147 
    148     @ViewDebug.ExportedProperty(category = "layout")
    149     private boolean mUseLargestChild;
    150 
    151     private int[] mMaxAscent;
    152     private int[] mMaxDescent;
    153 
    154     private static final int VERTICAL_GRAVITY_COUNT = 4;
    155 
    156     private static final int INDEX_CENTER_VERTICAL = 0;
    157     private static final int INDEX_TOP = 1;
    158     private static final int INDEX_BOTTOM = 2;
    159     private static final int INDEX_FILL = 3;
    160 
    161     private Drawable mDivider;
    162     private int mDividerWidth;
    163     private int mDividerHeight;
    164     private int mShowDividers;
    165     private int mDividerPadding;
    166 
    167     public LinearLayout(Context context) {
    168         super(context);
    169     }
    170 
    171     public LinearLayout(Context context, AttributeSet attrs) {
    172         this(context, attrs, 0);
    173     }
    174 
    175     public LinearLayout(Context context, AttributeSet attrs, int defStyle) {
    176         super(context, attrs, defStyle);
    177 
    178         TypedArray a = context.obtainStyledAttributes(attrs,
    179                 com.android.internal.R.styleable.LinearLayout, defStyle, 0);
    180 
    181         int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
    182         if (index >= 0) {
    183             setOrientation(index);
    184         }
    185 
    186         index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1);
    187         if (index >= 0) {
    188             setGravity(index);
    189         }
    190 
    191         boolean baselineAligned = a.getBoolean(R.styleable.LinearLayout_baselineAligned, true);
    192         if (!baselineAligned) {
    193             setBaselineAligned(baselineAligned);
    194         }
    195 
    196         mWeightSum = a.getFloat(R.styleable.LinearLayout_weightSum, -1.0f);
    197 
    198         mBaselineAlignedChildIndex =
    199                 a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1);
    200 
    201         mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_measureWithLargestChild, false);
    202 
    203         setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider));
    204         mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE);
    205         mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);
    206 
    207         a.recycle();
    208     }
    209 
    210     /**
    211      * Set how dividers should be shown between items in this layout
    212      *
    213      * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
    214      *                     {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
    215      *                     or {@link #SHOW_DIVIDER_NONE} to show no dividers.
    216      */
    217     public void setShowDividers(int showDividers) {
    218         if (showDividers != mShowDividers) {
    219             requestLayout();
    220         }
    221         mShowDividers = showDividers;
    222     }
    223 
    224     @Override
    225     public boolean shouldDelayChildPressedState() {
    226         return false;
    227     }
    228 
    229     /**
    230      * @return A flag set indicating how dividers should be shown around items.
    231      * @see #setShowDividers(int)
    232      */
    233     public int getShowDividers() {
    234         return mShowDividers;
    235     }
    236 
    237     /**
    238      * @return the divider Drawable that will divide each item.
    239      *
    240      * @see #setDividerDrawable(Drawable)
    241      *
    242      * @attr ref android.R.styleable#LinearLayout_divider
    243      */
    244     public Drawable getDividerDrawable() {
    245         return mDivider;
    246     }
    247 
    248     /**
    249      * Set a drawable to be used as a divider between items.
    250      *
    251      * @param divider Drawable that will divide each item.
    252      *
    253      * @see #setShowDividers(int)
    254      *
    255      * @attr ref android.R.styleable#LinearLayout_divider
    256      */
    257     public void setDividerDrawable(Drawable divider) {
    258         if (divider == mDivider) {
    259             return;
    260         }
    261         mDivider = divider;
    262         if (divider != null) {
    263             mDividerWidth = divider.getIntrinsicWidth();
    264             mDividerHeight = divider.getIntrinsicHeight();
    265         } else {
    266             mDividerWidth = 0;
    267             mDividerHeight = 0;
    268         }
    269         setWillNotDraw(divider == null);
    270         requestLayout();
    271     }
    272 
    273     /**
    274      * Set padding displayed on both ends of dividers.
    275      *
    276      * @param padding Padding value in pixels that will be applied to each end
    277      *
    278      * @see #setShowDividers(int)
    279      * @see #setDividerDrawable(Drawable)
    280      * @see #getDividerPadding()
    281      */
    282     public void setDividerPadding(int padding) {
    283         mDividerPadding = padding;
    284     }
    285 
    286     /**
    287      * Get the padding size used to inset dividers in pixels
    288      *
    289      * @see #setShowDividers(int)
    290      * @see #setDividerDrawable(Drawable)
    291      * @see #setDividerPadding(int)
    292      */
    293     public int getDividerPadding() {
    294         return mDividerPadding;
    295     }
    296 
    297     /**
    298      * Get the width of the current divider drawable.
    299      *
    300      * @hide Used internally by framework.
    301      */
    302     public int getDividerWidth() {
    303         return mDividerWidth;
    304     }
    305 
    306     @Override
    307     protected void onDraw(Canvas canvas) {
    308         if (mDivider == null) {
    309             return;
    310         }
    311 
    312         if (mOrientation == VERTICAL) {
    313             drawDividersVertical(canvas);
    314         } else {
    315             drawDividersHorizontal(canvas);
    316         }
    317     }
    318 
    319     void drawDividersVertical(Canvas canvas) {
    320         final int count = getVirtualChildCount();
    321         for (int i = 0; i < count; i++) {
    322             final View child = getVirtualChildAt(i);
    323 
    324             if (child != null && child.getVisibility() != GONE) {
    325                 if (hasDividerBeforeChildAt(i)) {
    326                     final LayoutParams lp = (LayoutParams) child.getLayoutParams();
    327                     final int top = child.getTop() - lp.topMargin - mDividerHeight;
    328                     drawHorizontalDivider(canvas, top);
    329                 }
    330             }
    331         }
    332 
    333         if (hasDividerBeforeChildAt(count)) {
    334             final View child = getVirtualChildAt(count - 1);
    335             int bottom = 0;
    336             if (child == null) {
    337                 bottom = getHeight() - getPaddingBottom() - mDividerHeight;
    338             } else {
    339                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
    340                 bottom = child.getBottom() + lp.bottomMargin;
    341             }
    342             drawHorizontalDivider(canvas, bottom);
    343         }
    344     }
    345 
    346     void drawDividersHorizontal(Canvas canvas) {
    347         final int count = getVirtualChildCount();
    348         for (int i = 0; i < count; i++) {
    349             final View child = getVirtualChildAt(i);
    350 
    351             if (child != null && child.getVisibility() != GONE) {
    352                 if (hasDividerBeforeChildAt(i)) {
    353                     final LayoutParams lp = (LayoutParams) child.getLayoutParams();
    354                     final int left = child.getLeft() - lp.leftMargin - mDividerWidth;
    355                     drawVerticalDivider(canvas, left);
    356                 }
    357             }
    358         }
    359 
    360         if (hasDividerBeforeChildAt(count)) {
    361             final View child = getVirtualChildAt(count - 1);
    362             int right = 0;
    363             if (child == null) {
    364                 right = getWidth() - getPaddingRight() - mDividerWidth;
    365             } else {
    366                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
    367                 right = child.getRight() + lp.rightMargin;
    368             }
    369             drawVerticalDivider(canvas, right);
    370         }
    371     }
    372 
    373     void drawHorizontalDivider(Canvas canvas, int top) {
    374         mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
    375                 getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
    376         mDivider.draw(canvas);
    377     }
    378 
    379     void drawVerticalDivider(Canvas canvas, int left) {
    380         mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
    381                 left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
    382         mDivider.draw(canvas);
    383     }
    384 
    385     /**
    386      * <p>Indicates whether widgets contained within this layout are aligned
    387      * on their baseline or not.</p>
    388      *
    389      * @return true when widgets are baseline-aligned, false otherwise
    390      */
    391     public boolean isBaselineAligned() {
    392         return mBaselineAligned;
    393     }
    394 
    395     /**
    396      * <p>Defines whether widgets contained in this layout are
    397      * baseline-aligned or not.</p>
    398      *
    399      * @param baselineAligned true to align widgets on their baseline,
    400      *         false otherwise
    401      *
    402      * @attr ref android.R.styleable#LinearLayout_baselineAligned
    403      */
    404     @android.view.RemotableViewMethod
    405     public void setBaselineAligned(boolean baselineAligned) {
    406         mBaselineAligned = baselineAligned;
    407     }
    408 
    409     /**
    410      * When true, all children with a weight will be considered having
    411      * the minimum size of the largest child. If false, all children are
    412      * measured normally.
    413      *
    414      * @return True to measure children with a weight using the minimum
    415      *         size of the largest child, false otherwise.
    416      *
    417      * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
    418      */
    419     public boolean isMeasureWithLargestChildEnabled() {
    420         return mUseLargestChild;
    421     }
    422 
    423     /**
    424      * When set to true, all children with a weight will be considered having
    425      * the minimum size of the largest child. If false, all children are
    426      * measured normally.
    427      *
    428      * Disabled by default.
    429      *
    430      * @param enabled True to measure children with a weight using the
    431      *        minimum size of the largest child, false otherwise.
    432      *
    433      * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
    434      */
    435     @android.view.RemotableViewMethod
    436     public void setMeasureWithLargestChildEnabled(boolean enabled) {
    437         mUseLargestChild = enabled;
    438     }
    439 
    440     @Override
    441     public int getBaseline() {
    442         if (mBaselineAlignedChildIndex < 0) {
    443             return super.getBaseline();
    444         }
    445 
    446         if (getChildCount() <= mBaselineAlignedChildIndex) {
    447             throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
    448                     + "set to an index that is out of bounds.");
    449         }
    450 
    451         final View child = getChildAt(mBaselineAlignedChildIndex);
    452         final int childBaseline = child.getBaseline();
    453 
    454         if (childBaseline == -1) {
    455             if (mBaselineAlignedChildIndex == 0) {
    456                 // this is just the default case, safe to return -1
    457                 return -1;
    458             }
    459             // the user picked an index that points to something that doesn't
    460             // know how to calculate its baseline.
    461             throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
    462                     + "points to a View that doesn't know how to get its baseline.");
    463         }
    464 
    465         // TODO: This should try to take into account the virtual offsets
    466         // (See getNextLocationOffset and getLocationOffset)
    467         // We should add to childTop:
    468         // sum([getNextLocationOffset(getChildAt(i)) / i < mBaselineAlignedChildIndex])
    469         // and also add:
    470         // getLocationOffset(child)
    471         int childTop = mBaselineChildTop;
    472 
    473         if (mOrientation == VERTICAL) {
    474             final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
    475             if (majorGravity != Gravity.TOP) {
    476                switch (majorGravity) {
    477                    case Gravity.BOTTOM:
    478                        childTop = mBottom - mTop - mPaddingBottom - mTotalLength;
    479                        break;
    480 
    481                    case Gravity.CENTER_VERTICAL:
    482                        childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) -
    483                                mTotalLength) / 2;
    484                        break;
    485                }
    486             }
    487         }
    488 
    489         LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
    490         return childTop + lp.topMargin + childBaseline;
    491     }
    492 
    493     /**
    494      * @return The index of the child that will be used if this layout is
    495      *   part of a larger layout that is baseline aligned, or -1 if none has
    496      *   been set.
    497      */
    498     public int getBaselineAlignedChildIndex() {
    499         return mBaselineAlignedChildIndex;
    500     }
    501 
    502     /**
    503      * @param i The index of the child that will be used if this layout is
    504      *          part of a larger layout that is baseline aligned.
    505      *
    506      * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
    507      */
    508     @android.view.RemotableViewMethod
    509     public void setBaselineAlignedChildIndex(int i) {
    510         if ((i < 0) || (i >= getChildCount())) {
    511             throw new IllegalArgumentException("base aligned child index out "
    512                     + "of range (0, " + getChildCount() + ")");
    513         }
    514         mBaselineAlignedChildIndex = i;
    515     }
    516 
    517     /**
    518      * <p>Returns the view at the specified index. This method can be overriden
    519      * to take into account virtual children. Refer to
    520      * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
    521      * for an example.</p>
    522      *
    523      * @param index the child's index
    524      * @return the child at the specified index
    525      */
    526     View getVirtualChildAt(int index) {
    527         return getChildAt(index);
    528     }
    529 
    530     /**
    531      * <p>Returns the virtual number of children. This number might be different
    532      * than the actual number of children if the layout can hold virtual
    533      * children. Refer to
    534      * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
    535      * for an example.</p>
    536      *
    537      * @return the virtual number of children
    538      */
    539     int getVirtualChildCount() {
    540         return getChildCount();
    541     }
    542 
    543     /**
    544      * Returns the desired weights sum.
    545      *
    546      * @return A number greater than 0.0f if the weight sum is defined, or
    547      *         a number lower than or equals to 0.0f if not weight sum is
    548      *         to be used.
    549      */
    550     public float getWeightSum() {
    551         return mWeightSum;
    552     }
    553 
    554     /**
    555      * Defines the desired weights sum. If unspecified the weights sum is computed
    556      * at layout time by adding the layout_weight of each child.
    557      *
    558      * This can be used for instance to give a single child 50% of the total
    559      * available space by giving it a layout_weight of 0.5 and setting the
    560      * weightSum to 1.0.
    561      *
    562      * @param weightSum a number greater than 0.0f, or a number lower than or equals
    563      *        to 0.0f if the weight sum should be computed from the children's
    564      *        layout_weight
    565      */
    566     @android.view.RemotableViewMethod
    567     public void setWeightSum(float weightSum) {
    568         mWeightSum = Math.max(0.0f, weightSum);
    569     }
    570 
    571     @Override
    572     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    573         if (mOrientation == VERTICAL) {
    574             measureVertical(widthMeasureSpec, heightMeasureSpec);
    575         } else {
    576             measureHorizontal(widthMeasureSpec, heightMeasureSpec);
    577         }
    578     }
    579 
    580     /**
    581      * Determines where to position dividers between children.
    582      *
    583      * @param childIndex Index of child to check for preceding divider
    584      * @return true if there should be a divider before the child at childIndex
    585      * @hide Pending API consideration. Currently only used internally by the system.
    586      */
    587     protected boolean hasDividerBeforeChildAt(int childIndex) {
    588         if (childIndex == 0) {
    589             return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
    590         } else if (childIndex == getChildCount()) {
    591             return (mShowDividers & SHOW_DIVIDER_END) != 0;
    592         } else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
    593             boolean hasVisibleViewBefore = false;
    594             for (int i = childIndex - 1; i >= 0; i--) {
    595                 if (getChildAt(i).getVisibility() != GONE) {
    596                     hasVisibleViewBefore = true;
    597                     break;
    598                 }
    599             }
    600             return hasVisibleViewBefore;
    601         }
    602         return false;
    603     }
    604 
    605     /**
    606      * Measures the children when the orientation of this LinearLayout is set
    607      * to {@link #VERTICAL}.
    608      *
    609      * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
    610      * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
    611      *
    612      * @see #getOrientation()
    613      * @see #setOrientation(int)
    614      * @see #onMeasure(int, int)
    615      */
    616     void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
    617         mTotalLength = 0;
    618         int maxWidth = 0;
    619         int childState = 0;
    620         int alternativeMaxWidth = 0;
    621         int weightedMaxWidth = 0;
    622         boolean allFillParent = true;
    623         float totalWeight = 0;
    624 
    625         final int count = getVirtualChildCount();
    626 
    627         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    628         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    629 
    630         boolean matchWidth = false;
    631 
    632         final int baselineChildIndex = mBaselineAlignedChildIndex;
    633         final boolean useLargestChild = mUseLargestChild;
    634 
    635         int largestChildHeight = Integer.MIN_VALUE;
    636 
    637         // See how tall everyone is. Also remember max width.
    638         for (int i = 0; i < count; ++i) {
    639             final View child = getVirtualChildAt(i);
    640 
    641             if (child == null) {
    642                 mTotalLength += measureNullChild(i);
    643                 continue;
    644             }
    645 
    646             if (child.getVisibility() == View.GONE) {
    647                i += getChildrenSkipCount(child, i);
    648                continue;
    649             }
    650 
    651             if (hasDividerBeforeChildAt(i)) {
    652                 mTotalLength += mDividerHeight;
    653             }
    654 
    655             LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
    656 
    657             totalWeight += lp.weight;
    658 
    659             if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {
    660                 // Optimization: don't bother measuring children who are going to use
    661                 // leftover space. These views will get measured again down below if
    662                 // there is any leftover space.
    663                 final int totalLength = mTotalLength;
    664                 mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
    665             } else {
    666                 int oldHeight = Integer.MIN_VALUE;
    667 
    668                 if (lp.height == 0 && lp.weight > 0) {
    669                     // heightMode is either UNSPECIFIED or AT_MOST, and this
    670                     // child wanted to stretch to fill available space.
    671                     // Translate that to WRAP_CONTENT so that it does not end up
    672                     // with a height of 0
    673                     oldHeight = 0;
    674                     lp.height = LayoutParams.WRAP_CONTENT;
    675                 }
    676 
    677                 // Determine how big this child would like to be. If this or
    678                 // previous children have given a weight, then we allow it to
    679                 // use all available space (and we will shrink things later
    680                 // if needed).
    681                 measureChildBeforeLayout(
    682                        child, i, widthMeasureSpec, 0, heightMeasureSpec,
    683                        totalWeight == 0 ? mTotalLength : 0);
    684 
    685                 if (oldHeight != Integer.MIN_VALUE) {
    686                    lp.height = oldHeight;
    687                 }
    688 
    689                 final int childHeight = child.getMeasuredHeight();
    690                 final int totalLength = mTotalLength;
    691                 mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
    692                        lp.bottomMargin + getNextLocationOffset(child));
    693 
    694                 if (useLargestChild) {
    695                     largestChildHeight = Math.max(childHeight, largestChildHeight);
    696                 }
    697             }
    698 
    699             /**
    700              * If applicable, compute the additional offset to the child's baseline
    701              * we'll need later when asked {@link #getBaseline}.
    702              */
    703             if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {
    704                mBaselineChildTop = mTotalLength;
    705             }
    706 
    707             // if we are trying to use a child index for our baseline, the above
    708             // book keeping only works if there are no children above it with
    709             // weight.  fail fast to aid the developer.
    710             if (i < baselineChildIndex && lp.weight > 0) {
    711                 throw new RuntimeException("A child of LinearLayout with index "
    712                         + "less than mBaselineAlignedChildIndex has weight > 0, which "
    713                         + "won't work.  Either remove the weight, or don't set "
    714                         + "mBaselineAlignedChildIndex.");
    715             }
    716 
    717             boolean matchWidthLocally = false;
    718             if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {
    719                 // The width of the linear layout will scale, and at least one
    720                 // child said it wanted to match our width. Set a flag
    721                 // indicating that we need to remeasure at least that view when
    722                 // we know our width.
    723                 matchWidth = true;
    724                 matchWidthLocally = true;
    725             }
    726 
    727             final int margin = lp.leftMargin + lp.rightMargin;
    728             final int measuredWidth = child.getMeasuredWidth() + margin;
    729             maxWidth = Math.max(maxWidth, measuredWidth);
    730             childState = combineMeasuredStates(childState, child.getMeasuredState());
    731 
    732             allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
    733             if (lp.weight > 0) {
    734                 /*
    735                  * Widths of weighted Views are bogus if we end up
    736                  * remeasuring, so keep them separate.
    737                  */
    738                 weightedMaxWidth = Math.max(weightedMaxWidth,
    739                         matchWidthLocally ? margin : measuredWidth);
    740             } else {
    741                 alternativeMaxWidth = Math.max(alternativeMaxWidth,
    742                         matchWidthLocally ? margin : measuredWidth);
    743             }
    744 
    745             i += getChildrenSkipCount(child, i);
    746         }
    747 
    748         if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {
    749             mTotalLength += mDividerHeight;
    750         }
    751 
    752         if (useLargestChild &&
    753                 (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
    754             mTotalLength = 0;
    755 
    756             for (int i = 0; i < count; ++i) {
    757                 final View child = getVirtualChildAt(i);
    758 
    759                 if (child == null) {
    760                     mTotalLength += measureNullChild(i);
    761                     continue;
    762                 }
    763 
    764                 if (child.getVisibility() == GONE) {
    765                     i += getChildrenSkipCount(child, i);
    766                     continue;
    767                 }
    768 
    769                 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
    770                         child.getLayoutParams();
    771                 // Account for negative margins
    772                 final int totalLength = mTotalLength;
    773                 mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +
    774                         lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
    775             }
    776         }
    777 
    778         // Add in our padding
    779         mTotalLength += mPaddingTop + mPaddingBottom;
    780 
    781         int heightSize = mTotalLength;
    782 
    783         // Check against our minimum height
    784         heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
    785 
    786         // Reconcile our calculated size with the heightMeasureSpec
    787         int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
    788         heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
    789 
    790         // Either expand children with weight to take up available space or
    791         // shrink them if they extend beyond our current bounds
    792         int delta = heightSize - mTotalLength;
    793         if (delta != 0 && totalWeight > 0.0f) {
    794             float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
    795 
    796             mTotalLength = 0;
    797 
    798             for (int i = 0; i < count; ++i) {
    799                 final View child = getVirtualChildAt(i);
    800 
    801                 if (child.getVisibility() == View.GONE) {
    802                     continue;
    803                 }
    804 
    805                 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
    806 
    807                 float childExtra = lp.weight;
    808                 if (childExtra > 0) {
    809                     // Child said it could absorb extra space -- give him his share
    810                     int share = (int) (childExtra * delta / weightSum);
    811                     weightSum -= childExtra;
    812                     delta -= share;
    813 
    814                     final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
    815                             mPaddingLeft + mPaddingRight +
    816                                     lp.leftMargin + lp.rightMargin, lp.width);
    817 
    818                     // TODO: Use a field like lp.isMeasured to figure out if this
    819                     // child has been previously measured
    820                     if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) {
    821                         // child was measured once already above...
    822                         // base new measurement on stored values
    823                         int childHeight = child.getMeasuredHeight() + share;
    824                         if (childHeight < 0) {
    825                             childHeight = 0;
    826                         }
    827 
    828                         child.measure(childWidthMeasureSpec,
    829                                 MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
    830                     } else {
    831                         // child was skipped in the loop above.
    832                         // Measure for this first time here
    833                         child.measure(childWidthMeasureSpec,
    834                                 MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,
    835                                         MeasureSpec.EXACTLY));
    836                     }
    837 
    838                     // Child may now not fit in vertical dimension.
    839                     childState = combineMeasuredStates(childState, child.getMeasuredState()
    840                             & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
    841                 }
    842 
    843                 final int margin =  lp.leftMargin + lp.rightMargin;
    844                 final int measuredWidth = child.getMeasuredWidth() + margin;
    845                 maxWidth = Math.max(maxWidth, measuredWidth);
    846 
    847                 boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&
    848                         lp.width == LayoutParams.MATCH_PARENT;
    849 
    850                 alternativeMaxWidth = Math.max(alternativeMaxWidth,
    851                         matchWidthLocally ? margin : measuredWidth);
    852 
    853                 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
    854 
    855                 final int totalLength = mTotalLength;
    856                 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +
    857                         lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
    858             }
    859 
    860             // Add in our padding
    861             mTotalLength += mPaddingTop + mPaddingBottom;
    862             // TODO: Should we recompute the heightSpec based on the new total length?
    863         } else {
    864             alternativeMaxWidth = Math.max(alternativeMaxWidth,
    865                                            weightedMaxWidth);
    866 
    867 
    868             // We have no limit, so make all weighted views as tall as the largest child.
    869             // Children will have already been measured once.
    870             if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
    871                 for (int i = 0; i < count; i++) {
    872                     final View child = getVirtualChildAt(i);
    873 
    874                     if (child == null || child.getVisibility() == View.GONE) {
    875                         continue;
    876                     }
    877 
    878                     final LinearLayout.LayoutParams lp =
    879                             (LinearLayout.LayoutParams) child.getLayoutParams();
    880 
    881                     float childExtra = lp.weight;
    882                     if (childExtra > 0) {
    883                         child.measure(
    884                                 MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
    885                                         MeasureSpec.EXACTLY),
    886                                 MeasureSpec.makeMeasureSpec(largestChildHeight,
    887                                         MeasureSpec.EXACTLY));
    888                     }
    889                 }
    890             }
    891         }
    892 
    893         if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
    894             maxWidth = alternativeMaxWidth;
    895         }
    896 
    897         maxWidth += mPaddingLeft + mPaddingRight;
    898 
    899         // Check against our minimum width
    900         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
    901 
    902         setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
    903                 heightSizeAndState);
    904 
    905         if (matchWidth) {
    906             forceUniformWidth(count, heightMeasureSpec);
    907         }
    908     }
    909 
    910     private void forceUniformWidth(int count, int heightMeasureSpec) {
    911         // Pretend that the linear layout has an exact size.
    912         int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
    913                 MeasureSpec.EXACTLY);
    914         for (int i = 0; i< count; ++i) {
    915            final View child = getVirtualChildAt(i);
    916            if (child.getVisibility() != GONE) {
    917                LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
    918 
    919                if (lp.width == LayoutParams.MATCH_PARENT) {
    920                    // Temporarily force children to reuse their old measured height
    921                    // FIXME: this may not be right for something like wrapping text?
    922                    int oldHeight = lp.height;
    923                    lp.height = child.getMeasuredHeight();
    924 
    925                    // Remeasue with new dimensions
    926                    measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);
    927                    lp.height = oldHeight;
    928                }
    929            }
    930         }
    931     }
    932 
    933     /**
    934      * Measures the children when the orientation of this LinearLayout is set
    935      * to {@link #HORIZONTAL}.
    936      *
    937      * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
    938      * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
    939      *
    940      * @see #getOrientation()
    941      * @see #setOrientation(int)
    942      * @see #onMeasure(int, int)
    943      */
    944     void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
    945         mTotalLength = 0;
    946         int maxHeight = 0;
    947         int childState = 0;
    948         int alternativeMaxHeight = 0;
    949         int weightedMaxHeight = 0;
    950         boolean allFillParent = true;
    951         float totalWeight = 0;
    952 
    953         final int count = getVirtualChildCount();
    954 
    955         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    956         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    957 
    958         boolean matchHeight = false;
    959 
    960         if (mMaxAscent == null || mMaxDescent == null) {
    961             mMaxAscent = new int[VERTICAL_GRAVITY_COUNT];
    962             mMaxDescent = new int[VERTICAL_GRAVITY_COUNT];
    963         }
    964 
    965         final int[] maxAscent = mMaxAscent;
    966         final int[] maxDescent = mMaxDescent;
    967 
    968         maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
    969         maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
    970 
    971         final boolean baselineAligned = mBaselineAligned;
    972         final boolean useLargestChild = mUseLargestChild;
    973 
    974         final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
    975 
    976         int largestChildWidth = Integer.MIN_VALUE;
    977 
    978         // See how wide everyone is. Also remember max height.
    979         for (int i = 0; i < count; ++i) {
    980             final View child = getVirtualChildAt(i);
    981 
    982             if (child == null) {
    983                 mTotalLength += measureNullChild(i);
    984                 continue;
    985             }
    986 
    987             if (child.getVisibility() == GONE) {
    988                 i += getChildrenSkipCount(child, i);
    989                 continue;
    990             }
    991 
    992             if (hasDividerBeforeChildAt(i)) {
    993                 mTotalLength += mDividerWidth;
    994             }
    995 
    996             final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
    997                     child.getLayoutParams();
    998 
    999             totalWeight += lp.weight;
   1000 
   1001             if (widthMode == MeasureSpec.EXACTLY && lp.width == 0 && lp.weight > 0) {
   1002                 // Optimization: don't bother measuring children who are going to use
   1003                 // leftover space. These views will get measured again down below if
   1004                 // there is any leftover space.
   1005                 if (isExactly) {
   1006                     mTotalLength += lp.leftMargin + lp.rightMargin;
   1007                 } else {
   1008                     final int totalLength = mTotalLength;
   1009                     mTotalLength = Math.max(totalLength, totalLength +
   1010                             lp.leftMargin + lp.rightMargin);
   1011                 }
   1012 
   1013                 // Baseline alignment requires to measure widgets to obtain the
   1014                 // baseline offset (in particular for TextViews). The following
   1015                 // defeats the optimization mentioned above. Allow the child to
   1016                 // use as much space as it wants because we can shrink things
   1017                 // later (and re-measure).
   1018                 if (baselineAligned) {
   1019                     final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
   1020                     child.measure(freeSpec, freeSpec);
   1021                 }
   1022             } else {
   1023                 int oldWidth = Integer.MIN_VALUE;
   1024 
   1025                 if (lp.width == 0 && lp.weight > 0) {
   1026                     // widthMode is either UNSPECIFIED or AT_MOST, and this
   1027                     // child
   1028                     // wanted to stretch to fill available space. Translate that to
   1029                     // WRAP_CONTENT so that it does not end up with a width of 0
   1030                     oldWidth = 0;
   1031                     lp.width = LayoutParams.WRAP_CONTENT;
   1032                 }
   1033 
   1034                 // Determine how big this child would like to be. If this or
   1035                 // previous children have given a weight, then we allow it to
   1036                 // use all available space (and we will shrink things later
   1037                 // if needed).
   1038                 measureChildBeforeLayout(child, i, widthMeasureSpec,
   1039                         totalWeight == 0 ? mTotalLength : 0,
   1040                         heightMeasureSpec, 0);
   1041 
   1042                 if (oldWidth != Integer.MIN_VALUE) {
   1043                     lp.width = oldWidth;
   1044                 }
   1045 
   1046                 final int childWidth = child.getMeasuredWidth();
   1047                 if (isExactly) {
   1048                     mTotalLength += childWidth + lp.leftMargin + lp.rightMargin +
   1049                             getNextLocationOffset(child);
   1050                 } else {
   1051                     final int totalLength = mTotalLength;
   1052                     mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin +
   1053                            lp.rightMargin + getNextLocationOffset(child));
   1054                 }
   1055 
   1056                 if (useLargestChild) {
   1057                     largestChildWidth = Math.max(childWidth, largestChildWidth);
   1058                 }
   1059             }
   1060 
   1061             boolean matchHeightLocally = false;
   1062             if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.MATCH_PARENT) {
   1063                 // The height of the linear layout will scale, and at least one
   1064                 // child said it wanted to match our height. Set a flag indicating that
   1065                 // we need to remeasure at least that view when we know our height.
   1066                 matchHeight = true;
   1067                 matchHeightLocally = true;
   1068             }
   1069 
   1070             final int margin = lp.topMargin + lp.bottomMargin;
   1071             final int childHeight = child.getMeasuredHeight() + margin;
   1072             childState = combineMeasuredStates(childState, child.getMeasuredState());
   1073 
   1074             if (baselineAligned) {
   1075                 final int childBaseline = child.getBaseline();
   1076                 if (childBaseline != -1) {
   1077                     // Translates the child's vertical gravity into an index
   1078                     // in the range 0..VERTICAL_GRAVITY_COUNT
   1079                     final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
   1080                             & Gravity.VERTICAL_GRAVITY_MASK;
   1081                     final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
   1082                             & ~Gravity.AXIS_SPECIFIED) >> 1;
   1083 
   1084                     maxAscent[index] = Math.max(maxAscent[index], childBaseline);
   1085                     maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline);
   1086                 }
   1087             }
   1088 
   1089             maxHeight = Math.max(maxHeight, childHeight);
   1090 
   1091             allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
   1092             if (lp.weight > 0) {
   1093                 /*
   1094                  * Heights of weighted Views are bogus if we end up
   1095                  * remeasuring, so keep them separate.
   1096                  */
   1097                 weightedMaxHeight = Math.max(weightedMaxHeight,
   1098                         matchHeightLocally ? margin : childHeight);
   1099             } else {
   1100                 alternativeMaxHeight = Math.max(alternativeMaxHeight,
   1101                         matchHeightLocally ? margin : childHeight);
   1102             }
   1103 
   1104             i += getChildrenSkipCount(child, i);
   1105         }
   1106 
   1107         if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {
   1108             mTotalLength += mDividerWidth;
   1109         }
   1110 
   1111         // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
   1112         // the most common case
   1113         if (maxAscent[INDEX_TOP] != -1 ||
   1114                 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
   1115                 maxAscent[INDEX_BOTTOM] != -1 ||
   1116                 maxAscent[INDEX_FILL] != -1) {
   1117             final int ascent = Math.max(maxAscent[INDEX_FILL],
   1118                     Math.max(maxAscent[INDEX_CENTER_VERTICAL],
   1119                     Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
   1120             final int descent = Math.max(maxDescent[INDEX_FILL],
   1121                     Math.max(maxDescent[INDEX_CENTER_VERTICAL],
   1122                     Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
   1123             maxHeight = Math.max(maxHeight, ascent + descent);
   1124         }
   1125 
   1126         if (useLargestChild &&
   1127                 (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED)) {
   1128             mTotalLength = 0;
   1129 
   1130             for (int i = 0; i < count; ++i) {
   1131                 final View child = getVirtualChildAt(i);
   1132 
   1133                 if (child == null) {
   1134                     mTotalLength += measureNullChild(i);
   1135                     continue;
   1136                 }
   1137 
   1138                 if (child.getVisibility() == GONE) {
   1139                     i += getChildrenSkipCount(child, i);
   1140                     continue;
   1141                 }
   1142 
   1143                 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
   1144                         child.getLayoutParams();
   1145                 if (isExactly) {
   1146                     mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
   1147                             getNextLocationOffset(child);
   1148                 } else {
   1149                     final int totalLength = mTotalLength;
   1150                     mTotalLength = Math.max(totalLength, totalLength + largestChildWidth +
   1151                             lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
   1152                 }
   1153             }
   1154         }
   1155 
   1156         // Add in our padding
   1157         mTotalLength += mPaddingLeft + mPaddingRight;
   1158 
   1159         int widthSize = mTotalLength;
   1160 
   1161         // Check against our minimum width
   1162         widthSize = Math.max(widthSize, getSuggestedMinimumWidth());
   1163 
   1164         // Reconcile our calculated size with the widthMeasureSpec
   1165         int widthSizeAndState = resolveSizeAndState(widthSize, widthMeasureSpec, 0);
   1166         widthSize = widthSizeAndState & MEASURED_SIZE_MASK;
   1167 
   1168         // Either expand children with weight to take up available space or
   1169         // shrink them if they extend beyond our current bounds
   1170         int delta = widthSize - mTotalLength;
   1171         if (delta != 0 && totalWeight > 0.0f) {
   1172             float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
   1173 
   1174             maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
   1175             maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
   1176             maxHeight = -1;
   1177 
   1178             mTotalLength = 0;
   1179 
   1180             for (int i = 0; i < count; ++i) {
   1181                 final View child = getVirtualChildAt(i);
   1182 
   1183                 if (child == null || child.getVisibility() == View.GONE) {
   1184                     continue;
   1185                 }
   1186 
   1187                 final LinearLayout.LayoutParams lp =
   1188                         (LinearLayout.LayoutParams) child.getLayoutParams();
   1189 
   1190                 float childExtra = lp.weight;
   1191                 if (childExtra > 0) {
   1192                     // Child said it could absorb extra space -- give him his share
   1193                     int share = (int) (childExtra * delta / weightSum);
   1194                     weightSum -= childExtra;
   1195                     delta -= share;
   1196 
   1197                     final int childHeightMeasureSpec = getChildMeasureSpec(
   1198                             heightMeasureSpec,
   1199                             mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
   1200                             lp.height);
   1201 
   1202                     // TODO: Use a field like lp.isMeasured to figure out if this
   1203                     // child has been previously measured
   1204                     if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) {
   1205                         // child was measured once already above ... base new measurement
   1206                         // on stored values
   1207                         int childWidth = child.getMeasuredWidth() + share;
   1208                         if (childWidth < 0) {
   1209                             childWidth = 0;
   1210                         }
   1211 
   1212                         child.measure(
   1213                             MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
   1214                             childHeightMeasureSpec);
   1215                     } else {
   1216                         // child was skipped in the loop above. Measure for this first time here
   1217                         child.measure(MeasureSpec.makeMeasureSpec(
   1218                                 share > 0 ? share : 0, MeasureSpec.EXACTLY),
   1219                                 childHeightMeasureSpec);
   1220                     }
   1221 
   1222                     // Child may now not fit in horizontal dimension.
   1223                     childState = combineMeasuredStates(childState,
   1224                             child.getMeasuredState() & MEASURED_STATE_MASK);
   1225                 }
   1226 
   1227                 if (isExactly) {
   1228                     mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin +
   1229                             getNextLocationOffset(child);
   1230                 } else {
   1231                     final int totalLength = mTotalLength;
   1232                     mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() +
   1233                             lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
   1234                 }
   1235 
   1236                 boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY &&
   1237                         lp.height == LayoutParams.MATCH_PARENT;
   1238 
   1239                 final int margin = lp.topMargin + lp .bottomMargin;
   1240                 int childHeight = child.getMeasuredHeight() + margin;
   1241                 maxHeight = Math.max(maxHeight, childHeight);
   1242                 alternativeMaxHeight = Math.max(alternativeMaxHeight,
   1243                         matchHeightLocally ? margin : childHeight);
   1244 
   1245                 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
   1246 
   1247                 if (baselineAligned) {
   1248                     final int childBaseline = child.getBaseline();
   1249                     if (childBaseline != -1) {
   1250                         // Translates the child's vertical gravity into an index in the range 0..2
   1251                         final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
   1252                                 & Gravity.VERTICAL_GRAVITY_MASK;
   1253                         final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
   1254                                 & ~Gravity.AXIS_SPECIFIED) >> 1;
   1255 
   1256                         maxAscent[index] = Math.max(maxAscent[index], childBaseline);
   1257                         maxDescent[index] = Math.max(maxDescent[index],
   1258                                 childHeight - childBaseline);
   1259                     }
   1260                 }
   1261             }
   1262 
   1263             // Add in our padding
   1264             mTotalLength += mPaddingLeft + mPaddingRight;
   1265             // TODO: Should we update widthSize with the new total length?
   1266 
   1267             // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
   1268             // the most common case
   1269             if (maxAscent[INDEX_TOP] != -1 ||
   1270                     maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
   1271                     maxAscent[INDEX_BOTTOM] != -1 ||
   1272                     maxAscent[INDEX_FILL] != -1) {
   1273                 final int ascent = Math.max(maxAscent[INDEX_FILL],
   1274                         Math.max(maxAscent[INDEX_CENTER_VERTICAL],
   1275                         Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
   1276                 final int descent = Math.max(maxDescent[INDEX_FILL],
   1277                         Math.max(maxDescent[INDEX_CENTER_VERTICAL],
   1278                         Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
   1279                 maxHeight = Math.max(maxHeight, ascent + descent);
   1280             }
   1281         } else {
   1282             alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight);
   1283 
   1284             // We have no limit, so make all weighted views as wide as the largest child.
   1285             // Children will have already been measured once.
   1286             if (useLargestChild && widthMode != MeasureSpec.EXACTLY) {
   1287                 for (int i = 0; i < count; i++) {
   1288                     final View child = getVirtualChildAt(i);
   1289 
   1290                     if (child == null || child.getVisibility() == View.GONE) {
   1291                         continue;
   1292                     }
   1293 
   1294                     final LinearLayout.LayoutParams lp =
   1295                             (LinearLayout.LayoutParams) child.getLayoutParams();
   1296 
   1297                     float childExtra = lp.weight;
   1298                     if (childExtra > 0) {
   1299                         child.measure(
   1300                                 MeasureSpec.makeMeasureSpec(largestChildWidth, MeasureSpec.EXACTLY),
   1301                                 MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
   1302                                         MeasureSpec.EXACTLY));
   1303                     }
   1304                 }
   1305             }
   1306         }
   1307 
   1308         if (!allFillParent && heightMode != MeasureSpec.EXACTLY) {
   1309             maxHeight = alternativeMaxHeight;
   1310         }
   1311 
   1312         maxHeight += mPaddingTop + mPaddingBottom;
   1313 
   1314         // Check against our minimum height
   1315         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
   1316 
   1317         setMeasuredDimension(widthSizeAndState | (childState&MEASURED_STATE_MASK),
   1318                 resolveSizeAndState(maxHeight, heightMeasureSpec,
   1319                         (childState<<MEASURED_HEIGHT_STATE_SHIFT)));
   1320 
   1321         if (matchHeight) {
   1322             forceUniformHeight(count, widthMeasureSpec);
   1323         }
   1324     }
   1325 
   1326     private void forceUniformHeight(int count, int widthMeasureSpec) {
   1327         // Pretend that the linear layout has an exact size. This is the measured height of
   1328         // ourselves. The measured height should be the max height of the children, changed
   1329         // to accomodate the heightMesureSpec from the parent
   1330         int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
   1331                 MeasureSpec.EXACTLY);
   1332         for (int i = 0; i < count; ++i) {
   1333            final View child = getVirtualChildAt(i);
   1334            if (child.getVisibility() != GONE) {
   1335                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
   1336 
   1337                if (lp.height == LayoutParams.MATCH_PARENT) {
   1338                    // Temporarily force children to reuse their old measured width
   1339                    // FIXME: this may not be right for something like wrapping text?
   1340                    int oldWidth = lp.width;
   1341                    lp.width = child.getMeasuredWidth();
   1342 
   1343                    // Remeasure with new dimensions
   1344                    measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0);
   1345                    lp.width = oldWidth;
   1346                }
   1347            }
   1348         }
   1349     }
   1350 
   1351     /**
   1352      * <p>Returns the number of children to skip after measuring/laying out
   1353      * the specified child.</p>
   1354      *
   1355      * @param child the child after which we want to skip children
   1356      * @param index the index of the child after which we want to skip children
   1357      * @return the number of children to skip, 0 by default
   1358      */
   1359     int getChildrenSkipCount(View child, int index) {
   1360         return 0;
   1361     }
   1362 
   1363     /**
   1364      * <p>Returns the size (width or height) that should be occupied by a null
   1365      * child.</p>
   1366      *
   1367      * @param childIndex the index of the null child
   1368      * @return the width or height of the child depending on the orientation
   1369      */
   1370     int measureNullChild(int childIndex) {
   1371         return 0;
   1372     }
   1373 
   1374     /**
   1375      * <p>Measure the child according to the parent's measure specs. This
   1376      * method should be overriden by subclasses to force the sizing of
   1377      * children. This method is called by {@link #measureVertical(int, int)} and
   1378      * {@link #measureHorizontal(int, int)}.</p>
   1379      *
   1380      * @param child the child to measure
   1381      * @param childIndex the index of the child in this view
   1382      * @param widthMeasureSpec horizontal space requirements as imposed by the parent
   1383      * @param totalWidth extra space that has been used up by the parent horizontally
   1384      * @param heightMeasureSpec vertical space requirements as imposed by the parent
   1385      * @param totalHeight extra space that has been used up by the parent vertically
   1386      */
   1387     void measureChildBeforeLayout(View child, int childIndex,
   1388             int widthMeasureSpec, int totalWidth, int heightMeasureSpec,
   1389             int totalHeight) {
   1390         measureChildWithMargins(child, widthMeasureSpec, totalWidth,
   1391                 heightMeasureSpec, totalHeight);
   1392     }
   1393 
   1394     /**
   1395      * <p>Return the location offset of the specified child. This can be used
   1396      * by subclasses to change the location of a given widget.</p>
   1397      *
   1398      * @param child the child for which to obtain the location offset
   1399      * @return the location offset in pixels
   1400      */
   1401     int getLocationOffset(View child) {
   1402         return 0;
   1403     }
   1404 
   1405     /**
   1406      * <p>Return the size offset of the next sibling of the specified child.
   1407      * This can be used by subclasses to change the location of the widget
   1408      * following <code>child</code>.</p>
   1409      *
   1410      * @param child the child whose next sibling will be moved
   1411      * @return the location offset of the next child in pixels
   1412      */
   1413     int getNextLocationOffset(View child) {
   1414         return 0;
   1415     }
   1416 
   1417     @Override
   1418     protected void onLayout(boolean changed, int l, int t, int r, int b) {
   1419         if (mOrientation == VERTICAL) {
   1420             layoutVertical();
   1421         } else {
   1422             layoutHorizontal();
   1423         }
   1424     }
   1425 
   1426     /**
   1427      * Position the children during a layout pass if the orientation of this
   1428      * LinearLayout is set to {@link #VERTICAL}.
   1429      *
   1430      * @see #getOrientation()
   1431      * @see #setOrientation(int)
   1432      * @see #onLayout(boolean, int, int, int, int)
   1433      */
   1434     void layoutVertical() {
   1435         final int paddingLeft = mPaddingLeft;
   1436 
   1437         int childTop;
   1438         int childLeft;
   1439 
   1440         // Where right end of child should go
   1441         final int width = mRight - mLeft;
   1442         int childRight = width - mPaddingRight;
   1443 
   1444         // Space available for child
   1445         int childSpace = width - paddingLeft - mPaddingRight;
   1446 
   1447         final int count = getVirtualChildCount();
   1448 
   1449         final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
   1450         final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
   1451 
   1452         switch (majorGravity) {
   1453            case Gravity.BOTTOM:
   1454                // mTotalLength contains the padding already
   1455                childTop = mPaddingTop + mBottom - mTop - mTotalLength;
   1456                break;
   1457 
   1458                // mTotalLength contains the padding already
   1459            case Gravity.CENTER_VERTICAL:
   1460                childTop = mPaddingTop + (mBottom - mTop - mTotalLength) / 2;
   1461                break;
   1462 
   1463            case Gravity.TOP:
   1464            default:
   1465                childTop = mPaddingTop;
   1466                break;
   1467         }
   1468 
   1469         for (int i = 0; i < count; i++) {
   1470             final View child = getVirtualChildAt(i);
   1471             if (child == null) {
   1472                 childTop += measureNullChild(i);
   1473             } else if (child.getVisibility() != GONE) {
   1474                 final int childWidth = child.getMeasuredWidth();
   1475                 final int childHeight = child.getMeasuredHeight();
   1476 
   1477                 final LinearLayout.LayoutParams lp =
   1478                         (LinearLayout.LayoutParams) child.getLayoutParams();
   1479 
   1480                 int gravity = lp.gravity;
   1481                 if (gravity < 0) {
   1482                     gravity = minorGravity;
   1483                 }
   1484                 final int layoutDirection = getResolvedLayoutDirection();
   1485                 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
   1486                 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
   1487                     case Gravity.CENTER_HORIZONTAL:
   1488                         childLeft = paddingLeft + ((childSpace - childWidth) / 2)
   1489                                 + lp.leftMargin - lp.rightMargin;
   1490                         break;
   1491 
   1492                     case Gravity.RIGHT:
   1493                         childLeft = childRight - childWidth - lp.rightMargin;
   1494                         break;
   1495 
   1496                     case Gravity.LEFT:
   1497                     default:
   1498                         childLeft = paddingLeft + lp.leftMargin;
   1499                         break;
   1500                 }
   1501 
   1502                 if (hasDividerBeforeChildAt(i)) {
   1503                     childTop += mDividerHeight;
   1504                 }
   1505 
   1506                 childTop += lp.topMargin;
   1507                 setChildFrame(child, childLeft, childTop + getLocationOffset(child),
   1508                         childWidth, childHeight);
   1509                 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
   1510 
   1511                 i += getChildrenSkipCount(child, i);
   1512             }
   1513         }
   1514     }
   1515 
   1516     /**
   1517      * Position the children during a layout pass if the orientation of this
   1518      * LinearLayout is set to {@link #HORIZONTAL}.
   1519      *
   1520      * @see #getOrientation()
   1521      * @see #setOrientation(int)
   1522      * @see #onLayout(boolean, int, int, int, int)
   1523      */
   1524     void layoutHorizontal() {
   1525         final boolean isLayoutRtl = isLayoutRtl();
   1526         final int paddingTop = mPaddingTop;
   1527 
   1528         int childTop;
   1529         int childLeft;
   1530 
   1531         // Where bottom of child should go
   1532         final int height = mBottom - mTop;
   1533         int childBottom = height - mPaddingBottom;
   1534 
   1535         // Space available for child
   1536         int childSpace = height - paddingTop - mPaddingBottom;
   1537 
   1538         final int count = getVirtualChildCount();
   1539 
   1540         final int majorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
   1541         final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
   1542 
   1543         final boolean baselineAligned = mBaselineAligned;
   1544 
   1545         final int[] maxAscent = mMaxAscent;
   1546         final int[] maxDescent = mMaxDescent;
   1547 
   1548         final int layoutDirection = getResolvedLayoutDirection();
   1549         switch (Gravity.getAbsoluteGravity(majorGravity, layoutDirection)) {
   1550             case Gravity.RIGHT:
   1551                 // mTotalLength contains the padding already
   1552                 childLeft = mPaddingLeft + mRight - mLeft - mTotalLength;
   1553                 break;
   1554 
   1555             case Gravity.CENTER_HORIZONTAL:
   1556                 // mTotalLength contains the padding already
   1557                 childLeft = mPaddingLeft + (mRight - mLeft - mTotalLength) / 2;
   1558                 break;
   1559 
   1560             case Gravity.LEFT:
   1561             default:
   1562                 childLeft = mPaddingLeft;
   1563                 break;
   1564         }
   1565 
   1566         int start = 0;
   1567         int dir = 1;
   1568         //In case of RTL, start drawing from the last child.
   1569         if (isLayoutRtl) {
   1570             start = count - 1;
   1571             dir = -1;
   1572         }
   1573 
   1574         for (int i = 0; i < count; i++) {
   1575             int childIndex = start + dir * i;
   1576             final View child = getVirtualChildAt(childIndex);
   1577 
   1578             if (child == null) {
   1579                 childLeft += measureNullChild(childIndex);
   1580             } else if (child.getVisibility() != GONE) {
   1581                 final int childWidth = child.getMeasuredWidth();
   1582                 final int childHeight = child.getMeasuredHeight();
   1583                 int childBaseline = -1;
   1584 
   1585                 final LinearLayout.LayoutParams lp =
   1586                         (LinearLayout.LayoutParams) child.getLayoutParams();
   1587 
   1588                 if (baselineAligned && lp.height != LayoutParams.MATCH_PARENT) {
   1589                     childBaseline = child.getBaseline();
   1590                 }
   1591 
   1592                 int gravity = lp.gravity;
   1593                 if (gravity < 0) {
   1594                     gravity = minorGravity;
   1595                 }
   1596 
   1597                 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
   1598                     case Gravity.TOP:
   1599                         childTop = paddingTop + lp.topMargin;
   1600                         if (childBaseline != -1) {
   1601                             childTop += maxAscent[INDEX_TOP] - childBaseline;
   1602                         }
   1603                         break;
   1604 
   1605                     case Gravity.CENTER_VERTICAL:
   1606                         // Removed support for baseline alignment when layout_gravity or
   1607                         // gravity == center_vertical. See bug #1038483.
   1608                         // Keep the code around if we need to re-enable this feature
   1609                         // if (childBaseline != -1) {
   1610                         //     // Align baselines vertically only if the child is smaller than us
   1611                         //     if (childSpace - childHeight > 0) {
   1612                         //         childTop = paddingTop + (childSpace / 2) - childBaseline;
   1613                         //     } else {
   1614                         //         childTop = paddingTop + (childSpace - childHeight) / 2;
   1615                         //     }
   1616                         // } else {
   1617                         childTop = paddingTop + ((childSpace - childHeight) / 2)
   1618                                 + lp.topMargin - lp.bottomMargin;
   1619                         break;
   1620 
   1621                     case Gravity.BOTTOM:
   1622                         childTop = childBottom - childHeight - lp.bottomMargin;
   1623                         if (childBaseline != -1) {
   1624                             int descent = child.getMeasuredHeight() - childBaseline;
   1625                             childTop -= (maxDescent[INDEX_BOTTOM] - descent);
   1626                         }
   1627                         break;
   1628                     default:
   1629                         childTop = paddingTop;
   1630                         break;
   1631                 }
   1632 
   1633                 if (hasDividerBeforeChildAt(childIndex)) {
   1634                     childLeft += mDividerWidth;
   1635                 }
   1636 
   1637                 childLeft += lp.leftMargin;
   1638                 setChildFrame(child, childLeft + getLocationOffset(child), childTop,
   1639                         childWidth, childHeight);
   1640                 childLeft += childWidth + lp.rightMargin +
   1641                         getNextLocationOffset(child);
   1642 
   1643                 i += getChildrenSkipCount(child, childIndex);
   1644             }
   1645         }
   1646     }
   1647 
   1648     private void setChildFrame(View child, int left, int top, int width, int height) {
   1649         child.layout(left, top, left + width, top + height);
   1650     }
   1651 
   1652     /**
   1653      * Should the layout be a column or a row.
   1654      * @param orientation Pass HORIZONTAL or VERTICAL. Default
   1655      * value is HORIZONTAL.
   1656      *
   1657      * @attr ref android.R.styleable#LinearLayout_orientation
   1658      */
   1659     public void setOrientation(int orientation) {
   1660         if (mOrientation != orientation) {
   1661             mOrientation = orientation;
   1662             requestLayout();
   1663         }
   1664     }
   1665 
   1666     /**
   1667      * Returns the current orientation.
   1668      *
   1669      * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
   1670      */
   1671     public int getOrientation() {
   1672         return mOrientation;
   1673     }
   1674 
   1675     /**
   1676      * Describes how the child views are positioned. Defaults to GRAVITY_TOP. If
   1677      * this layout has a VERTICAL orientation, this controls where all the child
   1678      * views are placed if there is extra vertical space. If this layout has a
   1679      * HORIZONTAL orientation, this controls the alignment of the children.
   1680      *
   1681      * @param gravity See {@link android.view.Gravity}
   1682      *
   1683      * @attr ref android.R.styleable#LinearLayout_gravity
   1684      */
   1685     @android.view.RemotableViewMethod
   1686     public void setGravity(int gravity) {
   1687         if (mGravity != gravity) {
   1688             if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
   1689                 gravity |= Gravity.START;
   1690             }
   1691 
   1692             if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
   1693                 gravity |= Gravity.TOP;
   1694             }
   1695 
   1696             mGravity = gravity;
   1697             requestLayout();
   1698         }
   1699     }
   1700 
   1701     @android.view.RemotableViewMethod
   1702     public void setHorizontalGravity(int horizontalGravity) {
   1703         final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
   1704         if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) {
   1705             mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity;
   1706             requestLayout();
   1707         }
   1708     }
   1709 
   1710     @android.view.RemotableViewMethod
   1711     public void setVerticalGravity(int verticalGravity) {
   1712         final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
   1713         if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
   1714             mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity;
   1715             requestLayout();
   1716         }
   1717     }
   1718 
   1719     @Override
   1720     public LayoutParams generateLayoutParams(AttributeSet attrs) {
   1721         return new LinearLayout.LayoutParams(getContext(), attrs);
   1722     }
   1723 
   1724     /**
   1725      * Returns a set of layout parameters with a width of
   1726      * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}
   1727      * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
   1728      * when the layout's orientation is {@link #VERTICAL}. When the orientation is
   1729      * {@link #HORIZONTAL}, the width is set to {@link LayoutParams#WRAP_CONTENT}
   1730      * and the height to {@link LayoutParams#WRAP_CONTENT}.
   1731      */
   1732     @Override
   1733     protected LayoutParams generateDefaultLayoutParams() {
   1734         if (mOrientation == HORIZONTAL) {
   1735             return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
   1736         } else if (mOrientation == VERTICAL) {
   1737             return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
   1738         }
   1739         return null;
   1740     }
   1741 
   1742     @Override
   1743     protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
   1744         return new LayoutParams(p);
   1745     }
   1746 
   1747 
   1748     // Override to allow type-checking of LayoutParams.
   1749     @Override
   1750     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
   1751         return p instanceof LinearLayout.LayoutParams;
   1752     }
   1753 
   1754     @Override
   1755     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
   1756         super.onInitializeAccessibilityEvent(event);
   1757         event.setClassName(LinearLayout.class.getName());
   1758     }
   1759 
   1760     @Override
   1761     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
   1762         super.onInitializeAccessibilityNodeInfo(info);
   1763         info.setClassName(LinearLayout.class.getName());
   1764     }
   1765 
   1766     /**
   1767      * Per-child layout information associated with ViewLinearLayout.
   1768      *
   1769      * @attr ref android.R.styleable#LinearLayout_Layout_layout_weight
   1770      * @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity
   1771      */
   1772     public static class LayoutParams extends ViewGroup.MarginLayoutParams {
   1773         /**
   1774          * Indicates how much of the extra space in the LinearLayout will be
   1775          * allocated to the view associated with these LayoutParams. Specify
   1776          * 0 if the view should not be stretched. Otherwise the extra pixels
   1777          * will be pro-rated among all views whose weight is greater than 0.
   1778          */
   1779         @ViewDebug.ExportedProperty(category = "layout")
   1780         public float weight;
   1781 
   1782         /**
   1783          * Gravity for the view associated with these LayoutParams.
   1784          *
   1785          * @see android.view.Gravity
   1786          */
   1787         @ViewDebug.ExportedProperty(category = "layout", mapping = {
   1788             @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
   1789             @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
   1790             @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
   1791             @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
   1792             @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
   1793             @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
   1794             @ViewDebug.IntToString(from = Gravity.START,            to = "START"),
   1795             @ViewDebug.IntToString(from = Gravity.END,             to = "END"),
   1796             @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
   1797             @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
   1798             @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
   1799             @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),
   1800             @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),
   1801             @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")
   1802         })
   1803         public int gravity = -1;
   1804 
   1805         /**
   1806          * {@inheritDoc}
   1807          */
   1808         public LayoutParams(Context c, AttributeSet attrs) {
   1809             super(c, attrs);
   1810             TypedArray a =
   1811                     c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);
   1812 
   1813             weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0);
   1814             gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1);
   1815 
   1816             a.recycle();
   1817         }
   1818 
   1819         /**
   1820          * {@inheritDoc}
   1821          */
   1822         public LayoutParams(int width, int height) {
   1823             super(width, height);
   1824             weight = 0;
   1825         }
   1826 
   1827         /**
   1828          * Creates a new set of layout parameters with the specified width, height
   1829          * and weight.
   1830          *
   1831          * @param width the width, either {@link #MATCH_PARENT},
   1832          *        {@link #WRAP_CONTENT} or a fixed size in pixels
   1833          * @param height the height, either {@link #MATCH_PARENT},
   1834          *        {@link #WRAP_CONTENT} or a fixed size in pixels
   1835          * @param weight the weight
   1836          */
   1837         public LayoutParams(int width, int height, float weight) {
   1838             super(width, height);
   1839             this.weight = weight;
   1840         }
   1841 
   1842         /**
   1843          * {@inheritDoc}
   1844          */
   1845         public LayoutParams(ViewGroup.LayoutParams p) {
   1846             super(p);
   1847         }
   1848 
   1849         /**
   1850          * {@inheritDoc}
   1851          */
   1852         public LayoutParams(MarginLayoutParams source) {
   1853             super(source);
   1854         }
   1855 
   1856         @Override
   1857         public String debug(String output) {
   1858             return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) +
   1859                     ", height=" + sizeToString(height) + " weight=" + weight +  "}";
   1860         }
   1861     }
   1862 }
   1863