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 android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.content.Context;
23import android.content.res.TypedArray;
24import android.graphics.Canvas;
25import android.graphics.drawable.Drawable;
26import android.os.Build;
27import android.util.AttributeSet;
28import android.view.Gravity;
29import android.view.View;
30import android.view.ViewDebug;
31import android.view.ViewGroup;
32import android.view.ViewHierarchyEncoder;
33import android.widget.RemoteViews.RemoteView;
34
35import com.android.internal.R;
36
37import java.lang.annotation.Retention;
38import 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
88public 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