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