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