1bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/*
249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Copyright (C) 2014 The Android Open Source Project
3bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *
4bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Licensed under the Apache License, Version 2.0 (the "License");
5bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * you may not use this file except in compliance with the License.
6bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * You may obtain a copy of the License at
7bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *
8bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *      http://www.apache.org/licenses/LICENSE-2.0
9bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *
10bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Unless required by applicable law or agreed to in writing, software
11bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * distributed under the License is distributed on an "AS IS" BASIS,
12bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * See the License for the specific language governing permissions and
14bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * limitations under the License.
15bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */
1649c78900da0d43140fb602431fb93212bd7f6c70Chris Banespackage android.support.v7.widget;
17bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
188e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikasimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
198e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas
20bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.Context;
21bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.res.Configuration;
227325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banesimport android.graphics.drawable.Drawable;
237325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banesimport android.support.annotation.Nullable;
24c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo;
25f694ca99453213b7ce3c2a46e237209fcb5841cdTor Norbyeimport android.support.annotation.StyleRes;
2666698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.ActionMenuItemView;
2766698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuBuilder;
2866698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuItemImpl;
2966698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuPresenter;
3066698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuView;
31bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.util.AttributeSet;
3249c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.ContextThemeWrapper;
33bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.Gravity;
3449c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.Menu;
3549c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.MenuItem;
36bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.View;
37bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewDebug;
38bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewGroup;
39bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.accessibility.AccessibilityEvent;
40bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
41bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/**
4249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * ActionMenuView is a presentation of a series of menu options as a View. It provides
4349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * several top level options as action buttons while spilling remaining options over as
4449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * items in an overflow menu. This allows applications to present packs of actions inline with
4549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * specific or repeating content.
46bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */
4749c78900da0d43140fb602431fb93212bd7f6c70Chris Banespublic class ActionMenuView extends LinearLayoutCompat implements MenuBuilder.ItemInvoker,
4849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        MenuView {
49b34bdc0555f758dccd9307ce696c5134f5ce5042Trevor Johns
5020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    private static final String TAG = "ActionMenuView";
51bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
5220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    static final int MIN_CELL_SIZE = 56; // dips
5320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    static final int GENERATED_ITEM_PADDING = 4; // dips
5420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
5520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    private MenuBuilder mMenu;
56bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
5749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** Context against which to inflate popup menus. */
5849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private Context mPopupContext;
5949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
6049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** Theme resource against which to inflate popup menus. */
6149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private int mPopupTheme;
6249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
6320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    private boolean mReserveOverflow;
6420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    private ActionMenuPresenter mPresenter;
65c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes    private MenuPresenter.Callback mActionMenuPresenterCallback;
662c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas    MenuBuilder.Callback mMenuBuilderCallback;
6720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    private boolean mFormatItems;
6820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    private int mFormatItemsWidth;
6920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    private int mMinCellSize;
7020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    private int mGeneratedItemPadding;
7149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
722c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas    OnMenuItemClickListener mOnMenuItemClickListener;
73bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
7420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    public ActionMenuView(Context context) {
7520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        this(context, null);
76bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
77bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
7820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    public ActionMenuView(Context context, AttributeSet attrs) {
7920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        super(context, attrs);
8020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        setBaselineAligned(false);
8120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final float density = context.getResources().getDisplayMetrics().density;
8220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        mMinCellSize = (int) (MIN_CELL_SIZE * density);
8320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density);
8449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mPopupContext = context;
8549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mPopupTheme = 0;
8649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
8720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
8849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
8949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Specifies the theme to use when inflating popup menus. By default, uses
9049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * the same theme as the action menu view itself.
9149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
9249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param resId theme used to inflate popup menus
9349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @see #getPopupTheme()
9449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
95f694ca99453213b7ce3c2a46e237209fcb5841cdTor Norbye    public void setPopupTheme(@StyleRes int resId) {
9649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (mPopupTheme != resId) {
9749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mPopupTheme = resId;
9849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (resId == 0) {
997325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes                mPopupContext = getContext();
10049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            } else {
1017325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes                mPopupContext = new ContextThemeWrapper(getContext(), resId);
10249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
10349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
104bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
105bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
10649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
10749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return resource identifier of the theme used to inflate popup menus, or
10849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *         0 if menus are inflated against the action menu view theme
10949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @see #setPopupTheme(int)
11049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
11149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public int getPopupTheme() {
11249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return mPopupTheme;
113bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
114bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
11549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
11649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param presenter Menu presenter used to display popup menu
11749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @hide
11849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
1198e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
12049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public void setPresenter(ActionMenuPresenter presenter) {
12149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mPresenter = presenter;
12249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mPresenter.setMenuView(this);
12320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    }
124bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
12520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    @Override
12620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    public void onConfigurationChanged(Configuration newConfig) {
12764dbe1d454f1190b3cd8426d09b9119949a10709Kirill Grouchnikov        super.onConfigurationChanged(newConfig);
128bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
1291f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes        if (mPresenter != null) {
1301f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes            mPresenter.updateMenuView(false);
131bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
1321f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes            if (mPresenter.isOverflowMenuShowing()) {
1331f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes                mPresenter.hideOverflowMenu();
1341f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes                mPresenter.showOverflowMenu();
1351f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes            }
13620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
13720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    }
138bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
13949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
14049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mOnMenuItemClickListener = listener;
14149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
14249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
14320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    @Override
14420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
14520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // If we've been given an exact size to match, apply special formatting during layout.
14620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final boolean wasFormatted = mFormatItems;
14720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
148bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
14920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (wasFormatted != mFormatItems) {
15020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            mFormatItemsWidth = 0; // Reset this when switching modes
15120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
152bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
15320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // Special formatting can change whether items can fit as action buttons.
15420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // Kick the menu and update presenters when this changes.
15549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
15620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) {
15720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            mFormatItemsWidth = widthSize;
15820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            mMenu.onItemsChanged(true);
15920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
160bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
16149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final int childCount = getChildCount();
16249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (mFormatItems && childCount > 0) {
16320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec);
16420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        } else {
16520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            // Previous measurement at exact format may have set margins - reset them.
16620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            for (int i = 0; i < childCount; i++) {
16720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final View child = getChildAt(i);
16820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
16920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                lp.leftMargin = lp.rightMargin = 0;
17020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
17120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
17220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
17320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    }
174bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
17520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) {
17620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // We already know the width mode is EXACTLY if we're here.
17720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
17820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
17920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
180bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
18120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int widthPadding = getPaddingLeft() + getPaddingRight();
18220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int heightPadding = getPaddingTop() + getPaddingBottom();
183bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
18449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final int itemHeightSpec = getChildMeasureSpec(heightMeasureSpec, heightPadding,
18549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                ViewGroup.LayoutParams.WRAP_CONTENT);
186bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
18720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        widthSize -= widthPadding;
188bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
18920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // Divide the view into cells.
19020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int cellCount = widthSize / mMinCellSize;
19120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int cellSizeRemaining = widthSize % mMinCellSize;
192bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
19320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (cellCount == 0) {
19420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            // Give up, nothing fits.
19520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            setMeasuredDimension(widthSize, 0);
19620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            return;
19720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
198bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
19920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int cellSize = mMinCellSize + cellSizeRemaining / cellCount;
20020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
20120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int cellsRemaining = cellCount;
20220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int maxChildHeight = 0;
20320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int maxCellsUsed = 0;
20420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int expandableItemCount = 0;
20520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int visibleItemCount = 0;
20620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        boolean hasOverflow = false;
20720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
20820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // This is used as a bitfield to locate the smallest items present. Assumes childCount < 64.
20920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        long smallestItemsAt = 0;
21020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
21120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int childCount = getChildCount();
21220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        for (int i = 0; i < childCount; i++) {
21320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final View child = getChildAt(i);
21449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (child.getVisibility() == GONE) continue;
21520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
21620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final boolean isGeneratedItem = child instanceof ActionMenuItemView;
21720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            visibleItemCount++;
21820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
21920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            if (isGeneratedItem) {
22020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                // Reset padding for generated menu item views; it may change below
22120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                // and views are recycled.
22220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0);
22320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
22420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
22520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
22620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            lp.expanded = false;
22720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            lp.extraPixels = 0;
22820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            lp.cellsUsed = 0;
22920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            lp.expandable = false;
23020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            lp.leftMargin = 0;
23120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            lp.rightMargin = 0;
23220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText();
23320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
23420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            // Overflow always gets 1 cell. No more, no less.
23520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining;
23620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
23720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable,
23820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    itemHeightSpec, heightPadding);
23920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
24020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            maxCellsUsed = Math.max(maxCellsUsed, cellsUsed);
24149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (lp.expandable) expandableItemCount++;
24249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (lp.isOverflowButton) hasOverflow = true;
24320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
24420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            cellsRemaining -= cellsUsed;
24520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
24649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (cellsUsed == 1) smallestItemsAt |= (1 << i);
247bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        }
248bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
24920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // When we have overflow and a single expanded (text) item, we want to try centering it
25020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // visually in the available space even though overflow consumes some of it.
25120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2;
25220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
25320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // Divide space for remaining cells if we have items that can expand.
25420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // Try distributing whole leftover cells to smaller items first.
25520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
25620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        boolean needsExpansion = false;
25720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        while (expandableItemCount > 0 && cellsRemaining > 0) {
25820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            int minCells = Integer.MAX_VALUE;
25920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            long minCellsAt = 0; // Bit locations are indices of relevant child views
26020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            int minCellsItemCount = 0;
26120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            for (int i = 0; i < childCount; i++) {
26220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final View child = getChildAt(i);
26320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
26420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
26520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                // Don't try to expand items that shouldn't.
26649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (!lp.expandable) continue;
26720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
26820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                // Mark indices of children that can receive an extra cell.
26920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                if (lp.cellsUsed < minCells) {
27020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    minCells = lp.cellsUsed;
27120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    minCellsAt = 1 << i;
27220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    minCellsItemCount = 1;
27320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                } else if (lp.cellsUsed == minCells) {
27420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    minCellsAt |= 1 << i;
27520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    minCellsItemCount++;
27620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                }
27720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
27820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
27920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            // Items that get expanded will always be in the set of smallest items when we're done.
28020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            smallestItemsAt |= minCellsAt;
28120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
28249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop.
28320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
28420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            // We have enough cells, all minimum size items will be incremented.
28520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            minCells++;
28620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
28720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            for (int i = 0; i < childCount; i++) {
28820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final View child = getChildAt(i);
28920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
29020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                if ((minCellsAt & (1 << i)) == 0) {
29120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    // If this item is already at our small item count, mark it for later.
29249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i;
29320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    continue;
29420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                }
29520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
29620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) {
29720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    // Add padding to this item such that it centers.
29820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0);
29920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                }
30020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                lp.cellsUsed++;
30120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                lp.expanded = true;
30220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                cellsRemaining--;
30320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
30420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
30520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            needsExpansion = true;
306bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        }
307bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
30820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // Divide any space left that wouldn't divide along cell boundaries
30920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // evenly among the smallest items
31020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
31120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final boolean singleItem = !hasOverflow && visibleItemCount == 1;
31220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (cellsRemaining > 0 && smallestItemsAt != 0 &&
31320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                (cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) {
31420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            float expandCount = Long.bitCount(smallestItemsAt);
31520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
31620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            if (!singleItem) {
31720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                // The items at the far edges may only expand by half in order to pin to either side.
31820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                if ((smallestItemsAt & 1) != 0) {
31920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams();
32049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    if (!lp.preventEdgeOffset) expandCount -= 0.5f;
32120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                }
32220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                if ((smallestItemsAt & (1 << (childCount - 1))) != 0) {
32320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams());
32449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    if (!lp.preventEdgeOffset) expandCount -= 0.5f;
32520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                }
32620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
32720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
32820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final int extraPixels = expandCount > 0 ?
32920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    (int) (cellsRemaining * cellSize / expandCount) : 0;
33020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
33120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            for (int i = 0; i < childCount; i++) {
33249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if ((smallestItemsAt & (1 << i)) == 0) continue;
33320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
33420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final View child = getChildAt(i);
33520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
33620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                if (child instanceof ActionMenuItemView) {
33720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    // If this is one of our views, expand and measure at the larger size.
33820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    lp.extraPixels = extraPixels;
33920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    lp.expanded = true;
34020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    if (i == 0 && !lp.preventEdgeOffset) {
34120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                        // First item gets part of its new padding pushed out of sight.
34220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                        // The last item will get this implicitly from layout.
34320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                        lp.leftMargin = -extraPixels / 2;
34420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    }
34520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    needsExpansion = true;
34620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                } else if (lp.isOverflowButton) {
34720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    lp.extraPixels = extraPixels;
34820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    lp.expanded = true;
34920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    lp.rightMargin = -extraPixels / 2;
35020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    needsExpansion = true;
35120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                } else {
35220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    // If we don't know what it is, give it some margins instead
35320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    // and let it center within its space. We still want to pin
35420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    // against the edges.
35520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    if (i != 0) {
35620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                        lp.leftMargin = extraPixels / 2;
35720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    }
35820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    if (i != childCount - 1) {
35920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                        lp.rightMargin = extraPixels / 2;
36020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    }
36120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                }
36220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
36320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
36420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            cellsRemaining = 0;
36520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
366bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
36720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        // Remeasure any items that have had extra space allocated to them.
36820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (needsExpansion) {
36920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            for (int i = 0; i < childCount; i++) {
37020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final View child = getChildAt(i);
37120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
372bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
37349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (!lp.expanded) continue;
374bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
37520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final int width = lp.cellsUsed * cellSize + lp.extraPixels;
37620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
37720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                        itemHeightSpec);
37820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
379bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        }
380bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
38120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (heightMode != MeasureSpec.EXACTLY) {
38220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            heightSize = maxChildHeight;
383bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        }
384bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
38520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        setMeasuredDimension(widthSize, heightSize);
386bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
387bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
38820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    /**
38949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Measure a child view to fit within cell-based formatting. The child's width
39049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * will be measured to a whole multiple of cellSize.
39120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns     *
39220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns     * <p>Sets the expandable and cellsUsed fields of LayoutParams.
39320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns     *
39449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param child Child to measure
39549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param cellSize Size of one cell
39649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param cellsRemaining Number of cells remaining that this view can expand to fill
39720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns     * @param parentHeightMeasureSpec MeasureSpec used by the parent view
39849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param parentHeightPadding Padding present in the parent view
39920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns     * @return Number of cells this child was measured to occupy
40020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns     */
40120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    static int measureChildForCells(View child, int cellSize, int cellsRemaining,
40220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            int parentHeightMeasureSpec, int parentHeightPadding) {
403bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
404bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
40520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) -
40620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                parentHeightPadding;
40720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec);
40820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode);
40920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
41020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
41120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                (ActionMenuItemView) child : null;
41220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final boolean hasText = itemView != null && itemView.hasText();
41320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
41420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int cellsUsed = 0;
41520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (cellsRemaining > 0 && (!hasText || cellsRemaining >= 2)) {
41620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final int childWidthSpec = MeasureSpec.makeMeasureSpec(
41720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    cellSize * cellsRemaining, MeasureSpec.AT_MOST);
41820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            child.measure(childWidthSpec, childHeightSpec);
41920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
42020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final int measuredWidth = child.getMeasuredWidth();
42120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            cellsUsed = measuredWidth / cellSize;
42249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (measuredWidth % cellSize != 0) cellsUsed++;
42349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (hasText && cellsUsed < 2) cellsUsed = 2;
42420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
425bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
42620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final boolean expandable = !lp.isOverflowButton && hasText;
42720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        lp.expandable = expandable;
428bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
42920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        lp.cellsUsed = cellsUsed;
43020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int targetWidth = cellsUsed * cellSize;
43120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
43220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                childHeightSpec);
43320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        return cellsUsed;
434bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
435bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
43620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    @Override
43720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
43820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (!mFormatItems) {
43920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            super.onLayout(changed, left, top, right, bottom);
44020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            return;
44120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
442bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
44320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int childCount = getChildCount();
4442f4abc2b347f34ba070a2a5e87cf16ee2c373192Chris Banes        final int midVertical = (bottom - top) / 2;
44549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final int dividerWidth = getDividerWidth();
44620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int overflowWidth = 0;
44720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int nonOverflowWidth = 0;
44820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int nonOverflowCount = 0;
44920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
45020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        boolean hasOverflow = false;
451a2c72b87007d10202c25e78e904938f770c6337dChris Banes        final boolean isLayoutRtl = ViewUtils.isLayoutRtl(this);
45220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        for (int i = 0; i < childCount; i++) {
45320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final View v = getChildAt(i);
45420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            if (v.getVisibility() == GONE) {
45520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                continue;
45620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
45720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
45820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            LayoutParams p = (LayoutParams) v.getLayoutParams();
45920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            if (p.isOverflowButton) {
46020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                overflowWidth = v.getMeasuredWidth();
4611582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes                if (hasSupportDividerBeforeChildAt(i)) {
4621582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes                    overflowWidth += dividerWidth;
4631582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes                }
46420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                int height = v.getMeasuredHeight();
465a2c72b87007d10202c25e78e904938f770c6337dChris Banes                int r;
466a2c72b87007d10202c25e78e904938f770c6337dChris Banes                int l;
467a2c72b87007d10202c25e78e904938f770c6337dChris Banes                if (isLayoutRtl) {
468a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    l = getPaddingLeft() + p.leftMargin;
469a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    r = l + overflowWidth;
470a2c72b87007d10202c25e78e904938f770c6337dChris Banes                } else {
471a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    r = getWidth() - getPaddingRight() - p.rightMargin;
472a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    l = r - overflowWidth;
473a2c72b87007d10202c25e78e904938f770c6337dChris Banes                }
47420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                int t = midVertical - (height / 2);
47520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                int b = t + height;
47620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                v.layout(l, t, r, b);
47720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
47820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                widthRemaining -= overflowWidth;
47920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                hasOverflow = true;
48020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            } else {
48120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
48220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                nonOverflowWidth += size;
48320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                widthRemaining -= size;
4841582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes                if (hasSupportDividerBeforeChildAt(i)) {
4851582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes                    nonOverflowWidth += dividerWidth;
4861582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes                }
48720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                nonOverflowCount++;
48820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
48920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
49020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
49120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (childCount == 1 && !hasOverflow) {
49220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            // Center a single child
49320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final View v = getChildAt(0);
49420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final int width = v.getMeasuredWidth();
49520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final int height = v.getMeasuredHeight();
49620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final int midHorizontal = (right - left) / 2;
49720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final int l = midHorizontal - width / 2;
49820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            final int t = midVertical - height / 2;
49920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            v.layout(l, t, l + width, t + height);
50020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            return;
50120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
50220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
50320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1);
50420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0);
50520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
506a2c72b87007d10202c25e78e904938f770c6337dChris Banes        if (isLayoutRtl) {
507a2c72b87007d10202c25e78e904938f770c6337dChris Banes            int startRight = getWidth() - getPaddingRight();
508a2c72b87007d10202c25e78e904938f770c6337dChris Banes            for (int i = 0; i < childCount; i++) {
509a2c72b87007d10202c25e78e904938f770c6337dChris Banes                final View v = getChildAt(i);
510a2c72b87007d10202c25e78e904938f770c6337dChris Banes                final LayoutParams lp = (LayoutParams) v.getLayoutParams();
511a2c72b87007d10202c25e78e904938f770c6337dChris Banes                if (v.getVisibility() == GONE || lp.isOverflowButton) {
512a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    continue;
513a2c72b87007d10202c25e78e904938f770c6337dChris Banes                }
514a2c72b87007d10202c25e78e904938f770c6337dChris Banes
515a2c72b87007d10202c25e78e904938f770c6337dChris Banes                startRight -= lp.rightMargin;
516a2c72b87007d10202c25e78e904938f770c6337dChris Banes                int width = v.getMeasuredWidth();
517a2c72b87007d10202c25e78e904938f770c6337dChris Banes                int height = v.getMeasuredHeight();
518a2c72b87007d10202c25e78e904938f770c6337dChris Banes                int t = midVertical - height / 2;
519a2c72b87007d10202c25e78e904938f770c6337dChris Banes                v.layout(startRight - width, t, startRight, t + height);
520a2c72b87007d10202c25e78e904938f770c6337dChris Banes                startRight -= width + lp.leftMargin + spacerSize;
52120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
522a2c72b87007d10202c25e78e904938f770c6337dChris Banes        } else {
523a2c72b87007d10202c25e78e904938f770c6337dChris Banes            int startLeft = getPaddingLeft();
524a2c72b87007d10202c25e78e904938f770c6337dChris Banes            for (int i = 0; i < childCount; i++) {
525a2c72b87007d10202c25e78e904938f770c6337dChris Banes                final View v = getChildAt(i);
526a2c72b87007d10202c25e78e904938f770c6337dChris Banes                final LayoutParams lp = (LayoutParams) v.getLayoutParams();
527a2c72b87007d10202c25e78e904938f770c6337dChris Banes                if (v.getVisibility() == GONE || lp.isOverflowButton) {
528a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    continue;
529a2c72b87007d10202c25e78e904938f770c6337dChris Banes                }
53020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
531a2c72b87007d10202c25e78e904938f770c6337dChris Banes                startLeft += lp.leftMargin;
532a2c72b87007d10202c25e78e904938f770c6337dChris Banes                int width = v.getMeasuredWidth();
533a2c72b87007d10202c25e78e904938f770c6337dChris Banes                int height = v.getMeasuredHeight();
534a2c72b87007d10202c25e78e904938f770c6337dChris Banes                int t = midVertical - height / 2;
535a2c72b87007d10202c25e78e904938f770c6337dChris Banes                v.layout(startLeft, t, startLeft + width, t + height);
536a2c72b87007d10202c25e78e904938f770c6337dChris Banes                startLeft += width + lp.rightMargin + spacerSize;
537a2c72b87007d10202c25e78e904938f770c6337dChris Banes            }
53820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
53920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    }
54020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
54120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    @Override
54220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    public void onDetachedFromWindow() {
54320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        super.onDetachedFromWindow();
54449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        dismissPopupMenus();
54520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    }
54620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
547c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes    /**
5487325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes     * Set the icon to use for the overflow button.
549c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes     *
5507325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes     * @param icon Drawable to set, may be null to clear the icon
551c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes     */
5527325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes    public void setOverflowIcon(@Nullable Drawable icon) {
5537325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes        getMenu();
5547325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes        mPresenter.setOverflowIcon(icon);
555c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes    }
556c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes
557c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes    /**
5587325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes     * Return the current drawable used as the overflow icon.
559c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes     *
5607325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes     * @return The overflow icon drawable
561c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes     */
5627325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes    @Nullable
5637325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes    public Drawable getOverflowIcon() {
5647325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes        getMenu();
5657325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes        return mPresenter.getOverflowIcon();
5667325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes    }
5677325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes
5687325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes    /** @hide */
5698e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
5707325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes    public boolean isOverflowReserved() {
5717325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes        return mReserveOverflow;
5727325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes    }
5737325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes
5747325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes    /** @hide */
5758e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
5767325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes    public void setOverflowReserved(boolean reserveOverflow) {
5777325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes        mReserveOverflow = reserveOverflow;
578c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes    }
579c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes
58020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    @Override
58120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    protected LayoutParams generateDefaultLayoutParams() {
58220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
58320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                LayoutParams.WRAP_CONTENT);
58420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        params.gravity = Gravity.CENTER_VERTICAL;
58520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        return params;
586bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
587bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
58820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    @Override
58920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    public LayoutParams generateLayoutParams(AttributeSet attrs) {
59020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        return new LayoutParams(getContext(), attrs);
591bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
592bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
59320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    @Override
59420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
59549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (p != null) {
59649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final LayoutParams result = p instanceof LayoutParams
59749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    ? new LayoutParams((LayoutParams) p)
59849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    : new LayoutParams(p);
59920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            if (result.gravity <= Gravity.NO_GRAVITY) {
60020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                result.gravity = Gravity.CENTER_VERTICAL;
60120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            }
60220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            return result;
60320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
60420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        return generateDefaultLayoutParams();
605bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
60620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
60720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    @Override
60820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
60920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        return p != null && p instanceof LayoutParams;
610bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
61120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
61249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** @hide */
6138e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
61420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    public LayoutParams generateOverflowButtonLayoutParams() {
61520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        LayoutParams result = generateDefaultLayoutParams();
61620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        result.isOverflowButton = true;
61720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        return result;
618bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
61920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
62049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** @hide */
621e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas    @Override
6228e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
62320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    public boolean invokeItem(MenuItemImpl item) {
62420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        return mMenu.performItemAction(item, 0);
625bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
62620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
62749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** @hide */
628e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas    @Override
6298e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
63020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    public int getWindowAnimations() {
63120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        return 0;
63220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    }
63320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
63449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** @hide */
635e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas    @Override
6368e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
63720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    public void initialize(MenuBuilder menu) {
63820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        mMenu = menu;
63920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    }
64020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
64149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
64249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Returns the Menu object that this ActionMenuView is currently presenting.
64349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
64449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * <p>Applications should use this method to obtain the ActionMenuView's Menu object
64549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * and inflate or add content to it as necessary.</p>
64649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
64749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return the Menu presented by this view
64849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
64949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public Menu getMenu() {
65049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (mMenu == null) {
65149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final Context context = getContext();
65249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mMenu = new MenuBuilder(context);
65349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mMenu.setCallback(new MenuBuilderCallback());
65449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mPresenter = new ActionMenuPresenter(context);
655ae5248b8902c62325fafbdac3fe18783aec06073Chris Banes            mPresenter.setReserveOverflow(true);
656c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes            mPresenter.setCallback(mActionMenuPresenterCallback != null
657c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes                    ? mActionMenuPresenterCallback : new ActionMenuPresenterCallback());
65849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mMenu.addMenuPresenter(mPresenter, mPopupContext);
65949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mPresenter.setMenuView(this);
66049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
66149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
66249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return mMenu;
66349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
66449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
66549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
666c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes     * Must be called before the first call to getMenu()
667c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes     * @hide
668c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes     */
6698e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
670c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes    public void setMenuCallbacks(MenuPresenter.Callback pcb, MenuBuilder.Callback mcb) {
671c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes        mActionMenuPresenterCallback = pcb;
672c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes        mMenuBuilderCallback = mcb;
673c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes    }
674c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes
675c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes    /**
67649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Returns the current menu or null if one has not yet been configured.
67749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @hide Internal use only for action bar integration
67849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
6798e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
68049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public MenuBuilder peekMenu() {
68149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return mMenu;
68249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
68349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
68449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
68549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Show the overflow items from the associated menu.
68649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
68749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return true if the menu was able to be shown, false otherwise
68849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
68949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public boolean showOverflowMenu() {
69049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return mPresenter != null && mPresenter.showOverflowMenu();
69149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
69249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
69349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
69449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Hide the overflow items from the associated menu.
69549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
69649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return true if the menu was able to be hidden, false otherwise
69749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
69849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public boolean hideOverflowMenu() {
69949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return mPresenter != null && mPresenter.hideOverflowMenu();
70049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
70149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
70249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
70349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Check whether the overflow menu is currently showing. This may not reflect
70449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * a pending show operation in progress.
70549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
70649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return true if the overflow menu is currently showing
70749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
70849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public boolean isOverflowMenuShowing() {
70949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return mPresenter != null && mPresenter.isOverflowMenuShowing();
71049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
71149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
71249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** @hide */
7138e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
71449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public boolean isOverflowMenuShowPending() {
71549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return mPresenter != null && mPresenter.isOverflowMenuShowPending();
71649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
71749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
71849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
71949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Dismiss any popups associated with this menu view.
72049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
72149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public void dismissPopupMenus() {
72249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (mPresenter != null) {
72349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mPresenter.dismissPopupMenus();
72449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
72549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
72649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
727a2c72b87007d10202c25e78e904938f770c6337dChris Banes    /**
728a2c72b87007d10202c25e78e904938f770c6337dChris Banes     * @hide Private LinearLayout (superclass) API. Un-hide if LinearLayout API is made public.
729a2c72b87007d10202c25e78e904938f770c6337dChris Banes     */
7308e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
7311582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes    protected boolean hasSupportDividerBeforeChildAt(int childIndex) {
73249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (childIndex == 0) {
73349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return false;
73449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
73520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final View childBefore = getChildAt(childIndex - 1);
73620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        final View child = getChildAt(childIndex);
73720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        boolean result = false;
73820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) {
73920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            result |= ((ActionMenuChildView) childBefore).needsDividerAfter();
74020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
74120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (childIndex > 0 && child instanceof ActionMenuChildView) {
74220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            result |= ((ActionMenuChildView) child).needsDividerBefore();
74320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
74420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        return result;
745bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
746bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
747e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas    @Override
74820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
74920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        return false;
750bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
751bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
75249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** @hide */
7538e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
75449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public void setExpandedActionViewsExclusive(boolean exclusive) {
75549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mPresenter.setExpandedActionViewsExclusive(exclusive);
75649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
75720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
75849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
75949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Interface responsible for receiving menu item click events if the items themselves
76049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * do not have individual item click listeners.
76149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
76249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public interface OnMenuItemClickListener {
76349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /**
76449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * This method will be invoked when a menu item is clicked if the item itself did
76549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * not already handle the event.
76649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         *
76749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @param item {@link MenuItem} that was clicked
76849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
76949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         */
77049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public boolean onMenuItemClick(MenuItem item);
77149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
77220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
77349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private class MenuBuilderCallback implements MenuBuilder.Callback {
7742c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas        MenuBuilderCallback() {
7752c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas        }
7762c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas
77749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
77849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
77949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return mOnMenuItemClickListener != null &&
78049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    mOnMenuItemClickListener.onMenuItemClick(item);
78149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
78249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
78349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
78449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public void onMenuModeChange(MenuBuilder menu) {
785c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes            if (mMenuBuilderCallback != null) {
786c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes                mMenuBuilderCallback.onMenuModeChange(menu);
787c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes            }
78849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
78949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
79049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
791ad1b0e82100ee31e70040d77bfa4d847b2bf0864Aurimas Liutikas    private static class ActionMenuPresenterCallback implements ActionMenuPresenter.Callback {
7922c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas        ActionMenuPresenterCallback() {
7932c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas        }
7942c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas
79549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
79649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
79749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
79849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
79949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
80049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public boolean onOpenSubMenu(MenuBuilder subMenu) {
80149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return false;
80249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
80349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
80449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
80549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** @hide */
8068e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
80749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public interface ActionMenuChildView {
808c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette        boolean needsDividerBefore();
809c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette        boolean needsDividerAfter();
810bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
811bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
81249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public static class LayoutParams extends LinearLayoutCompat.LayoutParams {
81320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
81420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        @ViewDebug.ExportedProperty()
81520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        public boolean isOverflowButton;
81620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
81720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        @ViewDebug.ExportedProperty()
81820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        public int cellsUsed;
81920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
82020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        @ViewDebug.ExportedProperty()
82120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        public int extraPixels;
82220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
82320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        @ViewDebug.ExportedProperty()
82420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        public boolean expandable;
82520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
82620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        @ViewDebug.ExportedProperty()
82720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        public boolean preventEdgeOffset;
82820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
82949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        boolean expanded;
83020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
83120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        public LayoutParams(Context c, AttributeSet attrs) {
83220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            super(c, attrs);
83320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
83420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
83549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public LayoutParams(ViewGroup.LayoutParams other) {
83649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            super(other);
83749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
83849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
83920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        public LayoutParams(LayoutParams other) {
84049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            super((ViewGroup.LayoutParams) other);
84120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            isOverflowButton = other.isOverflowButton;
84220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
84320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
84420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        public LayoutParams(int width, int height) {
84520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            super(width, height);
84620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            isOverflowButton = false;
84720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
84820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
84949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        LayoutParams(int width, int height, boolean isOverflowButton) {
85020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            super(width, height);
85120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            this.isOverflowButton = isOverflowButton;
85220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
853bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
854bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell}
855