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