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