ActionMenuPresenter.java revision a647640f85f415bd8fb8cb925e7687658fe9ae37
1696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell/*
2696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * Copyright (C) 2011 The Android Open Source Project
3696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell *
4696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * Licensed under the Apache License, Version 2.0 (the "License");
5696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * you may not use this file except in compliance with the License.
6696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * You may obtain a copy of the License at
7696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell *
8696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell *      http://www.apache.org/licenses/LICENSE-2.0
9696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell *
10696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * Unless required by applicable law or agreed to in writing, software
11696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * distributed under the License is distributed on an "AS IS" BASIS,
12696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * See the License for the specific language governing permissions and
14696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * limitations under the License.
15696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell */
16696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
17696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellpackage com.android.internal.view.menu;
18696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
19696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport com.android.internal.view.menu.ActionMenuView.ActionMenuChildView;
20696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
21696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.content.Context;
22bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powellimport android.content.res.Configuration;
23696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.content.res.Resources;
2411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powellimport android.os.Parcel;
2511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powellimport android.os.Parcelable;
26696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.util.SparseBooleanArray;
27823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powellimport android.view.ActionProvider;
28696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.view.MenuItem;
29696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.view.SoundEffectConstants;
30696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.view.View;
31696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.view.View.MeasureSpec;
328c4706252228755ed181d19532b7e0cfec270ba4Adam Powellimport android.view.ViewConfiguration;
33696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.view.ViewGroup;
34696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.widget.ImageButton;
35696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
36696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport java.util.ArrayList;
37696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
38696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell/**
39696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * MenuPresenter for building action menus as seen in the action bar and action modes.
40696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell */
41823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powellpublic class ActionMenuPresenter extends BaseMenuPresenter
42823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell        implements ActionProvider.SubUiVisibilityListener {
43640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    private static final String TAG = "ActionMenuPresenter";
44640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell
45696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private View mOverflowButton;
46696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private boolean mReserveOverflow;
471ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell    private boolean mReserveOverflowSet;
48696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private int mWidthLimit;
49696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private int mActionItemWidthLimit;
50696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private int mMaxItems;
511ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell    private boolean mMaxItemsSet;
52640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    private boolean mStrictWidthLimit;
531ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell    private boolean mWidthLimitSet;
54b187cd9c54f0100c0fb47c354cdecad29ca7c0aeAdam Powell    private boolean mExpandedActionViewsExclusive;
55696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
5635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    private int mMinCellSize;
5735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
58696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    // Group IDs that have been added as actions - used temporarily, allocated here for reuse.
59696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
60696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
61696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private View mScrapActionButtonView;
62696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
63696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private OverflowPopup mOverflowPopup;
64696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private ActionButtonSubmenu mActionButtonPopup;
65696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
66696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private OpenOverflowRunnable mPostedOpenRunnable;
67696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
6811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
6911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    int mOpenSubMenuId;
7011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
71538e565c06e915b91e7e3a901f872ccdd9bccdd3Adam Powell    public ActionMenuPresenter(Context context) {
72538e565c06e915b91e7e3a901f872ccdd9bccdd3Adam Powell        super(context, com.android.internal.R.layout.action_menu_layout,
73696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                com.android.internal.R.layout.action_menu_item_layout);
74696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
75696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
76696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    @Override
77696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void initForMenu(Context context, MenuBuilder menu) {
78696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        super.initForMenu(context, menu);
79696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
80696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final Resources res = context.getResources();
811ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell
821ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        if (!mReserveOverflowSet) {
838c4706252228755ed181d19532b7e0cfec270ba4Adam Powell            mReserveOverflow = !ViewConfiguration.get(context).hasPermanentMenuKey();
841ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        }
851ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell
861ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        if (!mWidthLimitSet) {
871ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell            mWidthLimit = res.getDisplayMetrics().widthPixels / 2;
881ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        }
89696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
90696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        // Measure for initial configuration
911ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        if (!mMaxItemsSet) {
921ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell            mMaxItems = res.getInteger(com.android.internal.R.integer.max_action_buttons);
931ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        }
94696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
95696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        int width = mWidthLimit;
96696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mReserveOverflow) {
979b4bee0f14bbd137b0797127aff2df46a6321ec5Adam Powell            if (mOverflowButton == null) {
98538e565c06e915b91e7e3a901f872ccdd9bccdd3Adam Powell                mOverflowButton = new OverflowMenuButton(mSystemContext);
999b4bee0f14bbd137b0797127aff2df46a6321ec5Adam Powell                final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
1009b4bee0f14bbd137b0797127aff2df46a6321ec5Adam Powell                mOverflowButton.measure(spec, spec);
1019b4bee0f14bbd137b0797127aff2df46a6321ec5Adam Powell            }
102696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            width -= mOverflowButton.getMeasuredWidth();
103696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        } else {
104696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mOverflowButton = null;
105696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
106696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
107696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mActionItemWidthLimit = width;
108696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
10935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density);
11035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
111696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        // Drop a scrap view as it may no longer reflect the proper context/config.
112696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mScrapActionButtonView = null;
113696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
114696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
115bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powell    public void onConfigurationChanged(Configuration newConfig) {
116bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powell        if (!mMaxItemsSet) {
117bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powell            mMaxItems = mContext.getResources().getInteger(
118bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powell                    com.android.internal.R.integer.max_action_buttons);
119bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powell            if (mMenu != null) {
120bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powell                mMenu.onItemsChanged(true);
121bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powell            }
122bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powell        }
123bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powell    }
124bfcdfaf919cdb67897a6e24afc8f14b2c810596aAdam Powell
125640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    public void setWidthLimit(int width, boolean strict) {
1261ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        mWidthLimit = width;
127640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        mStrictWidthLimit = strict;
1281ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        mWidthLimitSet = true;
1291ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell    }
1301ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell
1311ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell    public void setReserveOverflow(boolean reserveOverflow) {
1321ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        mReserveOverflow = reserveOverflow;
1331ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        mReserveOverflowSet = true;
1349b4bee0f14bbd137b0797127aff2df46a6321ec5Adam Powell    }
1359b4bee0f14bbd137b0797127aff2df46a6321ec5Adam Powell
1369b4bee0f14bbd137b0797127aff2df46a6321ec5Adam Powell    public void setItemLimit(int itemCount) {
1379b4bee0f14bbd137b0797127aff2df46a6321ec5Adam Powell        mMaxItems = itemCount;
1381ab418a222e1834c4b1312fde355e41a1947af0dAdam Powell        mMaxItemsSet = true;
1399b4bee0f14bbd137b0797127aff2df46a6321ec5Adam Powell    }
1409b4bee0f14bbd137b0797127aff2df46a6321ec5Adam Powell
141b187cd9c54f0100c0fb47c354cdecad29ca7c0aeAdam Powell    public void setExpandedActionViewsExclusive(boolean isExclusive) {
142b187cd9c54f0100c0fb47c354cdecad29ca7c0aeAdam Powell        mExpandedActionViewsExclusive = isExclusive;
143b187cd9c54f0100c0fb47c354cdecad29ca7c0aeAdam Powell    }
144b187cd9c54f0100c0fb47c354cdecad29ca7c0aeAdam Powell
145696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    @Override
146696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public MenuView getMenuView(ViewGroup root) {
147696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        MenuView result = super.getMenuView(root);
148696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        ((ActionMenuView) result).setPresenter(this);
149696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return result;
150696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
151696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
152696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    @Override
153696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
1548d02deabac62c4a68a335a7b3141795466362b89Adam Powell        View actionView = item.getActionView();
15535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        if (actionView == null || item.hasCollapsibleActionView()) {
15635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            if (!(convertView instanceof ActionMenuItemView)) {
15735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                convertView = null;
15835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            }
15935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            actionView = super.getItemView(item, convertView, parent);
16035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
1618d02deabac62c4a68a335a7b3141795466362b89Adam Powell        actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
16235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
16335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final ActionMenuView menuParent = (ActionMenuView) parent;
16435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final ViewGroup.LayoutParams lp = actionView.getLayoutParams();
16535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        if (!menuParent.checkLayoutParams(lp)) {
16635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            actionView.setLayoutParams(menuParent.generateLayoutParams(lp));
16735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
1688d02deabac62c4a68a335a7b3141795466362b89Adam Powell        return actionView;
169696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
170696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
171696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    @Override
172696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) {
173696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        itemView.initialize(item, 0);
17435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
17535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final ActionMenuView menuView = (ActionMenuView) mMenuView;
17635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        ActionMenuItemView actionItemView = (ActionMenuItemView) itemView;
17735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        actionItemView.setItemInvoker(menuView);
178696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
179696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
180696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    @Override
181696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
182696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return item.isActionButton();
183696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
184696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
185696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    @Override
186696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void updateMenuView(boolean cleared) {
187696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        super.updateMenuView(cleared);
188696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
189823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell        if (mMenu != null) {
190823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell            final ArrayList<MenuItemImpl> actionItems = mMenu.getActionItems();
191823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell            final int count = actionItems.size();
192823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell            for (int i = 0; i < count; i++) {
193823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell                final ActionProvider provider = actionItems.get(i).getActionProvider();
194823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell                if (provider != null) {
195823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell                    provider.setSubUiVisibilityListener(this);
196823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell                }
197823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell            }
198823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell        }
199823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell
200275702c2f47ed87ab642462530092d9777f32ecdAdam Powell        final ArrayList<MenuItemImpl> nonActionItems = mMenu != null ?
201275702c2f47ed87ab642462530092d9777f32ecdAdam Powell                mMenu.getNonActionItems() : null;
202275702c2f47ed87ab642462530092d9777f32ecdAdam Powell
203275702c2f47ed87ab642462530092d9777f32ecdAdam Powell        boolean hasOverflow = false;
204275702c2f47ed87ab642462530092d9777f32ecdAdam Powell        if (mReserveOverflow && nonActionItems != null) {
205275702c2f47ed87ab642462530092d9777f32ecdAdam Powell            final int count = nonActionItems.size();
206275702c2f47ed87ab642462530092d9777f32ecdAdam Powell            if (count == 1) {
207275702c2f47ed87ab642462530092d9777f32ecdAdam Powell                hasOverflow = !nonActionItems.get(0).isActionViewExpanded();
208275702c2f47ed87ab642462530092d9777f32ecdAdam Powell            } else {
209275702c2f47ed87ab642462530092d9777f32ecdAdam Powell                hasOverflow = count > 0;
210275702c2f47ed87ab642462530092d9777f32ecdAdam Powell            }
211275702c2f47ed87ab642462530092d9777f32ecdAdam Powell        }
212275702c2f47ed87ab642462530092d9777f32ecdAdam Powell
21314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        if (hasOverflow) {
214696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (mOverflowButton == null) {
215538e565c06e915b91e7e3a901f872ccdd9bccdd3Adam Powell                mOverflowButton = new OverflowMenuButton(mSystemContext);
216696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
217696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
218696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (parent != mMenuView) {
219696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                if (parent != null) {
220696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    parent.removeView(mOverflowButton);
221696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                }
22235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                ActionMenuView menuView = (ActionMenuView) mMenuView;
22335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                menuView.addView(mOverflowButton, menuView.generateOverflowButtonLayoutParams());
224696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
225696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        } else if (mOverflowButton != null && mOverflowButton.getParent() == mMenuView) {
226696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            ((ViewGroup) mMenuView).removeView(mOverflowButton);
227696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
22814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell
22914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell        ((ActionMenuView) mMenuView).setOverflowReserved(mReserveOverflow);
230696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
231696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
232696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    @Override
233696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean filterLeftoverView(ViewGroup parent, int childIndex) {
234696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (parent.getChildAt(childIndex) == mOverflowButton) return false;
235696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return super.filterLeftoverView(parent, childIndex);
236696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
237696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
238696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
239696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (!subMenu.hasVisibleItems()) return false;
240696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
241696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        SubMenuBuilder topSubMenu = subMenu;
242696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        while (topSubMenu.getParentMenu() != mMenu) {
243696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu();
244696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
245696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        View anchor = findViewForItem(topSubMenu.getItem());
24611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        if (anchor == null) {
24711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            if (mOverflowButton == null) return false;
24811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            anchor = mOverflowButton;
24911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
250696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
25111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        mOpenSubMenuId = subMenu.getItem().getItemId();
252696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu);
253696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mActionButtonPopup.setAnchorView(anchor);
254696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mActionButtonPopup.show();
255696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        super.onSubMenuSelected(subMenu);
256696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return true;
257696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
258696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
259696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private View findViewForItem(MenuItem item) {
260696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final ViewGroup parent = (ViewGroup) mMenuView;
261696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (parent == null) return null;
262696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
263696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final int count = parent.getChildCount();
264696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (int i = 0; i < count; i++) {
265696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final View child = parent.getChildAt(i);
266696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (child instanceof MenuView.ItemView &&
267696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    ((MenuView.ItemView) child).getItemData() == item) {
268696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                return child;
269696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
270696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
271696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return null;
272696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
273696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
274696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
275696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Display the overflow menu if one is present.
276696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @return true if the overflow menu was shown, false otherwise.
277696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
278696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean showOverflowMenu() {
27970e9f4bd2c044858f3c1c040ffce973351a2383aAdam Powell        if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
280a647640f85f415bd8fb8cb925e7687658fe9ae37Jake Wharton                mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) {
281696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
282696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mPostedOpenRunnable = new OpenOverflowRunnable(popup);
283696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            // Post this for later; we might still need a layout for the anchor to be right.
284696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            ((View) mMenuView).post(mPostedOpenRunnable);
285696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
286696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            // ActionMenuPresenter uses null as a callback argument here
287696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            // to indicate overflow is opening.
288696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            super.onSubMenuSelected(null);
289696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
290696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            return true;
291696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
292696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return false;
293696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
294696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
295696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
296696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Hide the overflow menu if it is currently showing.
297696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     *
298696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @return true if the overflow menu was hidden, false otherwise.
299696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
300696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean hideOverflowMenu() {
301696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mPostedOpenRunnable != null && mMenuView != null) {
302696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            ((View) mMenuView).removeCallbacks(mPostedOpenRunnable);
303678ed0c5a32bac1ea18a5ac99b0b814421ea79b4Adam Powell            mPostedOpenRunnable = null;
304696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            return true;
305696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
306696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
307696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        MenuPopupHelper popup = mOverflowPopup;
308696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (popup != null) {
309696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            popup.dismiss();
310696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            return true;
311696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
312696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return false;
313696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
314696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
315696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
316696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Dismiss all popup menus - overflow and submenus.
317696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @return true if popups were dismissed, false otherwise. (This can be because none were open.)
318696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
319696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean dismissPopupMenus() {
320696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        boolean result = hideOverflowMenu();
321696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        result |= hideSubMenus();
322696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return result;
323696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
324696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
325696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
326696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Dismiss all submenu popups.
327696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     *
328696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @return true if popups were dismissed, false otherwise. (This can be because none were open.)
329696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
330696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean hideSubMenus() {
331696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mActionButtonPopup != null) {
332696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mActionButtonPopup.dismiss();
333696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            return true;
334696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
335696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return false;
336696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
337696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
338696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
339696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @return true if the overflow menu is currently showing
340696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
341696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean isOverflowMenuShowing() {
342696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return mOverflowPopup != null && mOverflowPopup.isShowing();
343696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
344696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
345696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
346696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @return true if space has been reserved in the action menu for an overflow item.
347696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
348696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean isOverflowReserved() {
349696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return mReserveOverflow;
350696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
351696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
352696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean flagActionItems() {
353696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
354696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final int itemsSize = visibleItems.size();
355696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        int maxActions = mMaxItems;
356696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        int widthLimit = mActionItemWidthLimit;
357696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
358696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final ViewGroup parent = (ViewGroup) mMenuView;
359696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
360696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        int requiredItems = 0;
361696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        int requestedItems = 0;
362696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        int firstActionWidth = 0;
363696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        boolean hasOverflow = false;
364696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (int i = 0; i < itemsSize; i++) {
365696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            MenuItemImpl item = visibleItems.get(i);
366696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (item.requiresActionButton()) {
367696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                requiredItems++;
368696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            } else if (item.requestsActionButton()) {
369696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                requestedItems++;
370696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            } else {
371696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                hasOverflow = true;
372696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
373b187cd9c54f0100c0fb47c354cdecad29ca7c0aeAdam Powell            if (mExpandedActionViewsExclusive && item.isActionViewExpanded()) {
374b187cd9c54f0100c0fb47c354cdecad29ca7c0aeAdam Powell                // Overflow everything if we have an expanded action view and we're
375b187cd9c54f0100c0fb47c354cdecad29ca7c0aeAdam Powell                // space constrained.
376b187cd9c54f0100c0fb47c354cdecad29ca7c0aeAdam Powell                maxActions = 0;
377b187cd9c54f0100c0fb47c354cdecad29ca7c0aeAdam Powell            }
378696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
379696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
380696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        // Reserve a spot for the overflow item if needed.
381696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mReserveOverflow &&
382696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                (hasOverflow || requiredItems + requestedItems > maxActions)) {
383696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            maxActions--;
384696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
385696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        maxActions -= requiredItems;
386696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
387696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final SparseBooleanArray seenGroups = mActionButtonGroups;
388696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        seenGroups.clear();
389696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
39035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        int cellSize = 0;
39135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        int cellsRemaining = 0;
39235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        if (mStrictWidthLimit) {
39335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            cellsRemaining = widthLimit / mMinCellSize;
39435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            final int cellSizeRemaining = widthLimit % mMinCellSize;
39535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            cellSize = mMinCellSize + cellSizeRemaining / cellsRemaining;
39635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
39735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
398696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        // Flag as many more requested items as will fit.
399696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (int i = 0; i < itemsSize; i++) {
400696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            MenuItemImpl item = visibleItems.get(i);
401696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
402696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (item.requiresActionButton()) {
40335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                View v = getItemView(item, mScrapActionButtonView, parent);
40435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                if (mScrapActionButtonView == null) {
40535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    mScrapActionButtonView = v;
40635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                }
40735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                if (mStrictWidthLimit) {
40835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    cellsRemaining -= ActionMenuView.measureChildForCells(v,
40935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                            cellSize, cellsRemaining, querySpec, 0);
41035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                } else {
41135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    v.measure(querySpec, querySpec);
412696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                }
413696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                final int measuredWidth = v.getMeasuredWidth();
414696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                widthLimit -= measuredWidth;
415696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                if (firstActionWidth == 0) {
416696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    firstActionWidth = measuredWidth;
417696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                }
418696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                final int groupId = item.getGroupId();
419696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                if (groupId != 0) {
420696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    seenGroups.put(groupId, true);
421696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                }
422ea1ca952c625d51dc71e1cc3d955b239921888c7Adam Powell                item.setIsActionButton(true);
423696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            } else if (item.requestsActionButton()) {
424696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                // Items in a group with other items that already have an action slot
425696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                // can break the max actions rule, but not the width limit.
426696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                final int groupId = item.getGroupId();
427696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                final boolean inGroup = seenGroups.get(groupId);
42835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0 &&
42935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                        (!mStrictWidthLimit || cellsRemaining > 0);
430696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
431696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                if (isAction) {
43235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    View v = getItemView(item, mScrapActionButtonView, parent);
43335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    if (mScrapActionButtonView == null) {
43435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                        mScrapActionButtonView = v;
43535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    }
43635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    if (mStrictWidthLimit) {
43735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                        final int cells = ActionMenuView.measureChildForCells(v,
43835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                                cellSize, cellsRemaining, querySpec, 0);
43935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                        cellsRemaining -= cells;
44035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                        if (cells == 0) {
44135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                            isAction = false;
442696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                        }
44335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                    } else {
44435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                        v.measure(querySpec, querySpec);
445696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    }
446696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    final int measuredWidth = v.getMeasuredWidth();
447696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    widthLimit -= measuredWidth;
448696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    if (firstActionWidth == 0) {
449696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                        firstActionWidth = measuredWidth;
450696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    }
451696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
452640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                    if (mStrictWidthLimit) {
45335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                        isAction &= widthLimit >= 0;
454640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                    } else {
455640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell                        // Did this push the entire first item past the limit?
45635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                        isAction &= widthLimit + firstActionWidth > 0;
457696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    }
458696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                }
459696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
460696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                if (isAction && groupId != 0) {
461696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    seenGroups.put(groupId, true);
462696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                } else if (inGroup) {
463696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    // We broke the width limit. Demote the whole group, they all overflow now.
464696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    seenGroups.put(groupId, false);
465696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    for (int j = 0; j < i; j++) {
466696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                        MenuItemImpl areYouMyGroupie = visibleItems.get(j);
467696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                        if (areYouMyGroupie.getGroupId() == groupId) {
46823f4cc0353615107cc9c19fda9cf96ddd43266e2Adam Powell                            // Give back the action slot
46923f4cc0353615107cc9c19fda9cf96ddd43266e2Adam Powell                            if (areYouMyGroupie.isActionButton()) maxActions++;
470696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                            areYouMyGroupie.setIsActionButton(false);
471696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                        }
472696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    }
473696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                }
474696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
47523f4cc0353615107cc9c19fda9cf96ddd43266e2Adam Powell                if (isAction) maxActions--;
47623f4cc0353615107cc9c19fda9cf96ddd43266e2Adam Powell
477696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                item.setIsActionButton(isAction);
478696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
479696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
480696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return true;
481696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
482696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
483696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    @Override
484696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
485696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        dismissPopupMenus();
486696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        super.onCloseMenu(menu, allMenusAreClosing);
487696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
488696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
48911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    @Override
49011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    public Parcelable onSaveInstanceState() {
49111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        SavedState state = new SavedState();
49211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        state.openSubMenuId = mOpenSubMenuId;
49311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        return state;
49411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
49511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
49611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    @Override
49711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    public void onRestoreInstanceState(Parcelable state) {
49811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        SavedState saved = (SavedState) state;
49911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        if (saved.openSubMenuId > 0) {
50011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            MenuItem item = mMenu.findItem(saved.openSubMenuId);
50111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            if (item != null) {
50211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
50311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                onSubMenuSelected(subMenu);
50411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            }
50511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
50611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
50711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
508823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell    @Override
509823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell    public void onSubUiVisibilityChanged(boolean isVisible) {
510823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell        if (isVisible) {
511823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell            // Not a submenu, but treat it like one.
512823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell            super.onSubMenuSelected(null);
513823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell        } else {
514823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell            mMenu.close(false);
515823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell        }
516823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell    }
517823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell
51811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    private static class SavedState implements Parcelable {
51911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        public int openSubMenuId;
52011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
52111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        SavedState() {
52211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
52311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
52411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        SavedState(Parcel in) {
52511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            openSubMenuId = in.readInt();
52611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
52711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
52811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        @Override
52911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        public int describeContents() {
53011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            return 0;
53111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
53211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
53311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        @Override
53411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        public void writeToParcel(Parcel dest, int flags) {
53511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            dest.writeInt(openSubMenuId);
53611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
53711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
53811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        public static final Parcelable.Creator<SavedState> CREATOR
53911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                = new Parcelable.Creator<SavedState>() {
54011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            public SavedState createFromParcel(Parcel in) {
54111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                return new SavedState(in);
54211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            }
54311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
54411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            public SavedState[] newArray(int size) {
54511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                return new SavedState[size];
54611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            }
54711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        };
54811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
54911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
550696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private class OverflowMenuButton extends ImageButton implements ActionMenuChildView {
551696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public OverflowMenuButton(Context context) {
552696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle);
553696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
554696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            setClickable(true);
555696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            setFocusable(true);
556696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            setVisibility(VISIBLE);
557696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            setEnabled(true);
558696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
559696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
560696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        @Override
561696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public boolean performClick() {
562696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (super.performClick()) {
563696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                return true;
564696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
565696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
566696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            playSoundEffect(SoundEffectConstants.CLICK);
567696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            showOverflowMenu();
568696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            return true;
569696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
570696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
571696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public boolean needsDividerBefore() {
57235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            return false;
573696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
574696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
575696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public boolean needsDividerAfter() {
576696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            return false;
577696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
578696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
579696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
580696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private class OverflowPopup extends MenuPopupHelper {
581696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
582696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                boolean overflowOnly) {
583696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            super(context, menu, anchorView, overflowOnly);
58411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            setCallback(mPopupPresenterCallback);
585696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
586696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
587696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        @Override
588696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public void onDismiss() {
589696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            super.onDismiss();
590696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mMenu.close();
591696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mOverflowPopup = null;
592696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
593696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
594696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
595696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private class ActionButtonSubmenu extends MenuPopupHelper {
596696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        private SubMenuBuilder mSubMenu;
597696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
598696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
599696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            super(context, subMenu);
600696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mSubMenu = subMenu;
601696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
602696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
603696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (!item.isActionButton()) {
604696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                // Give a reasonable anchor to nested submenus.
605696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton);
606696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
60711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
60811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            setCallback(mPopupPresenterCallback);
6099151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell
6109151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell            boolean preserveIconSpacing = false;
6119151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell            final int count = subMenu.size();
6129151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell            for (int i = 0; i < count; i++) {
6139151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell                MenuItem childItem = subMenu.getItem(i);
6149151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell                if (childItem.isVisible() && childItem.getIcon() != null) {
6159151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell                    preserveIconSpacing = true;
6169151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell                    break;
6179151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell                }
6189151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell            }
6199151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell            setForceShowIcon(preserveIconSpacing);
620696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
621696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
622696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        @Override
623696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public void onDismiss() {
624696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            super.onDismiss();
625696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mActionButtonPopup = null;
62611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            mOpenSubMenuId = 0;
62711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
62811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
62911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
63011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    private class PopupPresenterCallback implements MenuPresenter.Callback {
63111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
63211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        @Override
63311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        public boolean onOpenSubMenu(MenuBuilder subMenu) {
634823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell            if (subMenu == null) return false;
635823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell
63611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
63711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            return false;
63811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
63911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
64011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        @Override
64111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
642823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell            if (menu instanceof SubMenuBuilder) {
643823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell                ((SubMenuBuilder) menu).getRootMenu().close(false);
644823f074a73cfc23c40a7b576c71daa096ee9ed6aAdam Powell            }
645696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
646696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
647696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
648696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private class OpenOverflowRunnable implements Runnable {
649696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        private OverflowPopup mPopup;
650696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
651696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public OpenOverflowRunnable(OverflowPopup popup) {
652696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mPopup = popup;
653696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
654696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
655696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        public void run() {
656696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mMenu.changeMenuMode();
657678ed0c5a32bac1ea18a5ac99b0b814421ea79b4Adam Powell            final View menuView = (View) mMenuView;
658678ed0c5a32bac1ea18a5ac99b0b814421ea79b4Adam Powell            if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) {
659696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mOverflowPopup = mPopup;
660696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
661678ed0c5a32bac1ea18a5ac99b0b814421ea79b4Adam Powell            mPostedOpenRunnable = null;
662696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
663696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
664696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell}
665