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