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