ActionMenuView.java revision e43340c80dc66c45edc793ecd0343774aa34d108
1/*
2 * Copyright (C) 2010 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 */
16package android.widget;
17
18import android.content.Context;
19import android.content.res.Configuration;
20import android.util.AttributeSet;
21import android.view.Gravity;
22import android.view.Menu;
23import android.view.MenuItem;
24import android.view.View;
25import android.view.ViewDebug;
26import android.view.ViewGroup;
27import android.view.accessibility.AccessibilityEvent;
28import com.android.internal.view.menu.ActionMenuItemView;
29import com.android.internal.view.menu.MenuBuilder;
30import com.android.internal.view.menu.MenuItemImpl;
31import com.android.internal.view.menu.MenuPresenter;
32import com.android.internal.view.menu.MenuView;
33
34/**
35 * ActionMenuView is a presentation of a series of menu options as a View. It provides
36 * several top level options as action buttons while spilling remaining options over as
37 * items in an overflow menu. This allows applications to present packs of actions inline with
38 * specific or repeating content.
39 */
40public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvoker, MenuView {
41    private static final String TAG = "ActionMenuView";
42
43    static final int MIN_CELL_SIZE = 56; // dips
44    static final int GENERATED_ITEM_PADDING = 4; // dips
45
46    private MenuBuilder mMenu;
47
48    private boolean mReserveOverflow;
49    private ActionMenuPresenter mPresenter;
50    private boolean mFormatItems;
51    private int mFormatItemsWidth;
52    private int mMinCellSize;
53    private int mGeneratedItemPadding;
54
55    private OnMenuItemClickListener mOnMenuItemClickListener;
56
57    public ActionMenuView(Context context) {
58        this(context, null);
59    }
60
61    public ActionMenuView(Context context, AttributeSet attrs) {
62        super(context, attrs);
63        setBaselineAligned(false);
64        final float density = context.getResources().getDisplayMetrics().density;
65        mMinCellSize = (int) (MIN_CELL_SIZE * density);
66        mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density);
67    }
68
69    /** @hide */
70    public void setPresenter(ActionMenuPresenter presenter) {
71        mPresenter = presenter;
72    }
73
74    @Override
75    public void onConfigurationChanged(Configuration newConfig) {
76        super.onConfigurationChanged(newConfig);
77        mPresenter.updateMenuView(false);
78
79        if (mPresenter != null && mPresenter.isOverflowMenuShowing()) {
80            mPresenter.hideOverflowMenu();
81            mPresenter.showOverflowMenu();
82        }
83    }
84
85    public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
86        mOnMenuItemClickListener = listener;
87    }
88
89    @Override
90    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
91        // If we've been given an exact size to match, apply special formatting during layout.
92        final boolean wasFormatted = mFormatItems;
93        mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
94
95        if (wasFormatted != mFormatItems) {
96            mFormatItemsWidth = 0; // Reset this when switching modes
97        }
98
99        // Special formatting can change whether items can fit as action buttons.
100        // Kick the menu and update presenters when this changes.
101        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
102        if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) {
103            mFormatItemsWidth = widthSize;
104            mMenu.onItemsChanged(true);
105        }
106
107        final int childCount = getChildCount();
108        if (mFormatItems && childCount > 0) {
109            onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec);
110        } else {
111            // Previous measurement at exact format may have set margins - reset them.
112            for (int i = 0; i < childCount; i++) {
113                final View child = getChildAt(i);
114                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
115                lp.leftMargin = lp.rightMargin = 0;
116            }
117            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
118        }
119    }
120
121    private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) {
122        // We already know the width mode is EXACTLY if we're here.
123        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
124        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
125        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
126
127        final int widthPadding = getPaddingLeft() + getPaddingRight();
128        final int heightPadding = getPaddingTop() + getPaddingBottom();
129
130        final int itemHeightSpec = getChildMeasureSpec(heightMeasureSpec, heightPadding,
131                ViewGroup.LayoutParams.WRAP_CONTENT);
132
133        widthSize -= widthPadding;
134
135        // Divide the view into cells.
136        final int cellCount = widthSize / mMinCellSize;
137        final int cellSizeRemaining = widthSize % mMinCellSize;
138
139        if (cellCount == 0) {
140            // Give up, nothing fits.
141            setMeasuredDimension(widthSize, 0);
142            return;
143        }
144
145        final int cellSize = mMinCellSize + cellSizeRemaining / cellCount;
146
147        int cellsRemaining = cellCount;
148        int maxChildHeight = 0;
149        int maxCellsUsed = 0;
150        int expandableItemCount = 0;
151        int visibleItemCount = 0;
152        boolean hasOverflow = false;
153
154        // This is used as a bitfield to locate the smallest items present. Assumes childCount < 64.
155        long smallestItemsAt = 0;
156
157        final int childCount = getChildCount();
158        for (int i = 0; i < childCount; i++) {
159            final View child = getChildAt(i);
160            if (child.getVisibility() == GONE) continue;
161
162            final boolean isGeneratedItem = child instanceof ActionMenuItemView;
163            visibleItemCount++;
164
165            if (isGeneratedItem) {
166                // Reset padding for generated menu item views; it may change below
167                // and views are recycled.
168                child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0);
169            }
170
171            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
172            lp.expanded = false;
173            lp.extraPixels = 0;
174            lp.cellsUsed = 0;
175            lp.expandable = false;
176            lp.leftMargin = 0;
177            lp.rightMargin = 0;
178            lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText();
179
180            // Overflow always gets 1 cell. No more, no less.
181            final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining;
182
183            final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable,
184                    itemHeightSpec, heightPadding);
185
186            maxCellsUsed = Math.max(maxCellsUsed, cellsUsed);
187            if (lp.expandable) expandableItemCount++;
188            if (lp.isOverflowButton) hasOverflow = true;
189
190            cellsRemaining -= cellsUsed;
191            maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
192            if (cellsUsed == 1) smallestItemsAt |= (1 << i);
193        }
194
195        // When we have overflow and a single expanded (text) item, we want to try centering it
196        // visually in the available space even though overflow consumes some of it.
197        final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2;
198
199        // Divide space for remaining cells if we have items that can expand.
200        // Try distributing whole leftover cells to smaller items first.
201
202        boolean needsExpansion = false;
203        while (expandableItemCount > 0 && cellsRemaining > 0) {
204            int minCells = Integer.MAX_VALUE;
205            long minCellsAt = 0; // Bit locations are indices of relevant child views
206            int minCellsItemCount = 0;
207            for (int i = 0; i < childCount; i++) {
208                final View child = getChildAt(i);
209                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
210
211                // Don't try to expand items that shouldn't.
212                if (!lp.expandable) continue;
213
214                // Mark indices of children that can receive an extra cell.
215                if (lp.cellsUsed < minCells) {
216                    minCells = lp.cellsUsed;
217                    minCellsAt = 1 << i;
218                    minCellsItemCount = 1;
219                } else if (lp.cellsUsed == minCells) {
220                    minCellsAt |= 1 << i;
221                    minCellsItemCount++;
222                }
223            }
224
225            // Items that get expanded will always be in the set of smallest items when we're done.
226            smallestItemsAt |= minCellsAt;
227
228            if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop.
229
230            // We have enough cells, all minimum size items will be incremented.
231            minCells++;
232
233            for (int i = 0; i < childCount; i++) {
234                final View child = getChildAt(i);
235                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
236                if ((minCellsAt & (1 << i)) == 0) {
237                    // If this item is already at our small item count, mark it for later.
238                    if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i;
239                    continue;
240                }
241
242                if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) {
243                    // Add padding to this item such that it centers.
244                    child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0);
245                }
246                lp.cellsUsed++;
247                lp.expanded = true;
248                cellsRemaining--;
249            }
250
251            needsExpansion = true;
252        }
253
254        // Divide any space left that wouldn't divide along cell boundaries
255        // evenly among the smallest items
256
257        final boolean singleItem = !hasOverflow && visibleItemCount == 1;
258        if (cellsRemaining > 0 && smallestItemsAt != 0 &&
259                (cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) {
260            float expandCount = Long.bitCount(smallestItemsAt);
261
262            if (!singleItem) {
263                // The items at the far edges may only expand by half in order to pin to either side.
264                if ((smallestItemsAt & 1) != 0) {
265                    LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams();
266                    if (!lp.preventEdgeOffset) expandCount -= 0.5f;
267                }
268                if ((smallestItemsAt & (1 << (childCount - 1))) != 0) {
269                    LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams());
270                    if (!lp.preventEdgeOffset) expandCount -= 0.5f;
271                }
272            }
273
274            final int extraPixels = expandCount > 0 ?
275                    (int) (cellsRemaining * cellSize / expandCount) : 0;
276
277            for (int i = 0; i < childCount; i++) {
278                if ((smallestItemsAt & (1 << i)) == 0) continue;
279
280                final View child = getChildAt(i);
281                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
282                if (child instanceof ActionMenuItemView) {
283                    // If this is one of our views, expand and measure at the larger size.
284                    lp.extraPixels = extraPixels;
285                    lp.expanded = true;
286                    if (i == 0 && !lp.preventEdgeOffset) {
287                        // First item gets part of its new padding pushed out of sight.
288                        // The last item will get this implicitly from layout.
289                        lp.leftMargin = -extraPixels / 2;
290                    }
291                    needsExpansion = true;
292                } else if (lp.isOverflowButton) {
293                    lp.extraPixels = extraPixels;
294                    lp.expanded = true;
295                    lp.rightMargin = -extraPixels / 2;
296                    needsExpansion = true;
297                } else {
298                    // If we don't know what it is, give it some margins instead
299                    // and let it center within its space. We still want to pin
300                    // against the edges.
301                    if (i != 0) {
302                        lp.leftMargin = extraPixels / 2;
303                    }
304                    if (i != childCount - 1) {
305                        lp.rightMargin = extraPixels / 2;
306                    }
307                }
308            }
309
310            cellsRemaining = 0;
311        }
312
313        // Remeasure any items that have had extra space allocated to them.
314        if (needsExpansion) {
315            for (int i = 0; i < childCount; i++) {
316                final View child = getChildAt(i);
317                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
318
319                if (!lp.expanded) continue;
320
321                final int width = lp.cellsUsed * cellSize + lp.extraPixels;
322                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
323                        itemHeightSpec);
324            }
325        }
326
327        if (heightMode != MeasureSpec.EXACTLY) {
328            heightSize = maxChildHeight;
329        }
330
331        setMeasuredDimension(widthSize, heightSize);
332    }
333
334    /**
335     * Measure a child view to fit within cell-based formatting. The child's width
336     * will be measured to a whole multiple of cellSize.
337     *
338     * <p>Sets the expandable and cellsUsed fields of LayoutParams.
339     *
340     * @param child Child to measure
341     * @param cellSize Size of one cell
342     * @param cellsRemaining Number of cells remaining that this view can expand to fill
343     * @param parentHeightMeasureSpec MeasureSpec used by the parent view
344     * @param parentHeightPadding Padding present in the parent view
345     * @return Number of cells this child was measured to occupy
346     */
347    static int measureChildForCells(View child, int cellSize, int cellsRemaining,
348            int parentHeightMeasureSpec, int parentHeightPadding) {
349        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
350
351        final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) -
352                parentHeightPadding;
353        final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec);
354        final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode);
355
356        final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
357                (ActionMenuItemView) child : null;
358        final boolean hasText = itemView != null && itemView.hasText();
359
360        int cellsUsed = 0;
361        if (cellsRemaining > 0 && (!hasText || cellsRemaining >= 2)) {
362            final int childWidthSpec = MeasureSpec.makeMeasureSpec(
363                    cellSize * cellsRemaining, MeasureSpec.AT_MOST);
364            child.measure(childWidthSpec, childHeightSpec);
365
366            final int measuredWidth = child.getMeasuredWidth();
367            cellsUsed = measuredWidth / cellSize;
368            if (measuredWidth % cellSize != 0) cellsUsed++;
369            if (hasText && cellsUsed < 2) cellsUsed = 2;
370        }
371
372        final boolean expandable = !lp.isOverflowButton && hasText;
373        lp.expandable = expandable;
374
375        lp.cellsUsed = cellsUsed;
376        final int targetWidth = cellsUsed * cellSize;
377        child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
378                childHeightSpec);
379        return cellsUsed;
380    }
381
382    @Override
383    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
384        if (!mFormatItems) {
385            super.onLayout(changed, left, top, right, bottom);
386            return;
387        }
388
389        final int childCount = getChildCount();
390        final int midVertical = (top + bottom) / 2;
391        final int dividerWidth = getDividerWidth();
392        int overflowWidth = 0;
393        int nonOverflowWidth = 0;
394        int nonOverflowCount = 0;
395        int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
396        boolean hasOverflow = false;
397        final boolean isLayoutRtl = isLayoutRtl();
398        for (int i = 0; i < childCount; i++) {
399            final View v = getChildAt(i);
400            if (v.getVisibility() == GONE) {
401                continue;
402            }
403
404            LayoutParams p = (LayoutParams) v.getLayoutParams();
405            if (p.isOverflowButton) {
406                overflowWidth = v.getMeasuredWidth();
407                if (hasDividerBeforeChildAt(i)) {
408                    overflowWidth += dividerWidth;
409                }
410
411                int height = v.getMeasuredHeight();
412                int r;
413                int l;
414                if (isLayoutRtl) {
415                    l = getPaddingLeft() + p.leftMargin;
416                    r = l + overflowWidth;
417                } else {
418                    r = getWidth() - getPaddingRight() - p.rightMargin;
419                    l = r - overflowWidth;
420                }
421                int t = midVertical - (height / 2);
422                int b = t + height;
423                v.layout(l, t, r, b);
424
425                widthRemaining -= overflowWidth;
426                hasOverflow = true;
427            } else {
428                final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
429                nonOverflowWidth += size;
430                widthRemaining -= size;
431                if (hasDividerBeforeChildAt(i)) {
432                    nonOverflowWidth += dividerWidth;
433                }
434                nonOverflowCount++;
435            }
436        }
437
438        if (childCount == 1 && !hasOverflow) {
439            // Center a single child
440            final View v = getChildAt(0);
441            final int width = v.getMeasuredWidth();
442            final int height = v.getMeasuredHeight();
443            final int midHorizontal = (right - left) / 2;
444            final int l = midHorizontal - width / 2;
445            final int t = midVertical - height / 2;
446            v.layout(l, t, l + width, t + height);
447            return;
448        }
449
450        final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1);
451        final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0);
452
453        if (isLayoutRtl) {
454            int startRight = getWidth() - getPaddingRight();
455            for (int i = 0; i < childCount; i++) {
456                final View v = getChildAt(i);
457                final LayoutParams lp = (LayoutParams) v.getLayoutParams();
458                if (v.getVisibility() == GONE || lp.isOverflowButton) {
459                    continue;
460                }
461
462                startRight -= lp.rightMargin;
463                int width = v.getMeasuredWidth();
464                int height = v.getMeasuredHeight();
465                int t = midVertical - height / 2;
466                v.layout(startRight - width, t, startRight, t + height);
467                startRight -= width + lp.leftMargin + spacerSize;
468            }
469        } else {
470            int startLeft = getPaddingLeft();
471            for (int i = 0; i < childCount; i++) {
472                final View v = getChildAt(i);
473                final LayoutParams lp = (LayoutParams) v.getLayoutParams();
474                if (v.getVisibility() == GONE || lp.isOverflowButton) {
475                    continue;
476                }
477
478                startLeft += lp.leftMargin;
479                int width = v.getMeasuredWidth();
480                int height = v.getMeasuredHeight();
481                int t = midVertical - height / 2;
482                v.layout(startLeft, t, startLeft + width, t + height);
483                startLeft += width + lp.rightMargin + spacerSize;
484            }
485        }
486    }
487
488    @Override
489    public void onDetachedFromWindow() {
490        super.onDetachedFromWindow();
491        mPresenter.dismissPopupMenus();
492    }
493
494    /** @hide */
495    public boolean isOverflowReserved() {
496        return mReserveOverflow;
497    }
498
499    /** @hide */
500    public void setOverflowReserved(boolean reserveOverflow) {
501        mReserveOverflow = reserveOverflow;
502    }
503
504    @Override
505    protected LayoutParams generateDefaultLayoutParams() {
506        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
507                LayoutParams.WRAP_CONTENT);
508        params.gravity = Gravity.CENTER_VERTICAL;
509        return params;
510    }
511
512    @Override
513    public LayoutParams generateLayoutParams(AttributeSet attrs) {
514        return new LayoutParams(getContext(), attrs);
515    }
516
517    @Override
518    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
519        if (p != null) {
520            final LayoutParams result = p instanceof LayoutParams
521                    ? new LayoutParams((LayoutParams) p)
522                    : new LayoutParams(p);
523            if (result.gravity <= Gravity.NO_GRAVITY) {
524                result.gravity = Gravity.CENTER_VERTICAL;
525            }
526            return result;
527        }
528        return generateDefaultLayoutParams();
529    }
530
531    @Override
532    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
533        return p != null && p instanceof LayoutParams;
534    }
535
536    /** @hide */
537    public LayoutParams generateOverflowButtonLayoutParams() {
538        LayoutParams result = generateDefaultLayoutParams();
539        result.isOverflowButton = true;
540        return result;
541    }
542
543    /** @hide */
544    public boolean invokeItem(MenuItemImpl item) {
545        return mMenu.performItemAction(item, 0);
546    }
547
548    /** @hide */
549    public int getWindowAnimations() {
550        return 0;
551    }
552
553    /** @hide */
554    public void initialize(MenuBuilder menu) {
555        mMenu = menu;
556    }
557
558    /**
559     * Returns the Menu object that this ActionMenuView is currently presenting.
560     *
561     * <p>Applications should use this method to obtain the ActionMenuView's Menu object
562     * and inflate or add content to it as necessary.</p>
563     *
564     * @return the Menu presented by this view
565     */
566    public Menu getMenu() {
567        if (mMenu == null) {
568            final Context context = getContext();
569            mMenu = new MenuBuilder(context);
570            mMenu.setCallback(new MenuBuilderCallback());
571            mPresenter = new ActionMenuPresenter(context);
572            mPresenter.setMenuView(this);
573            mPresenter.setCallback(new ActionMenuPresenterCallback());
574            mMenu.addMenuPresenter(mPresenter);
575        }
576
577        return mMenu;
578    }
579
580    /**
581     * @hide Private LinearLayout (superclass) API. Un-hide if LinearLayout API is made public.
582     */
583    @Override
584    protected boolean hasDividerBeforeChildAt(int childIndex) {
585        if (childIndex == 0) {
586            return false;
587        }
588        final View childBefore = getChildAt(childIndex - 1);
589        final View child = getChildAt(childIndex);
590        boolean result = false;
591        if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) {
592            result |= ((ActionMenuChildView) childBefore).needsDividerAfter();
593        }
594        if (childIndex > 0 && child instanceof ActionMenuChildView) {
595            result |= ((ActionMenuChildView) child).needsDividerBefore();
596        }
597        return result;
598    }
599
600    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
601        return false;
602    }
603
604    /**
605     * Interface responsible for receiving menu item click events if the items themselves
606     * do not have individual item click listeners.
607     */
608    public interface OnMenuItemClickListener {
609        /**
610         * This method will be invoked when a menu item is clicked if the item itself did
611         * not already handle the event.
612         *
613         * @param item {@link MenuItem} that was clicked
614         * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
615         */
616        public boolean onMenuItemClick(MenuItem item);
617    }
618
619    private class MenuBuilderCallback implements MenuBuilder.Callback {
620        @Override
621        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
622            return mOnMenuItemClickListener != null &&
623                    mOnMenuItemClickListener.onMenuItemClick(item);
624        }
625
626        @Override
627        public void onMenuModeChange(MenuBuilder menu) {
628        }
629    }
630
631    private class ActionMenuPresenterCallback implements ActionMenuPresenter.Callback {
632        @Override
633        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
634        }
635
636        @Override
637        public boolean onOpenSubMenu(MenuBuilder subMenu) {
638            return false;
639        }
640    }
641
642    /** @hide */
643    public interface ActionMenuChildView {
644        public boolean needsDividerBefore();
645        public boolean needsDividerAfter();
646    }
647
648    public static class LayoutParams extends LinearLayout.LayoutParams {
649        /** @hide */
650        @ViewDebug.ExportedProperty(category = "layout")
651        public boolean isOverflowButton;
652
653        /** @hide */
654        @ViewDebug.ExportedProperty(category = "layout")
655        public int cellsUsed;
656
657        /** @hide */
658        @ViewDebug.ExportedProperty(category = "layout")
659        public int extraPixels;
660
661        /** @hide */
662        @ViewDebug.ExportedProperty(category = "layout")
663        public boolean expandable;
664
665        /** @hide */
666        @ViewDebug.ExportedProperty(category = "layout")
667        public boolean preventEdgeOffset;
668
669        /** @hide */
670        public boolean expanded;
671
672        public LayoutParams(Context c, AttributeSet attrs) {
673            super(c, attrs);
674        }
675
676        public LayoutParams(ViewGroup.LayoutParams other) {
677            super(other);
678        }
679
680        public LayoutParams(LayoutParams other) {
681            super((LinearLayout.LayoutParams) other);
682            isOverflowButton = other.isOverflowButton;
683        }
684
685        public LayoutParams(int width, int height) {
686            super(width, height);
687            isOverflowButton = false;
688        }
689
690        /** @hide */
691        public LayoutParams(int width, int height, boolean isOverflowButton) {
692            super(width, height);
693            this.isOverflowButton = isOverflowButton;
694        }
695    }
696}
697