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