19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.internal.view.menu;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ComponentName;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.ResolveInfo;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Configuration;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable;
2811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powellimport android.os.Bundle;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseArray;
31961dd11895ce72e59bca124ef5bea4e4c1183099Adam Powellimport android.view.ActionProvider;
3236fced9b211255e2137014e21fb3259042d8da85Adam Powellimport android.view.ContextMenu.ContextMenuInfo;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyCharacterMap;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Menu;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MenuItem;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.SubMenu;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.ref.WeakReference;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
43696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport java.util.concurrent.CopyOnWriteArrayList;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implementation of the {@link android.view.Menu} interface for creating a
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * standard menu UI.
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class MenuBuilder implements Menu {
5089b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell    private static final String TAG = "MenuBuilder";
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    private static final String PRESENTER_KEY = "android:menu:presenters";
53038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    private static final String ACTION_VIEW_STATES_KEY = "android:menu:actionviewstates";
54038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    private static final String EXPANDED_ACTION_VIEW_ID = "android:menu:expandedactionview";
5511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int[]  sCategoryToOrder = new int[] {
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        1, /* No category */
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        4, /* CONTAINER */
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        5, /* SYSTEM */
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        3, /* SECONDARY */
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        2, /* ALTERNATIVE */
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        0, /* SELECTED_ALTERNATIVE */
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Resources mResources;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Whether the shortcuts should be qwerty-accessible. Use isQwertyMode()
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * instead of accessing this directly.
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mQwertyMode;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Whether the shortcuts should be visible on menus. Use isShortcutsVisible()
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * instead of accessing this directly.
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mShortcutsVisible;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Callback that will receive the various menu-related events generated by
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * this class. Use getCallback to get a reference to the callback.
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Callback mCallback;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Contains all of the items for this menu */
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayList<MenuItemImpl> mItems;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Contains only the items that are currently visible.  This will be created/refreshed from
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #getVisibleItems()} */
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayList<MenuItemImpl> mVisibleItems;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Whether or not the items (or any one item's shown state) has changed since it was last
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * fetched from {@link #getVisibleItems()}
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsVisibleItemsStale;
9796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
9896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    /**
9996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     * Contains only the items that should appear in the Action Bar, if present.
10096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     */
10196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private ArrayList<MenuItemImpl> mActionItems;
10296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    /**
10396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     * Contains items that should NOT appear in the Action Bar, if present.
10496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     */
10596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private ArrayList<MenuItemImpl> mNonActionItems;
106696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
10736fced9b211255e2137014e21fb3259042d8da85Adam Powell    /**
10896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     * Whether or not the items (or any one item's action state) has changed since it was
10996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     * last fetched.
11096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     */
11196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private boolean mIsActionItemsStale;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1144d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell     * Default value for how added items should show in the action list.
1154d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell     */
1164d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell    private int mDefaultShowAsAction = MenuItem.SHOW_AS_ACTION_NEVER;
1174d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell
1184d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell    /**
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Current use case is Context Menus: As Views populate the context menu, each one has
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * extra information that should be passed along.  This is the current menu info that
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * should be set on all items added to this menu.
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ContextMenuInfo mCurrentMenuInfo;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Header title for menu types that have a header (context and submenus) */
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    CharSequence mHeaderTitle;
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Header icon for menu types that have a header and support icons (context) */
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Drawable mHeaderIcon;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Header custom view for menu types that have a header and support custom views (context) */
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    View mHeaderView;
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Contains the state of the View hierarchy for all menu views when the menu
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * was frozen.
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SparseArray<Parcelable> mFrozenViewStates;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Prevents onItemsChanged from doing its junk, useful for batching commands
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that may individually call onItemsChanged.
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mPreventDispatchingItemsChanged = false;
143696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private boolean mItemsChangedWhileDispatchPrevented = false;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mOptionalIconsVisible = false;
1462fbf4de64f0ec5052201cea9519c44d5b1789a40Adam Powell
147696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private boolean mIsClosing = false;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
149696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private ArrayList<MenuItemImpl> mTempShortcutItemList = new ArrayList<MenuItemImpl>();
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
151696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private CopyOnWriteArrayList<WeakReference<MenuPresenter>> mPresenters =
152696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            new CopyOnWriteArrayList<WeakReference<MenuPresenter>>();
1536b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell
1546b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell    /**
1556b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell     * Currently expanded menu item; must be collapsed when we clear.
1566b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell     */
1576b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell    private MenuItemImpl mExpandedItem;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
160696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Called by menu to notify of close and selection changes.
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface Callback {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Called when a menu item is selected.
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param menu The menu that is the parent of the item
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param item The menu item that is selected
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return whether the menu item selection was handled
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Called when the mode of the menu changes (for example, from icon to expanded).
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param menu the menu that has changed modes
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onMenuModeChange(MenuBuilder menu);
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Called by menu items to execute their associated action
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface ItemInvoker {
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean invokeItem(MenuItemImpl item);
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuBuilder(Context context) {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mResources = context.getResources();
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItems = new ArrayList<MenuItemImpl>();
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVisibleItems = new ArrayList<MenuItemImpl>();
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsVisibleItemsStale = true;
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mActionItems = new ArrayList<MenuItemImpl>();
19696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mNonActionItems = new ArrayList<MenuItemImpl>();
19796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mIsActionItemsStale = true;
19896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
1994aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown        setShortcutsVisibleInner(true);
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2024d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell    public MenuBuilder setDefaultShowAsAction(int defaultShowAsAction) {
2034d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell        mDefaultShowAsAction = defaultShowAsAction;
2044d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell        return this;
2054d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell    }
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
207696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
208696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Add a presenter to this menu. This will only hold a WeakReference;
209696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * you do not need to explicitly remove a presenter, but you can using
210696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * {@link #removeMenuPresenter(MenuPresenter)}.
211696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     *
212696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @param presenter The presenter to add
213696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
214696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void addMenuPresenter(MenuPresenter presenter) {
2153d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette        addMenuPresenter(presenter, mContext);
2163d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette    }
2173d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette
2183d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette    /**
2193d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette     * Add a presenter to this menu that uses an alternate context for
2203d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette     * inflating menu items. This will only hold a WeakReference; you do not
2213d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette     * need to explicitly remove a presenter, but you can using
2223d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette     * {@link #removeMenuPresenter(MenuPresenter)}.
2233d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette     *
2243d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette     * @param presenter The presenter to add
2253d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette     * @param menuContext The context used to inflate menu items
2263d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette     */
2273d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette    public void addMenuPresenter(MenuPresenter presenter, Context menuContext) {
228696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mPresenters.add(new WeakReference<MenuPresenter>(presenter));
2293d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette        presenter.initForMenu(menuContext, this);
230696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mIsActionItemsStale = true;
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
232696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
234696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Remove a presenter from this menu. That presenter will no longer
235696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * receive notifications of updates to this menu's data.
236696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     *
237696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @param presenter The presenter to remove
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
239696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void removeMenuPresenter(MenuPresenter presenter) {
240696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
241696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuPresenter item = ref.get();
242696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (item == null || item == presenter) {
243696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mPresenters.remove(ref);
244696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
248696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private void dispatchPresenterUpdate(boolean cleared) {
249696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mPresenters.isEmpty()) return;
250696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
251640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        stopDispatchingItemsChanged();
252696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
253696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuPresenter presenter = ref.get();
254696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (presenter == null) {
255696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mPresenters.remove(ref);
256696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            } else {
257696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                presenter.updateMenuView(cleared);
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
260640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        startDispatchingItemsChanged();
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
263c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell    private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu,
264c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell            MenuPresenter preferredPresenter) {
265696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mPresenters.isEmpty()) return false;
266696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
267696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        boolean result = false;
268696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
269c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell        // Try the preferred presenter first.
270c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell        if (preferredPresenter != null) {
271c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell            result = preferredPresenter.onSubMenuSelected(subMenu);
272c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell        }
273c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell
274696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
275696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuPresenter presenter = ref.get();
276696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (presenter == null) {
277696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mPresenters.remove(ref);
278696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            } else if (!result) {
279696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                result = presenter.onSubMenuSelected(subMenu);
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
282696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return result;
283696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
284696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
28511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    private void dispatchSaveInstanceState(Bundle outState) {
28611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        if (mPresenters.isEmpty()) return;
28711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
28811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        SparseArray<Parcelable> presenterStates = new SparseArray<Parcelable>();
28911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
29011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
29111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            final MenuPresenter presenter = ref.get();
29211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            if (presenter == null) {
29311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                mPresenters.remove(ref);
29411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            } else {
29511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                final int id = presenter.getId();
29611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                if (id > 0) {
29711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    final Parcelable state = presenter.onSaveInstanceState();
29811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    if (state != null) {
29911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                        presenterStates.put(id, state);
30011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    }
30111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                }
30211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            }
30311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
30411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
30511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        outState.putSparseParcelableArray(PRESENTER_KEY, presenterStates);
30611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
30711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
30811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    private void dispatchRestoreInstanceState(Bundle state) {
30911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        SparseArray<Parcelable> presenterStates = state.getSparseParcelableArray(PRESENTER_KEY);
31011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
31111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        if (presenterStates == null || mPresenters.isEmpty()) return;
31211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
31311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
31411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            final MenuPresenter presenter = ref.get();
31511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            if (presenter == null) {
31611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                mPresenters.remove(ref);
31711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            } else {
31811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                final int id = presenter.getId();
31911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                if (id > 0) {
32011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    Parcelable parcel = presenterStates.get(id);
32111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    if (parcel != null) {
32211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                        presenter.onRestoreInstanceState(parcel);
32311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    }
32411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                }
32511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            }
32611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
32711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
32811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
32911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    public void savePresenterStates(Bundle outState) {
33011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        dispatchSaveInstanceState(outState);
33111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
33211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
33311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    public void restorePresenterStates(Bundle state) {
33411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        dispatchRestoreInstanceState(state);
33511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
33611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
337038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    public void saveActionViewStates(Bundle outStates) {
338038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        SparseArray<Parcelable> viewStates = null;
339038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
340038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        final int itemCount = size();
341038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        for (int i = 0; i < itemCount; i++) {
342038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            final MenuItem item = getItem(i);
343038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            final View v = item.getActionView();
344038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            if (v != null && v.getId() != View.NO_ID) {
345038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                if (viewStates == null) {
346038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                    viewStates = new SparseArray<Parcelable>();
347038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                }
348038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                v.saveHierarchyState(viewStates);
349038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                if (item.isActionViewExpanded()) {
350038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                    outStates.putInt(EXPANDED_ACTION_VIEW_ID, item.getItemId());
351038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                }
352038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            }
353038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            if (item.hasSubMenu()) {
354038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
355038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                subMenu.saveActionViewStates(outStates);
356038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            }
357038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        }
358038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
359038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        if (viewStates != null) {
360038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            outStates.putSparseParcelableArray(getActionViewStatesKey(), viewStates);
361038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        }
362038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    }
363038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
364038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    public void restoreActionViewStates(Bundle states) {
365038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        if (states == null) {
366038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            return;
367038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        }
368038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
369038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        SparseArray<Parcelable> viewStates = states.getSparseParcelableArray(
370038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                getActionViewStatesKey());
371038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
372038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        final int itemCount = size();
373038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        for (int i = 0; i < itemCount; i++) {
374038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            final MenuItem item = getItem(i);
375038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            final View v = item.getActionView();
376038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            if (v != null && v.getId() != View.NO_ID) {
377038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                v.restoreHierarchyState(viewStates);
378038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            }
379038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            if (item.hasSubMenu()) {
380038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
381038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                subMenu.restoreActionViewStates(states);
382038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            }
383038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        }
384038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
385038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        final int expandedId = states.getInt(EXPANDED_ACTION_VIEW_ID);
386038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        if (expandedId > 0) {
387038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            MenuItem itemToExpand = findItem(expandedId);
388038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            if (itemToExpand != null) {
389038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                itemToExpand.expandActionView();
390038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            }
391038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        }
392038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    }
393038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
394038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    protected String getActionViewStatesKey() {
395038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        return ACTION_VIEW_STATES_KEY;
396038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    }
397038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
398696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void setCallback(Callback cb) {
399696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mCallback = cb;
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Adds an item to the menu.  The other add methods funnel to this.
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int ordering = getOrdering(categoryOrder);
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4081001961f904bac5294aaf73a47c2497aa764bf7fDeepanshu Gupta        final MenuItemImpl item = createNewMenuItem(group, id, categoryOrder, ordering, title,
4091001961f904bac5294aaf73a47c2497aa764bf7fDeepanshu Gupta                mDefaultShowAsAction);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurrentMenuInfo != null) {
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Pass along the current menu info
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            item.setMenuInfo(mCurrentMenuInfo);
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItems.add(findInsertIndex(mItems, ordering), item);
417696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        onItemsChanged(true);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return item;
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4211001961f904bac5294aaf73a47c2497aa764bf7fDeepanshu Gupta
4221001961f904bac5294aaf73a47c2497aa764bf7fDeepanshu Gupta    // Layoutlib overrides this method to return its custom implementation of MenuItemImpl
4231001961f904bac5294aaf73a47c2497aa764bf7fDeepanshu Gupta    private MenuItemImpl createNewMenuItem(int group, int id, int categoryOrder, int ordering,
4241001961f904bac5294aaf73a47c2497aa764bf7fDeepanshu Gupta            CharSequence title, int defaultShowAsAction) {
4251001961f904bac5294aaf73a47c2497aa764bf7fDeepanshu Gupta        return new MenuItemImpl(this, group, id, categoryOrder, ordering, title,
4261001961f904bac5294aaf73a47c2497aa764bf7fDeepanshu Gupta                defaultShowAsAction);
4271001961f904bac5294aaf73a47c2497aa764bf7fDeepanshu Gupta    }
4281001961f904bac5294aaf73a47c2497aa764bf7fDeepanshu Gupta
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem add(CharSequence title) {
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addInternal(0, 0, 0, title);
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem add(int titleRes) {
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addInternal(0, 0, 0, mResources.getString(titleRes));
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem add(int group, int id, int categoryOrder, CharSequence title) {
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addInternal(group, id, categoryOrder, title);
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem add(int group, int id, int categoryOrder, int title) {
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addInternal(group, id, categoryOrder, mResources.getString(title));
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SubMenu addSubMenu(CharSequence title) {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addSubMenu(0, 0, 0, title);
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SubMenu addSubMenu(int titleRes) {
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addSubMenu(0, 0, 0, mResources.getString(titleRes));
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SubMenu addSubMenu(int group, int id, int categoryOrder, CharSequence title) {
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final MenuItemImpl item = (MenuItemImpl) addInternal(group, id, categoryOrder, title);
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final SubMenuBuilder subMenu = new SubMenuBuilder(mContext, this, item);
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        item.setSubMenu(subMenu);
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return subMenu;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SubMenu addSubMenu(int group, int id, int categoryOrder, int title) {
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addSubMenu(group, id, categoryOrder, mResources.getString(title));
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int addIntentOptions(int group, int id, int categoryOrder, ComponentName caller,
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PackageManager pm = mContext.getPackageManager();
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final List<ResolveInfo> lri =
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pm.queryIntentActivityOptions(caller, specifics, intent, 0);
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = lri != null ? lri.size() : 0;
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags & FLAG_APPEND_TO_GROUP) == 0) {
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeGroup(group);
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i=0; i<N; i++) {
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final ResolveInfo ri = lri.get(i);
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent rintent = new Intent(
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]);
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rintent.setComponent(new ComponentName(
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ri.activityInfo.applicationInfo.packageName,
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ri.activityInfo.name));
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final MenuItem item = add(group, id, categoryOrder, ri.loadLabel(pm))
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .setIcon(ri.loadIcon(pm))
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .setIntent(rintent);
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (outSpecificItems != null && ri.specificIndex >= 0) {
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                outSpecificItems[ri.specificIndex] = item;
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return N;
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeItem(int id) {
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        removeItemAtInt(findItemIndex(id), true);
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeGroup(int group) {
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int i = findGroupIndex(group);
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (i >= 0) {
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int maxRemovable = mItems.size() - i;
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int numRemoved = 0;
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while ((numRemoved++ < maxRemovable) && (mItems.get(i).getGroupId() == group)) {
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Don't force update for each one, this method will do it at the end
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                removeItemAtInt(i, false);
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Notify menu views
510696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            onItemsChanged(true);
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Remove the item at the given index and optionally forces menu views to
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * update.
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index The index of the item to be removed. If this index is
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            invalid an exception is thrown.
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param updateChildrenOnMenuViews Whether to force update on menu views.
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            Please make sure you eventually call this after your batch of
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            removals.
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void removeItemAtInt(int index, boolean updateChildrenOnMenuViews) {
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((index < 0) || (index >= mItems.size())) return;
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItems.remove(index);
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (updateChildrenOnMenuViews) onItemsChanged(true);
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeItemAt(int index) {
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        removeItemAtInt(index, true);
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clearAll() {
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPreventDispatchingItemsChanged = true;
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        clear();
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        clearHeader();
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPreventDispatchingItemsChanged = false;
541696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mItemsChangedWhileDispatchPrevented = false;
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onItemsChanged(true);
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clear() {
5466b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell        if (mExpandedItem != null) {
5476b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell            collapseItemActionView(mExpandedItem);
5486b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell        }
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItems.clear();
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onItemsChanged(true);
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setExclusiveItemChecked(MenuItem item) {
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int group = item.getGroupId();
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mItems.size();
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl curItem = mItems.get(i);
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (curItem.getGroupId() == group) {
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!curItem.isExclusiveCheckable()) continue;
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!curItem.isCheckable()) continue;
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Check the item meant to be checked, uncheck the others (that are in the group)
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                curItem.setCheckedInt(curItem == item);
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mItems.size();
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getGroupId() == group) {
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                item.setExclusiveCheckable(exclusive);
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                item.setCheckable(checkable);
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGroupVisible(int group, boolean visible) {
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mItems.size();
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // We handle the notification of items being changed ourselves, so we use setVisibleInt rather
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // than setVisible and at the end notify of items being changed
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean changedAtLeastOneItem = false;
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getGroupId() == group) {
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (item.setVisibleInt(visible)) changedAtLeastOneItem = true;
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
59623f4cc0353615107cc9c19fda9cf96ddd43266e2Adam Powell        if (changedAtLeastOneItem) onItemsChanged(true);
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGroupEnabled(int group, boolean enabled) {
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mItems.size();
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getGroupId() == group) {
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                item.setEnabled(enabled);
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean hasVisibleItems() {
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int size = size();
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < size; i++) {
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.isVisible()) {
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem findItem(int id) {
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int size = size();
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < size; i++) {
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getItemId() == id) {
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return item;
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (item.hasSubMenu()) {
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                MenuItem possibleItem = item.getSubMenu().findItem(id);
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (possibleItem != null) {
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return possibleItem;
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int findItemIndex(int id) {
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int size = size();
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < size; i++) {
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getItemId() == id) {
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return i;
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int findGroupIndex(int group) {
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return findGroupIndex(group, 0);
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int findGroupIndex(int group, int start) {
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int size = size();
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (start < 0) {
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            start = 0;
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = start; i < size; i++) {
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final MenuItemImpl item = mItems.get(i);
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getGroupId() == group) {
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return i;
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int size() {
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mItems.size();
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** {@inheritDoc} */
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem getItem(int index) {
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mItems.get(index);
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isShortcutKey(int keyCode, KeyEvent event) {
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return findItemWithShortcutForKey(keyCode, event) != null;
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setQwertyMode(boolean isQwerty) {
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mQwertyMode = isQwerty;
691696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
692696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        onItemsChanged(false);
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the ordering across all items. This will grab the category from
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the upper bits, find out how to order the category with respect to other
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * categories, and combine it with the lower bits.
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param categoryOrder The category order for a particular item (if it has
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            not been or/add with a category, the default category is
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            assumed).
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return An ordering integer that can be used to order this item across
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         all the items (even from other categories).
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
706696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private static int getOrdering(int categoryOrder) {
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int index = (categoryOrder & CATEGORY_MASK) >> CATEGORY_SHIFT;
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (index < 0 || index >= sCategoryToOrder.length) {
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("order does not contain a valid category.");
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (sCategoryToOrder[index] << CATEGORY_SHIFT) | (categoryOrder & USER_MASK);
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return whether the menu shortcuts are in qwerty mode or not
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean isQwertyMode() {
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mQwertyMode;
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets whether the shortcuts should be visible on menus.  Devices without hardware
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * key input will never make shortcuts visible even if this method is passed 'true'.
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param shortcutsVisible Whether shortcuts should be visible (if true and a
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            menu item does not have a shortcut defined, that item will
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            still NOT show a shortcut)
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setShortcutsVisible(boolean shortcutsVisible) {
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShortcutsVisible == shortcutsVisible) return;
7334aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown
7344aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown        setShortcutsVisibleInner(shortcutsVisible);
735696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        onItemsChanged(false);
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7384aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown    private void setShortcutsVisibleInner(boolean shortcutsVisible) {
7394aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown        mShortcutsVisible = shortcutsVisible
7404aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown                && mResources.getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS
7414aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown                && mResources.getBoolean(
7424aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown                        com.android.internal.R.bool.config_showMenuShortcutsWhenKeyboardPresent);
7434aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown    }
7444aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether shortcuts should be visible on menus.
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isShortcutsVisible() {
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mShortcutsVisible;
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Resources getResources() {
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mResources;
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Context getContext() {
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mContext;
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
760696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    boolean dispatchMenuItemSelected(MenuBuilder menu, MenuItem item) {
761696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return mCallback != null && mCallback.onMenuItemSelected(menu, item);
762696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
763696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
764696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
765696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Dispatch a mode change event to this menu's callback.
766696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
767696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void changeMenuMode() {
768696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mCallback != null) {
769696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mCallback.onMenuModeChange(this);
770696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
771696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
772696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static int findInsertIndex(ArrayList<MenuItemImpl> items, int ordering) {
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = items.size() - 1; i >= 0; i--) {
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = items.get(i);
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getOrdering() <= ordering) {
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return i + 1;
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final MenuItemImpl item = findItemWithShortcutForKey(keyCode, event);
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = false;
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (item != null) {
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handled = performItemAction(item, flags);
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags & FLAG_ALWAYS_PERFORM_CLOSE) != 0) {
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            close(true);
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return handled;
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
800e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard    /*
801e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * This function will return all the menu and sub-menu items that can
802e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * be directly (the shortcut directly corresponds) and indirectly
803e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * (the ALT-enabled char corresponds to the shortcut) associated
804e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * with the keyCode.
805e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     */
806696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    void findItemsWithShortcutForKey(List<MenuItemImpl> items, int keyCode, KeyEvent event) {
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean qwerty = isQwertyMode();
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int metaState = event.getMetaState();
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData();
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Get the chars associated with the keyCode (i.e using any chording combo)
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean isKeyCodeMapped = event.getKeyData(possibleChars);
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // The delete key is not mapped to '\b' so we treat it specially
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!isKeyCodeMapped && (keyCode != KeyEvent.KEYCODE_DEL)) {
814696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            return;
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Look for an item whose shortcut is this key.
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mItems.size();
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.hasSubMenu()) {
822696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                ((MenuBuilder)item.getSubMenu()).findItemsWithShortcutForKey(items, keyCode, event);
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
824e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut();
825e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) &&
826e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                  (shortcutChar != 0) &&
827e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                  (shortcutChar == possibleChars.meta[0]
828e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                      || shortcutChar == possibleChars.meta[2]
829e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                      || (qwerty && shortcutChar == '\b' &&
830e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                          keyCode == KeyEvent.KEYCODE_DEL)) &&
831e38eb4d4ef504c0b72d51dfcc8fcd06cf73c0d50Alan Viverette                  item.isEnabled()) {
832e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                items.add(item);
833e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            }
834e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        }
835e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard    }
836e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
837e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard    /*
838e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * We want to return the menu item associated with the key, but if there is no
839e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * ambiguity (i.e. there is only one menu item corresponding to the key) we want
840e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * to return it even if it's not an exact match; this allow the user to
841e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * _not_ use the ALT key for example, making the use of shortcuts slightly more
842e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * user-friendly. An example is on the G1, '!' and '1' are on the same key, and
843e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * in Gmail, Menu+1 will trigger Menu+! (the actual shortcut).
844e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     *
845e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * On the other hand, if two (or more) shortcuts corresponds to the same key,
846e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * we have to only return the exact match.
847e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     */
848e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard    MenuItemImpl findItemWithShortcutForKey(int keyCode, KeyEvent event) {
849e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        // Get all items that can be associated directly or indirectly with the keyCode
850696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        ArrayList<MenuItemImpl> items = mTempShortcutItemList;
851696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        items.clear();
852696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        findItemsWithShortcutForKey(items, keyCode, event);
853e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
854696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (items.isEmpty()) {
855e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            return null;
856e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        }
857e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
858e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        final int metaState = event.getMetaState();
859e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData();
860e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        // Get the chars associated with the keyCode (i.e using any chording combo)
861e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        event.getKeyData(possibleChars);
862e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
863e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        // If we have only one element, we can safely returns it
864696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final int size = items.size();
865696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (size == 1) {
866e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            return items.get(0);
867e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        }
868e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
869e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        final boolean qwerty = isQwertyMode();
870e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        // If we found more than one item associated with the key,
871e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        // we have to return the exact match
872696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (int i = 0; i < size; i++) {
873696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuItemImpl item = items.get(i);
874696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final char shortcutChar = qwerty ? item.getAlphabeticShortcut() :
875696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    item.getNumericShortcut();
876e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            if ((shortcutChar == possibleChars.meta[0] &&
877e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                    (metaState & KeyEvent.META_ALT_ON) == 0)
878e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                || (shortcutChar == possibleChars.meta[2] &&
879e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                    (metaState & KeyEvent.META_ALT_ON) != 0)
880e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                || (qwerty && shortcutChar == '\b' &&
881e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                    keyCode == KeyEvent.KEYCODE_DEL)) {
882e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                return item;
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
887e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performIdentifierAction(int id, int flags) {
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Look for an item whose identifier is the id.
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return performItemAction(findItem(id), flags);
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performItemAction(MenuItem item, int flags) {
894c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell        return performItemAction(item, null, flags);
895c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell    }
896c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell
897c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell    public boolean performItemAction(MenuItem item, MenuPresenter preferredPresenter, int flags) {
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MenuItemImpl itemImpl = (MenuItemImpl) item;
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (itemImpl == null || !itemImpl.isEnabled()) {
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9028d02deabac62c4a68a335a7b3141795466362b89Adam Powell        }
90376559a65ad9d644f10beacf8895ceb217fdd0aebSvetoslav Ganov
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean invoked = itemImpl.invoke();
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
906f77f480800a84ceb377e47cc200baf2bae4f5d9aAdam Powell        final ActionProvider provider = item.getActionProvider();
907f77f480800a84ceb377e47cc200baf2bae4f5d9aAdam Powell        final boolean providerHasSubMenu = provider != null && provider.hasSubMenu();
9088d02deabac62c4a68a335a7b3141795466362b89Adam Powell        if (itemImpl.hasCollapsibleActionView()) {
9098d02deabac62c4a68a335a7b3141795466362b89Adam Powell            invoked |= itemImpl.expandActionView();
9108d02deabac62c4a68a335a7b3141795466362b89Adam Powell            if (invoked) close(true);
911f77f480800a84ceb377e47cc200baf2bae4f5d9aAdam Powell        } else if (itemImpl.hasSubMenu() || providerHasSubMenu) {
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            close(false);
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
914f77f480800a84ceb377e47cc200baf2bae4f5d9aAdam Powell            if (!itemImpl.hasSubMenu()) {
915f77f480800a84ceb377e47cc200baf2bae4f5d9aAdam Powell                itemImpl.setSubMenu(new SubMenuBuilder(getContext(), this, itemImpl));
916f77f480800a84ceb377e47cc200baf2bae4f5d9aAdam Powell            }
917f77f480800a84ceb377e47cc200baf2bae4f5d9aAdam Powell
918f77f480800a84ceb377e47cc200baf2bae4f5d9aAdam Powell            final SubMenuBuilder subMenu = (SubMenuBuilder) itemImpl.getSubMenu();
919f77f480800a84ceb377e47cc200baf2bae4f5d9aAdam Powell            if (providerHasSubMenu) {
920961dd11895ce72e59bca124ef5bea4e4c1183099Adam Powell                provider.onPrepareSubMenu(subMenu);
921961dd11895ce72e59bca124ef5bea4e4c1183099Adam Powell            }
922c0cc68053e5013c207be6f64ffd2ad9e8c467defAdam Powell            invoked |= dispatchSubMenuSelected(subMenu, preferredPresenter);
923696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (!invoked) close(true);
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((flags & FLAG_PERFORM_NO_CLOSE) == 0) {
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                close(true);
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return invoked;
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Closes the visible menu.
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param allMenusAreClosing Whether the menus are completely closing (true),
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            or whether there is another menu coming in this menu's place
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            (false). For example, if the menu is closing because a
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            sub menu is about to be shown, <var>allMenusAreClosing</var>
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            is false.
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
942fa18d182a3f37505940e73ae6cd76c2e939f7f7cAdam Powell    public final void close(boolean allMenusAreClosing) {
943696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mIsClosing) return;
944696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
945696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mIsClosing = true;
946696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
947696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuPresenter presenter = ref.get();
948696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (presenter == null) {
949696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mPresenters.remove(ref);
950696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            } else {
951696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                presenter.onCloseMenu(this, allMenusAreClosing);
952696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
954696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mIsClosing = false;
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** {@inheritDoc} */
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void close() {
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        close(true);
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Called when an item is added or removed.
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
965696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @param structureChanged true if the menu structure changed,
966696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     *                         false if only item properties changed.
96723f4cc0353615107cc9c19fda9cf96ddd43266e2Adam Powell     *                         (Visibility is a structural property since it affects layout.)
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
969fa18d182a3f37505940e73ae6cd76c2e939f7f7cAdam Powell    public void onItemsChanged(boolean structureChanged) {
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mPreventDispatchingItemsChanged) {
971696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (structureChanged) {
972696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mIsVisibleItemsStale = true;
973696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mIsActionItemsStale = true;
974696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
9751821ff9022f0ea5f5c5d82a96a05f46192d50c26Adam Powell
976696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            dispatchPresenterUpdate(structureChanged);
977696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        } else {
978696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mItemsChangedWhileDispatchPrevented = true;
979696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
980696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
9811821ff9022f0ea5f5c5d82a96a05f46192d50c26Adam Powell
982696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
983696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Stop dispatching item changed events to presenters until
984696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * {@link #startDispatchingItemsChanged()} is called. Useful when
985696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * many menu operations are going to be performed as a batch.
986696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
987696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void stopDispatchingItemsChanged() {
988a86b350977be53146d568bc0736d0f2b4aef8de5Adam Powell        if (!mPreventDispatchingItemsChanged) {
989a86b350977be53146d568bc0736d0f2b4aef8de5Adam Powell            mPreventDispatchingItemsChanged = true;
990a86b350977be53146d568bc0736d0f2b4aef8de5Adam Powell            mItemsChangedWhileDispatchPrevented = false;
991a86b350977be53146d568bc0736d0f2b4aef8de5Adam Powell        }
992696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
993696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
994696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void startDispatchingItemsChanged() {
995696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mPreventDispatchingItemsChanged = false;
996696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
997696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mItemsChangedWhileDispatchPrevented) {
998696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mItemsChangedWhileDispatchPrevented = false;
999696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            onItemsChanged(true);
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Called by {@link MenuItemImpl} when its visible flag is changed.
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param item The item that has gone through a visibility change.
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void onItemVisibleChanged(MenuItemImpl item) {
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Notify of items being changed
1009696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mIsVisibleItemsStale = true;
101023f4cc0353615107cc9c19fda9cf96ddd43266e2Adam Powell        onItemsChanged(true);
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
101396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    /**
101496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     * Called by {@link MenuItemImpl} when its action request status is changed.
101596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     * @param item The item that has gone through a change in action request status.
101696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     */
101796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    void onItemActionRequestChanged(MenuItemImpl item) {
101896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        // Notify of items being changed
1019696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mIsActionItemsStale = true;
102023f4cc0353615107cc9c19fda9cf96ddd43266e2Adam Powell        onItemsChanged(true);
102196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
102296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
1023fa18d182a3f37505940e73ae6cd76c2e939f7f7cAdam Powell    public ArrayList<MenuItemImpl> getVisibleItems() {
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mIsVisibleItemsStale) return mVisibleItems;
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Refresh the visible items
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVisibleItems.clear();
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int itemsSize = mItems.size();
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MenuItemImpl item;
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < itemsSize; i++) {
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            item = mItems.get(i);
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.isVisible()) mVisibleItems.add(item);
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsVisibleItemsStale = false;
103796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mIsActionItemsStale = true;
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mVisibleItems;
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
104136fced9b211255e2137014e21fb3259042d8da85Adam Powell
104236fced9b211255e2137014e21fb3259042d8da85Adam Powell    /**
104336fced9b211255e2137014e21fb3259042d8da85Adam Powell     * This method determines which menu items get to be 'action items' that will appear
104436fced9b211255e2137014e21fb3259042d8da85Adam Powell     * in an action bar and which items should be 'overflow items' in a secondary menu.
104536fced9b211255e2137014e21fb3259042d8da85Adam Powell     * The rules are as follows:
104636fced9b211255e2137014e21fb3259042d8da85Adam Powell     *
104736fced9b211255e2137014e21fb3259042d8da85Adam Powell     * <p>Items are considered for inclusion in the order specified within the menu.
104836fced9b211255e2137014e21fb3259042d8da85Adam Powell     * There is a limit of mMaxActionItems as a total count, optionally including the overflow
104936fced9b211255e2137014e21fb3259042d8da85Adam Powell     * menu button itself. This is a soft limit; if an item shares a group ID with an item
105036fced9b211255e2137014e21fb3259042d8da85Adam Powell     * previously included as an action item, the new item will stay with its group and become
105136fced9b211255e2137014e21fb3259042d8da85Adam Powell     * an action item itself even if it breaks the max item count limit. This is done to
105236fced9b211255e2137014e21fb3259042d8da85Adam Powell     * limit the conceptual complexity of the items presented within an action bar. Only a few
105336fced9b211255e2137014e21fb3259042d8da85Adam Powell     * unrelated concepts should be presented to the user in this space, and groups are treated
105436fced9b211255e2137014e21fb3259042d8da85Adam Powell     * as a single concept.
105536fced9b211255e2137014e21fb3259042d8da85Adam Powell     *
105636fced9b211255e2137014e21fb3259042d8da85Adam Powell     * <p>There is also a hard limit of consumed measurable space: mActionWidthLimit. This
105736fced9b211255e2137014e21fb3259042d8da85Adam Powell     * limit may be broken by a single item that exceeds the remaining space, but no further
105836fced9b211255e2137014e21fb3259042d8da85Adam Powell     * items may be added. If an item that is part of a group cannot fit within the remaining
105936fced9b211255e2137014e21fb3259042d8da85Adam Powell     * measured width, the entire group will be demoted to overflow. This is done to ensure room
106036fced9b211255e2137014e21fb3259042d8da85Adam Powell     * for navigation and other affordances in the action bar as well as reduce general UI clutter.
106136fced9b211255e2137014e21fb3259042d8da85Adam Powell     *
106236fced9b211255e2137014e21fb3259042d8da85Adam Powell     * <p>The space freed by demoting a full group cannot be consumed by future menu items.
106336fced9b211255e2137014e21fb3259042d8da85Adam Powell     * Once items begin to overflow, all future items become overflow items as well. This is
106436fced9b211255e2137014e21fb3259042d8da85Adam Powell     * to avoid inadvertent reordering that may break the app's intended design.
106536fced9b211255e2137014e21fb3259042d8da85Adam Powell     */
1066696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void flagActionItems() {
1067da9710806bc7874b8c553f4daf9cf14f35ae1b07Adam Powell        // Important side effect: if getVisibleItems is stale it may refresh,
1068da9710806bc7874b8c553f4daf9cf14f35ae1b07Adam Powell        // which can affect action items staleness.
1069da9710806bc7874b8c553f4daf9cf14f35ae1b07Adam Powell        final ArrayList<MenuItemImpl> visibleItems = getVisibleItems();
1070da9710806bc7874b8c553f4daf9cf14f35ae1b07Adam Powell
107196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        if (!mIsActionItemsStale) {
107296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell            return;
107396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        }
10748028dd32a4a04154050220dd0693583d5b750330Adam Powell
1075696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        // Presenters flag action items as needed.
1076696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        boolean flagged = false;
1077696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
1078696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuPresenter presenter = ref.get();
1079696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (presenter == null) {
1080696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mPresenters.remove(ref);
10818028dd32a4a04154050220dd0693583d5b750330Adam Powell            } else {
1082696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                flagged |= presenter.flagActionItems();
108396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell            }
108496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        }
10858028dd32a4a04154050220dd0693583d5b750330Adam Powell
1086696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (flagged) {
1087696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mActionItems.clear();
1088696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mNonActionItems.clear();
1089696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final int itemsSize = visibleItems.size();
1090696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            for (int i = 0; i < itemsSize; i++) {
1091696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                MenuItemImpl item = visibleItems.get(i);
1092696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                if (item.isActionButton()) {
1093696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    mActionItems.add(item);
1094696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                } else {
1095696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    mNonActionItems.add(item);
109636fced9b211255e2137014e21fb3259042d8da85Adam Powell                }
109796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell            }
109804dc06f52a68299c0ad70fa0a9f204d99983ba2bAdam Powell        } else {
109904dc06f52a68299c0ad70fa0a9f204d99983ba2bAdam Powell            // Nobody flagged anything, everything is a non-action item.
1100696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            // (This happens during a first pass with no action-item presenters.)
1101696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mActionItems.clear();
1102696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mNonActionItems.clear();
1103696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mNonActionItems.addAll(getVisibleItems());
110496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        }
110596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mIsActionItemsStale = false;
110696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
110796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
1108fa18d182a3f37505940e73ae6cd76c2e939f7f7cAdam Powell    public ArrayList<MenuItemImpl> getActionItems() {
1109696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        flagActionItems();
111096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        return mActionItems;
111196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
111296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
1113fa18d182a3f37505940e73ae6cd76c2e939f7f7cAdam Powell    public ArrayList<MenuItemImpl> getNonActionItems() {
1114696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        flagActionItems();
111596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        return mNonActionItems;
111696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
111736fced9b211255e2137014e21fb3259042d8da85Adam Powell
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clearHeader() {
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderIcon = null;
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderTitle = null;
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderView = null;
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onItemsChanged(false);
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setHeaderInternal(final int titleRes, final CharSequence title, final int iconRes,
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Drawable icon, final View view) {
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Resources r = getResources();
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (view != null) {
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHeaderView = view;
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If using a custom view, then the title and icon aren't used
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHeaderTitle = null;
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHeaderIcon = null;
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (titleRes > 0) {
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHeaderTitle = r.getText(titleRes);
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (title != null) {
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHeaderTitle = title;
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (iconRes > 0) {
11448eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette                mHeaderIcon = getContext().getDrawable(iconRes);
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (icon != null) {
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHeaderIcon = icon;
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If using the title or icon, then a custom view isn't used
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHeaderView = null;
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Notify of change
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onItemsChanged(false);
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the header's title. This replaces the header view. Called by the
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * builder-style methods of subclasses.
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param title The new title.
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This MenuBuilder so additional setters can be called.
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected MenuBuilder setHeaderTitleInt(CharSequence title) {
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHeaderInternal(0, title, 0, null, null);
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the header's title. This replaces the header view. Called by the
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * builder-style methods of subclasses.
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param titleRes The new title (as a resource ID).
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This MenuBuilder so additional setters can be called.
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected MenuBuilder setHeaderTitleInt(int titleRes) {
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHeaderInternal(titleRes, null, 0, null, null);
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the header's icon. This replaces the header view. Called by the
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * builder-style methods of subclasses.
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param icon The new icon.
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This MenuBuilder so additional setters can be called.
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected MenuBuilder setHeaderIconInt(Drawable icon) {
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHeaderInternal(0, null, 0, icon, null);
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the header's icon. This replaces the header view. Called by the
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * builder-style methods of subclasses.
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param iconRes The new icon (as a resource ID).
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This MenuBuilder so additional setters can be called.
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected MenuBuilder setHeaderIconInt(int iconRes) {
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHeaderInternal(0, null, iconRes, null, null);
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the header's view. This replaces the title and icon. Called by the
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * builder-style methods of subclasses.
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view The new view.
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This MenuBuilder so additional setters can be called.
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected MenuBuilder setHeaderViewInt(View view) {
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHeaderInternal(0, null, 0, null, view);
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public CharSequence getHeaderTitle() {
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mHeaderTitle;
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable getHeaderIcon() {
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mHeaderIcon;
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public View getHeaderView() {
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mHeaderView;
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the root menu (if this is a submenu, find its root menu).
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The root menu.
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuBuilder getRootMenu() {
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the current menu info that is set on all items added to this menu
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (until this is called again with different menu info, in which case that
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * one will be added to all subsequent item additions).
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param menuInfo The extra menu information to add.
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setCurrentMenuInfo(ContextMenuInfo menuInfo) {
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurrentMenuInfo = menuInfo;
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setOptionalIconsVisible(boolean visible) {
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOptionalIconsVisible = visible;
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean getOptionalIconsVisible() {
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mOptionalIconsVisible;
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12558d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12568d02deabac62c4a68a335a7b3141795466362b89Adam Powell    public boolean expandItemActionView(MenuItemImpl item) {
12578d02deabac62c4a68a335a7b3141795466362b89Adam Powell        if (mPresenters.isEmpty()) return false;
12588d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12598d02deabac62c4a68a335a7b3141795466362b89Adam Powell        boolean expanded = false;
12608d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12618d02deabac62c4a68a335a7b3141795466362b89Adam Powell        stopDispatchingItemsChanged();
12628d02deabac62c4a68a335a7b3141795466362b89Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
12638d02deabac62c4a68a335a7b3141795466362b89Adam Powell            final MenuPresenter presenter = ref.get();
12648d02deabac62c4a68a335a7b3141795466362b89Adam Powell            if (presenter == null) {
12658d02deabac62c4a68a335a7b3141795466362b89Adam Powell                mPresenters.remove(ref);
12668d02deabac62c4a68a335a7b3141795466362b89Adam Powell            } else if ((expanded = presenter.expandItemActionView(this, item))) {
12678d02deabac62c4a68a335a7b3141795466362b89Adam Powell                break;
12688d02deabac62c4a68a335a7b3141795466362b89Adam Powell            }
12698d02deabac62c4a68a335a7b3141795466362b89Adam Powell        }
12708d02deabac62c4a68a335a7b3141795466362b89Adam Powell        startDispatchingItemsChanged();
12718d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12726b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell        if (expanded) {
12736b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell            mExpandedItem = item;
12746b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell        }
12758d02deabac62c4a68a335a7b3141795466362b89Adam Powell        return expanded;
12768d02deabac62c4a68a335a7b3141795466362b89Adam Powell    }
12778d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12788d02deabac62c4a68a335a7b3141795466362b89Adam Powell    public boolean collapseItemActionView(MenuItemImpl item) {
12796b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell        if (mPresenters.isEmpty() || mExpandedItem != item) return false;
12808d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12818d02deabac62c4a68a335a7b3141795466362b89Adam Powell        boolean collapsed = false;
12828d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12838d02deabac62c4a68a335a7b3141795466362b89Adam Powell        stopDispatchingItemsChanged();
12848d02deabac62c4a68a335a7b3141795466362b89Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
12858d02deabac62c4a68a335a7b3141795466362b89Adam Powell            final MenuPresenter presenter = ref.get();
12868d02deabac62c4a68a335a7b3141795466362b89Adam Powell            if (presenter == null) {
12878d02deabac62c4a68a335a7b3141795466362b89Adam Powell                mPresenters.remove(ref);
12888d02deabac62c4a68a335a7b3141795466362b89Adam Powell            } else if ((collapsed = presenter.collapseItemActionView(this, item))) {
12898d02deabac62c4a68a335a7b3141795466362b89Adam Powell                break;
12908d02deabac62c4a68a335a7b3141795466362b89Adam Powell            }
12918d02deabac62c4a68a335a7b3141795466362b89Adam Powell        }
12928d02deabac62c4a68a335a7b3141795466362b89Adam Powell        startDispatchingItemsChanged();
12938d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12946b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell        if (collapsed) {
12956b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell            mExpandedItem = null;
12966b0e97c7c48cf9446c7d4bc1b37d4c37d78433b0Adam Powell        }
12978d02deabac62c4a68a335a7b3141795466362b89Adam Powell        return collapsed;
12988d02deabac62c4a68a335a7b3141795466362b89Adam Powell    }
1299275702c2f47ed87ab642462530092d9777f32ecdAdam Powell
1300275702c2f47ed87ab642462530092d9777f32ecdAdam Powell    public MenuItemImpl getExpandedItem() {
1301275702c2f47ed87ab642462530092d9777f32ecdAdam Powell        return mExpandedItem;
1302275702c2f47ed87ab642462530092d9777f32ecdAdam Powell    }
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1304