196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell/*
296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * Copyright (C) 2010 The Android Open Source Project
396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell *
496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * Licensed under the Apache License, Version 2.0 (the "License");
596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * you may not use this file except in compliance with the License.
696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * You may obtain a copy of the License at
796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell *
896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell *      http://www.apache.org/licenses/LICENSE-2.0
996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell *
1096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * Unless required by applicable law or agreed to in writing, software
1196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * distributed under the License is distributed on an "AS IS" BASIS,
1296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * See the License for the specific language governing permissions and
1496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * limitations under the License.
1596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell */
1696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellpackage com.android.internal.view.menu;
1796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
18d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powellimport com.android.internal.R;
19d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell
2096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.content.Context;
218028dd32a4a04154050220dd0693583d5b750330Adam Powellimport android.content.res.Configuration;
22367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powellimport android.content.res.TypedArray;
2396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.util.AttributeSet;
246b336f835d637853800b94689375a03f337139a4Adam Powellimport android.view.Gravity;
25cf78b3e5101349fdddbde14b3a55140f9562ae66Adam Powellimport android.view.View;
26640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powellimport android.view.ViewDebug;
277ade1be822ed05a143b059319dccd5e9f623b56dAdam Powellimport android.view.ViewGroup;
287bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powellimport android.view.accessibility.AccessibilityEvent;
2996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.widget.LinearLayout;
3096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
3196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell/**
3296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * @hide
3396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell */
3496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellpublic class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvoker, MenuView {
3596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private static final String TAG = "ActionMenuView";
3696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
3735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    static final int MIN_CELL_SIZE = 56; // dips
38be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell    static final int GENERATED_ITEM_PADDING = 4; // dips
3935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
4096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private MenuBuilder mMenu;
417ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell
428028dd32a4a04154050220dd0693583d5b750330Adam Powell    private boolean mReserveOverflow;
43696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private ActionMenuPresenter mPresenter;
44640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    private boolean mFormatItems;
4589b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell    private int mFormatItemsWidth;
4635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    private int mMinCellSize;
47be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell    private int mGeneratedItemPadding;
4835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    private int mMeasuredExtraWidth;
49367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell    private int mMaxItemHeight;
508515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell
5196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public ActionMenuView(Context context) {
5296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        this(context, null);
5396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
5496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
5596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public ActionMenuView(Context context, AttributeSet attrs) {
5696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        super(context, attrs);
57f16888f1e849b0bc0b9c17e5f833c4e2cd54c382Adam Powell        setBaselineAligned(false);
58be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell        final float density = context.getResources().getDisplayMetrics().density;
59be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell        mMinCellSize = (int) (MIN_CELL_SIZE * density);
60be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell        mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density);
61367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell
62367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar,
63367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell                R.attr.actionBarStyle, 0);
64367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        mMaxItemHeight = a.getDimensionPixelSize(R.styleable.ActionBar_height, 0);
65367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        a.recycle();
66773b1b97fc0f01efc8cf1e17a1250a9b654b1b85Adam Powell    }
67773b1b97fc0f01efc8cf1e17a1250a9b654b1b85Adam Powell
68696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void setPresenter(ActionMenuPresenter presenter) {
69696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mPresenter = presenter;
70696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
71696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
7235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    public boolean isExpandedFormat() {
7335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        return mFormatItems;
7435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    }
7535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
76d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell    public void setMaxItemHeight(int maxItemHeight) {
77d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell        mMaxItemHeight = maxItemHeight;
78d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell        requestLayout();
79d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell    }
80d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell
816c6f575423d6718c3ff322224c1520901ce881e1Adam Powell    @Override
82773b1b97fc0f01efc8cf1e17a1250a9b654b1b85Adam Powell    public void onConfigurationChanged(Configuration newConfig) {
838515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell        super.onConfigurationChanged(newConfig);
84696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mPresenter.updateMenuView(false);
856c6f575423d6718c3ff322224c1520901ce881e1Adam Powell
86696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mPresenter != null && mPresenter.isOverflowMenuShowing()) {
87696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mPresenter.hideOverflowMenu();
88696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mPresenter.showOverflowMenu();
896c6f575423d6718c3ff322224c1520901ce881e1Adam Powell        }
90773b1b97fc0f01efc8cf1e17a1250a9b654b1b85Adam Powell    }
91773b1b97fc0f01efc8cf1e17a1250a9b654b1b85Adam Powell
928515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell    @Override
93640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
9435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        // If we've been given an exact size to match, apply special formatting during layout.
9589b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell        final boolean wasFormatted = mFormatItems;
9635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
9789b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell
9889b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell        if (wasFormatted != mFormatItems) {
9989b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell            mFormatItemsWidth = 0; // Reset this when switching modes
10089b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell        }
10189b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell
10289b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell        // Special formatting can change whether items can fit as action buttons.
10389b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell        // Kick the menu and update presenters when this changes.
10489b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell        final int widthSize = MeasureSpec.getMode(widthMeasureSpec);
10589b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell        if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) {
10689b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell            mFormatItemsWidth = widthSize;
107640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            mMenu.onItemsChanged(true);
108640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        }
10935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
11035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        if (mFormatItems) {
11135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec);
11235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        } else {
11375d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell            // Previous measurement at exact format may have set margins - reset them.
11475d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell            final int childCount = getChildCount();
11575d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell            for (int i = 0; i < childCount; i++) {
11675d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell                final View child = getChildAt(i);
11775d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
11875d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell                lp.leftMargin = lp.rightMargin = 0;
11975d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell            }
12035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
12135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
12235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    }
12335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
12435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) {
12535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        // We already know the width mode is EXACTLY if we're here.
12635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
12735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
12835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
12935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
13035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int widthPadding = getPaddingLeft() + getPaddingRight();
13135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int heightPadding = getPaddingTop() + getPaddingBottom();
13235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
133367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        final int itemHeightSpec = heightMode == MeasureSpec.EXACTLY
134367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell                ? MeasureSpec.makeMeasureSpec(heightSize - heightPadding, MeasureSpec.EXACTLY)
135367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell                : MeasureSpec.makeMeasureSpec(
136367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell                    Math.min(mMaxItemHeight, heightSize - heightPadding), MeasureSpec.AT_MOST);
137367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell
13835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        widthSize -= widthPadding;
13935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
14035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        // Divide the view into cells.
14135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int cellCount = widthSize / mMinCellSize;
14235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int cellSizeRemaining = widthSize % mMinCellSize;
1433bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell
1443bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell        if (cellCount == 0) {
1453bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell            // Give up, nothing fits.
1463bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell            setMeasuredDimension(widthSize, 0);
1473bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell            return;
1483bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell        }
1493bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell
15035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int cellSize = mMinCellSize + cellSizeRemaining / cellCount;
15135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
15235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        int cellsRemaining = cellCount;
15335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        int maxChildHeight = 0;
15435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        int maxCellsUsed = 0;
155160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell        int expandableItemCount = 0;
15614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        int visibleItemCount = 0;
15714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        boolean hasOverflow = false;
15835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
15914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        // This is used as a bitfield to locate the smallest items present. Assumes childCount < 64.
16014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        long smallestItemsAt = 0;
16135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
16235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int childCount = getChildCount();
16335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        for (int i = 0; i < childCount; i++) {
16435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            final View child = getChildAt(i);
16514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            if (child.getVisibility() == GONE) continue;
16614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell
167be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell            final boolean isGeneratedItem = child instanceof ActionMenuItemView;
16814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            visibleItemCount++;
16914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell
170be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell            if (isGeneratedItem) {
171be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                // Reset padding for generated menu item views; it may change below
172be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                // and views are recycled.
173be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0);
174be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell            }
175be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell
17635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
17735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            lp.expanded = false;
17835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            lp.extraPixels = 0;
17935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            lp.cellsUsed = 0;
180160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell            lp.expandable = false;
18114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            lp.leftMargin = 0;
18214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            lp.rightMargin = 0;
183be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell            lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText();
18435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
18535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            // Overflow always gets 1 cell. No more, no less.
18635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining;
18735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
18835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable,
189367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell                    itemHeightSpec, heightPadding);
19035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
19135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            maxCellsUsed = Math.max(maxCellsUsed, cellsUsed);
192160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell            if (lp.expandable) expandableItemCount++;
19314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            if (lp.isOverflowButton) hasOverflow = true;
19435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
19535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            cellsRemaining -= cellsUsed;
19635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
19714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            if (cellsUsed == 1) smallestItemsAt |= (1 << i);
19835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
19935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
200be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell        // When we have overflow and a single expanded (text) item, we want to try centering it
201be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell        // visually in the available space even though overflow consumes some of it.
202be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell        final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2;
203be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell
20435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        // Divide space for remaining cells if we have items that can expand.
20535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        // Try distributing whole leftover cells to smaller items first.
20635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
20735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        boolean needsExpansion = false;
208160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell        while (expandableItemCount > 0 && cellsRemaining > 0) {
20935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            int minCells = Integer.MAX_VALUE;
21035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            long minCellsAt = 0; // Bit locations are indices of relevant child views
21135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            int minCellsItemCount = 0;
21235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            for (int i = 0; i < childCount; i++) {
21335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                final View child = getChildAt(i);
21435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
21535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
21635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                // Don't try to expand items that shouldn't.
217160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell                if (!lp.expandable) continue;
21835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
21935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                // Mark indices of children that can receive an extra cell.
22035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                if (lp.cellsUsed < minCells) {
22135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    minCells = lp.cellsUsed;
22235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    minCellsAt = 1 << i;
22335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    minCellsItemCount = 1;
22435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                } else if (lp.cellsUsed == minCells) {
22535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    minCellsAt |= 1 << i;
22635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    minCellsItemCount++;
22735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                }
22835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            }
22935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
23035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            // Items that get expanded will always be in the set of smallest items when we're done.
23114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            smallestItemsAt |= minCellsAt;
23235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
233be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell            if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop.
23435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
235be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell            // We have enough cells, all minimum size items will be incremented.
236be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell            minCells++;
237be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell
238be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell            for (int i = 0; i < childCount; i++) {
23935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                final View child = getChildAt(i);
24035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
241be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                if ((minCellsAt & (1 << i)) == 0) {
242be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                    // If this item is already at our small item count, mark it for later.
243be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                    if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i;
244be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                    continue;
245be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                }
246be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell
247be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) {
248be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                    // Add padding to this item such that it centers.
249be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                    child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0);
250be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                }
25135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                lp.cellsUsed++;
25235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                lp.expanded = true;
25335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                cellsRemaining--;
25435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            }
25535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
25635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            needsExpansion = true;
25735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
25835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
25935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        // Divide any space left that wouldn't divide along cell boundaries
26014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        // evenly among the smallest items
26114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell
26214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        final boolean singleItem = !hasOverflow && visibleItemCount == 1;
26314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        if (cellsRemaining > 0 && smallestItemsAt != 0 &&
264be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                (cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) {
26514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            float expandCount = Long.bitCount(smallestItemsAt);
26614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell
26714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            if (!singleItem) {
26814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                // The items at the far edges may only expand by half in order to pin to either side.
26914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                if ((smallestItemsAt & 1) != 0) {
270be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                    LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams();
271be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                    if (!lp.preventEdgeOffset) expandCount -= 0.5f;
27214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                }
27314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                if ((smallestItemsAt & (1 << (childCount - 1))) != 0) {
274be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                    LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams());
275be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                    if (!lp.preventEdgeOffset) expandCount -= 0.5f;
27614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                }
27714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            }
27835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
2793bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell            final int extraPixels = expandCount > 0 ?
2803bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell                    (int) (cellsRemaining * cellSize / expandCount) : 0;
28135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
28235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            for (int i = 0; i < childCount; i++) {
28314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                if ((smallestItemsAt & (1 << i)) == 0) continue;
28435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
28535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                final View child = getChildAt(i);
28635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
28714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                if (child instanceof ActionMenuItemView) {
28814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    // If this is one of our views, expand and measure at the larger size.
28914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    lp.extraPixels = extraPixels;
29014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    lp.expanded = true;
291be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell                    if (i == 0 && !lp.preventEdgeOffset) {
29214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                        // First item gets part of its new padding pushed out of sight.
29314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                        // The last item will get this implicitly from layout.
29414b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                        lp.leftMargin = -extraPixels / 2;
29514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    }
29614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    needsExpansion = true;
29714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                } else if (lp.isOverflowButton) {
29814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    lp.extraPixels = extraPixels;
29914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    lp.expanded = true;
30014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    lp.rightMargin = -extraPixels / 2;
30114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    needsExpansion = true;
30214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                } else {
30314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    // If we don't know what it is, give it some margins instead
30414b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    // and let it center within its space. We still want to pin
30514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    // against the edges.
30614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    if (i != 0) {
30714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                        lp.leftMargin = extraPixels / 2;
30814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    }
30914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    if (i != childCount - 1) {
31014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                        lp.rightMargin = extraPixels / 2;
31114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                    }
31214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell                }
31335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            }
31435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
31535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            cellsRemaining = 0;
31635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
31735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
31835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        // Remeasure any items that have had extra space allocated to them.
31935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        if (needsExpansion) {
32035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            for (int i = 0; i < childCount; i++) {
32135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                final View child = getChildAt(i);
32235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
32335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
32435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                if (!lp.expanded) continue;
32535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
32635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                final int width = lp.cellsUsed * cellSize + lp.extraPixels;
327367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
328367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell                        itemHeightSpec);
32935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            }
33035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
33135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
33235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        if (heightMode != MeasureSpec.EXACTLY) {
33335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            heightSize = maxChildHeight;
33435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
33535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
33635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        setMeasuredDimension(widthSize, heightSize);
33735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        mMeasuredExtraWidth = cellsRemaining * cellSize;
33835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    }
33935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
34035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    /**
34135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     * Measure a child view to fit within cell-based formatting. The child's width
34235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     * will be measured to a whole multiple of cellSize.
34335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     *
344160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell     * <p>Sets the expandable and cellsUsed fields of LayoutParams.
34535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     *
34635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     * @param child Child to measure
34735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     * @param cellSize Size of one cell
34835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     * @param cellsRemaining Number of cells remaining that this view can expand to fill
34935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     * @param parentHeightMeasureSpec MeasureSpec used by the parent view
35035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     * @param parentHeightPadding Padding present in the parent view
35135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     * @return Number of cells this child was measured to occupy
35235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell     */
35335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    static int measureChildForCells(View child, int cellSize, int cellsRemaining,
35435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            int parentHeightMeasureSpec, int parentHeightPadding) {
35535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
35635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
35735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) -
35835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                parentHeightPadding;
35935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec);
36035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode);
36135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
362a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell        final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
363a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell                (ActionMenuItemView) child : null;
364a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell        final boolean hasText = itemView != null && itemView.hasText();
365a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell
366160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell        int cellsUsed = 0;
367a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell        if (cellsRemaining > 0 && (!hasText || cellsRemaining >= 2)) {
36835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            final int childWidthSpec = MeasureSpec.makeMeasureSpec(
36935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    cellSize * cellsRemaining, MeasureSpec.AT_MOST);
37035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            child.measure(childWidthSpec, childHeightSpec);
37135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
37235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            final int measuredWidth = child.getMeasuredWidth();
37335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            cellsUsed = measuredWidth / cellSize;
37435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            if (measuredWidth % cellSize != 0) cellsUsed++;
375a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell            if (hasText && cellsUsed < 2) cellsUsed = 2;
37635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
377160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell
378a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell        final boolean expandable = !lp.isOverflowButton && hasText;
379160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell        lp.expandable = expandable;
380160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell
38135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        lp.cellsUsed = cellsUsed;
38235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int targetWidth = cellsUsed * cellSize;
38335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
38435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                childHeightSpec);
38535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        return cellsUsed;
386640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    }
387640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
388640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    @Override
389640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
390640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        if (!mFormatItems) {
391640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            super.onLayout(changed, left, top, right, bottom);
392640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            return;
393640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        }
394640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
395640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        final int childCount = getChildCount();
396640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        final int midVertical = (top + bottom) / 2;
397640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        final int dividerWidth = getDividerWidth();
398640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        int overflowWidth = 0;
399640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        int nonOverflowWidth = 0;
400640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        int nonOverflowCount = 0;
401640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
40235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        boolean hasOverflow = false;
4030762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio        final boolean isLayoutRtl = isLayoutRtl();
404640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        for (int i = 0; i < childCount; i++) {
405640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            final View v = getChildAt(i);
406640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            if (v.getVisibility() == GONE) {
407640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                continue;
408640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            }
409640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
410640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            LayoutParams p = (LayoutParams) v.getLayoutParams();
411640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            if (p.isOverflowButton) {
412640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                overflowWidth = v.getMeasuredWidth();
413640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                if (hasDividerBeforeChildAt(i)) {
414640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                    overflowWidth += dividerWidth;
415640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                }
416640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
417640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                int height = v.getMeasuredHeight();
4180762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                int r;
4190762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                int l;
4200762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                if (isLayoutRtl) {
4210762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                    l = getPaddingLeft() + p.leftMargin;
4220762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                    r = l + overflowWidth;
4230762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                } else {
4240762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                    r = getWidth() - getPaddingRight() - p.rightMargin;
4250762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                    l = r - overflowWidth;
4260762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                }
427640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                int t = midVertical - (height / 2);
428640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                int b = t + height;
429640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                v.layout(l, t, r, b);
430640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
431640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                widthRemaining -= overflowWidth;
43235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                hasOverflow = true;
433640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            } else {
43435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
43535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                nonOverflowWidth += size;
43635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                widthRemaining -= size;
437640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                if (hasDividerBeforeChildAt(i)) {
438640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                    nonOverflowWidth += dividerWidth;
439640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                }
440640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                nonOverflowCount++;
441640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            }
442640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        }
443640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
44414b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        if (childCount == 1 && !hasOverflow) {
44514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            // Center a single child
44614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            final View v = getChildAt(0);
44714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            final int width = v.getMeasuredWidth();
44814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            final int height = v.getMeasuredHeight();
44914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            final int midHorizontal = (right - left) / 2;
45014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            final int l = midHorizontal - width / 2;
45114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            final int t = midVertical - height / 2;
45214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            v.layout(l, t, l + width, t + height);
45314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell            return;
45414b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        }
45514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell
45635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1);
45714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0);
458640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
4590762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio        if (isLayoutRtl) {
4600762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio            int startRight = getWidth() - getPaddingRight();
4610762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio            for (int i = 0; i < childCount; i++) {
4620762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                final View v = getChildAt(i);
4630762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                final LayoutParams lp = (LayoutParams) v.getLayoutParams();
4640762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                if (v.getVisibility() == GONE || lp.isOverflowButton) {
4650762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                    continue;
4660762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                }
4670762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio
4680762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                startRight -= lp.rightMargin;
4690762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                int width = v.getMeasuredWidth();
4700762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                int height = v.getMeasuredHeight();
4710762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                int t = midVertical - height / 2;
4720762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                v.layout(startRight - width, t, startRight, t + height);
4730762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                startRight -= width + lp.leftMargin + spacerSize;
474640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            }
4750762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio        } else {
4760762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio            int startLeft = getPaddingLeft();
4770762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio            for (int i = 0; i < childCount; i++) {
4780762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                final View v = getChildAt(i);
4790762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                final LayoutParams lp = (LayoutParams) v.getLayoutParams();
4800762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                if (v.getVisibility() == GONE || lp.isOverflowButton) {
4810762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                    continue;
4820762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                }
483640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
4840762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                startLeft += lp.leftMargin;
4850762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                int width = v.getMeasuredWidth();
4860762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                int height = v.getMeasuredHeight();
4870762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                int t = midVertical - height / 2;
4880762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                v.layout(startLeft, t, startLeft + width, t + height);
4890762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio                startLeft += width + lp.rightMargin + spacerSize;
4900762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio            }
491640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        }
492640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    }
493640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
494640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    @Override
4958515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell    public void onDetachedFromWindow() {
4968515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell        super.onDetachedFromWindow();
497696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mPresenter.dismissPopupMenus();
4988028dd32a4a04154050220dd0693583d5b750330Adam Powell    }
4998028dd32a4a04154050220dd0693583d5b750330Adam Powell
5008028dd32a4a04154050220dd0693583d5b750330Adam Powell    public boolean isOverflowReserved() {
5018028dd32a4a04154050220dd0693583d5b750330Adam Powell        return mReserveOverflow;
5027ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell    }
5037ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell
504b366bbae2b5a3009893ef64246e3430cea4b7736Adam Powell    public void setOverflowReserved(boolean reserveOverflow) {
505b366bbae2b5a3009893ef64246e3430cea4b7736Adam Powell        mReserveOverflow = reserveOverflow;
506b366bbae2b5a3009893ef64246e3430cea4b7736Adam Powell    }
507f0ad6e6eaf48ac8f4007232ad0a8511a7b5cfc0eAdam Powell
5087ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell    @Override
5097ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell    protected LayoutParams generateDefaultLayoutParams() {
5107ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
5117ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell                LayoutParams.WRAP_CONTENT);
5126b336f835d637853800b94689375a03f337139a4Adam Powell        params.gravity = Gravity.CENTER_VERTICAL;
5137ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell        return params;
5147ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell    }
5157ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell
5167ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell    @Override
51735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    public LayoutParams generateLayoutParams(AttributeSet attrs) {
51835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        return new LayoutParams(getContext(), attrs);
51935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    }
52035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
52135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    @Override
5227ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
5238c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell        if (p != null) {
5248c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell            final LayoutParams result = p instanceof LayoutParams
5258c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell                    ? new LayoutParams((LayoutParams) p)
5268c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell                    : new LayoutParams(p);
5273f476b34049d062942eafcf48396f593e00bd324Adam Powell            if (result.gravity <= Gravity.NO_GRAVITY) {
5283f476b34049d062942eafcf48396f593e00bd324Adam Powell                result.gravity = Gravity.CENTER_VERTICAL;
5293f476b34049d062942eafcf48396f593e00bd324Adam Powell            }
5303f476b34049d062942eafcf48396f593e00bd324Adam Powell            return result;
5313f476b34049d062942eafcf48396f593e00bd324Adam Powell        }
5327ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell        return generateDefaultLayoutParams();
5337ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell    }
53496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
535696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    @Override
536696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
53735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        return p != null && p instanceof LayoutParams;
538696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
539696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
540640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    public LayoutParams generateOverflowButtonLayoutParams() {
541640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        LayoutParams result = generateDefaultLayoutParams();
542640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        result.isOverflowButton = true;
543640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        return result;
544640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    }
545640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
54696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public boolean invokeItem(MenuItemImpl item) {
54796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        return mMenu.performItemAction(item, 0);
54896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
54996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
55096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public int getWindowAnimations() {
55196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        return 0;
55296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
55396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
554696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void initialize(MenuBuilder menu) {
55596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mMenu = menu;
556f6148c53f93978af678cc0559a4417b608a33ae1Adam Powell    }
557f6148c53f93978af678cc0559a4417b608a33ae1Adam Powell
558696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    @Override
559696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    protected boolean hasDividerBeforeChildAt(int childIndex) {
560825992f503439bc87d9d7e698a487f17b5acc243Jake Wharton        if (childIndex == 0) {
561825992f503439bc87d9d7e698a487f17b5acc243Jake Wharton            return false;
562825992f503439bc87d9d7e698a487f17b5acc243Jake Wharton        }
563696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final View childBefore = getChildAt(childIndex - 1);
564696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final View child = getChildAt(childIndex);
565696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        boolean result = false;
566696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) {
567696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            result |= ((ActionMenuChildView) childBefore).needsDividerAfter();
5688028dd32a4a04154050220dd0693583d5b750330Adam Powell        }
569696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (childIndex > 0 && child instanceof ActionMenuChildView) {
570696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            result |= ((ActionMenuChildView) child).needsDividerBefore();
571be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell        }
572be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell        return result;
573be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell    }
574be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell
5757bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
5767bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        return false;
5777bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    }
5787bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell
579696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public interface ActionMenuChildView {
580696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public boolean needsDividerBefore();
581696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public boolean needsDividerAfter();
5828515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell    }
583640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
584640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    public static class LayoutParams extends LinearLayout.LayoutParams {
585640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        @ViewDebug.ExportedProperty(category = "layout")
586640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        public boolean isOverflowButton;
58735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        @ViewDebug.ExportedProperty(category = "layout")
58835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        public int cellsUsed;
58935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        @ViewDebug.ExportedProperty(category = "layout")
59035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        public int extraPixels;
591160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell        @ViewDebug.ExportedProperty(category = "layout")
592160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell        public boolean expandable;
593be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell        @ViewDebug.ExportedProperty(category = "layout")
594be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell        public boolean preventEdgeOffset;
595160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell
59635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        public boolean expanded;
597640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
598640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        public LayoutParams(Context c, AttributeSet attrs) {
599640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            super(c, attrs);
600640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        }
601640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
6028c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell        public LayoutParams(ViewGroup.LayoutParams other) {
6038c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell            super(other);
6048c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell        }
6058c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell
606640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        public LayoutParams(LayoutParams other) {
607640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            super((LinearLayout.LayoutParams) other);
608640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            isOverflowButton = other.isOverflowButton;
609640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        }
610640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
611640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        public LayoutParams(int width, int height) {
612640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            super(width, height);
613640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            isOverflowButton = false;
614640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        }
615640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
616640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        public LayoutParams(int width, int height, boolean isOverflowButton) {
617640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            super(width, height);
618640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            this.isOverflowButton = isOverflowButton;
619640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        }
620640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    }
62196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell}
622