MenuBuilder.java revision 038f1c80af06da55056120e121d43e3ee89ec726
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 {
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String LOGTAG = "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>>();
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
155696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Called by menu to notify of close and selection changes.
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface Callback {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Called when a menu item is selected.
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param menu The menu that is the parent of the item
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param item The menu item that is selected
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return whether the menu item selection was handled
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Called when the mode of the menu changes (for example, from icon to expanded).
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param menu the menu that has changed modes
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onMenuModeChange(MenuBuilder menu);
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Called by menu items to execute their associated action
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface ItemInvoker {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean invokeItem(MenuItemImpl item);
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuBuilder(Context context) {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mResources = context.getResources();
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItems = new ArrayList<MenuItemImpl>();
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVisibleItems = new ArrayList<MenuItemImpl>();
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsVisibleItemsStale = true;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mActionItems = new ArrayList<MenuItemImpl>();
19196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mNonActionItems = new ArrayList<MenuItemImpl>();
19296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mIsActionItemsStale = true;
19396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
1944aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown        setShortcutsVisibleInner(true);
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1974d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell    public MenuBuilder setDefaultShowAsAction(int defaultShowAsAction) {
1984d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell        mDefaultShowAsAction = defaultShowAsAction;
1994d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell        return this;
2004d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell    }
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
202696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
203696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Add a presenter to this menu. This will only hold a WeakReference;
204696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * you do not need to explicitly remove a presenter, but you can using
205696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * {@link #removeMenuPresenter(MenuPresenter)}.
206696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     *
207696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @param presenter The presenter to add
208696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
209696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void addMenuPresenter(MenuPresenter presenter) {
210696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mPresenters.add(new WeakReference<MenuPresenter>(presenter));
211696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        presenter.initForMenu(mContext, this);
212696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mIsActionItemsStale = true;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
214696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
216696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Remove a presenter from this menu. That presenter will no longer
217696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * receive notifications of updates to this menu's data.
218696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     *
219696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @param presenter The presenter to remove
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
221696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void removeMenuPresenter(MenuPresenter presenter) {
222696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
223696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuPresenter item = ref.get();
224696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (item == null || item == presenter) {
225696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mPresenters.remove(ref);
226696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
230696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private void dispatchPresenterUpdate(boolean cleared) {
231696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mPresenters.isEmpty()) return;
232696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
233640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        stopDispatchingItemsChanged();
234696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
235696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuPresenter presenter = ref.get();
236696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (presenter == null) {
237696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mPresenters.remove(ref);
238696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            } else {
239696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                presenter.updateMenuView(cleared);
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
242640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell        startDispatchingItemsChanged();
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
245696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu) {
246696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mPresenters.isEmpty()) return false;
247696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
248696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        boolean result = false;
249696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
250696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
251696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuPresenter presenter = ref.get();
252696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (presenter == null) {
253696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mPresenters.remove(ref);
254696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            } else if (!result) {
255696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                result = presenter.onSubMenuSelected(subMenu);
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
258696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return result;
259696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
260696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
26111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    private void dispatchSaveInstanceState(Bundle outState) {
26211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        if (mPresenters.isEmpty()) return;
26311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
26411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        SparseArray<Parcelable> presenterStates = new SparseArray<Parcelable>();
26511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
26611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
26711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            final MenuPresenter presenter = ref.get();
26811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            if (presenter == null) {
26911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                mPresenters.remove(ref);
27011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            } else {
27111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                final int id = presenter.getId();
27211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                if (id > 0) {
27311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    final Parcelable state = presenter.onSaveInstanceState();
27411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    if (state != null) {
27511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                        presenterStates.put(id, state);
27611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    }
27711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                }
27811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            }
27911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
28011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
28111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        outState.putSparseParcelableArray(PRESENTER_KEY, presenterStates);
28211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
28311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
28411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    private void dispatchRestoreInstanceState(Bundle state) {
28511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        SparseArray<Parcelable> presenterStates = state.getSparseParcelableArray(PRESENTER_KEY);
28611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
28711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        if (presenterStates == null || mPresenters.isEmpty()) return;
28811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
28911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
29011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            final MenuPresenter presenter = ref.get();
29111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            if (presenter == null) {
29211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                mPresenters.remove(ref);
29311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            } else {
29411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                final int id = presenter.getId();
29511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                if (id > 0) {
29611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    Parcelable parcel = presenterStates.get(id);
29711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    if (parcel != null) {
29811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                        presenter.onRestoreInstanceState(parcel);
29911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                    }
30011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell                }
30111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell            }
30211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        }
30311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
30411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
30511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    public void savePresenterStates(Bundle outState) {
30611ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        dispatchSaveInstanceState(outState);
30711ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
30811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
30911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    public void restorePresenterStates(Bundle state) {
31011ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell        dispatchRestoreInstanceState(state);
31111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell    }
31211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell
313038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    public void saveActionViewStates(Bundle outStates) {
314038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        SparseArray<Parcelable> viewStates = null;
315038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
316038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        final int itemCount = size();
317038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        for (int i = 0; i < itemCount; i++) {
318038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            final MenuItem item = getItem(i);
319038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            final View v = item.getActionView();
320038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            if (v != null && v.getId() != View.NO_ID) {
321038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                if (viewStates == null) {
322038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                    viewStates = new SparseArray<Parcelable>();
323038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                }
324038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                v.saveHierarchyState(viewStates);
325038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                if (item.isActionViewExpanded()) {
326038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                    outStates.putInt(EXPANDED_ACTION_VIEW_ID, item.getItemId());
327038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                }
328038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            }
329038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            if (item.hasSubMenu()) {
330038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
331038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                subMenu.saveActionViewStates(outStates);
332038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            }
333038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        }
334038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
335038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        if (viewStates != null) {
336038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            outStates.putSparseParcelableArray(getActionViewStatesKey(), viewStates);
337038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        }
338038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    }
339038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
340038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    public void restoreActionViewStates(Bundle states) {
341038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        if (states == null) {
342038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            return;
343038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        }
344038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
345038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        SparseArray<Parcelable> viewStates = states.getSparseParcelableArray(
346038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                getActionViewStatesKey());
347038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
348038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        final int itemCount = size();
349038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        for (int i = 0; i < itemCount; i++) {
350038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            final MenuItem item = getItem(i);
351038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            final View v = item.getActionView();
352038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            if (v != null && v.getId() != View.NO_ID) {
353038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                v.restoreHierarchyState(viewStates);
354038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            }
355038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            if (item.hasSubMenu()) {
356038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
357038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                subMenu.restoreActionViewStates(states);
358038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            }
359038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        }
360038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
361038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        final int expandedId = states.getInt(EXPANDED_ACTION_VIEW_ID);
362038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        if (expandedId > 0) {
363038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            MenuItem itemToExpand = findItem(expandedId);
364038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            if (itemToExpand != null) {
365038f1c80af06da55056120e121d43e3ee89ec726Adam Powell                itemToExpand.expandActionView();
366038f1c80af06da55056120e121d43e3ee89ec726Adam Powell            }
367038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        }
368038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    }
369038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
370038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    protected String getActionViewStatesKey() {
371038f1c80af06da55056120e121d43e3ee89ec726Adam Powell        return ACTION_VIEW_STATES_KEY;
372038f1c80af06da55056120e121d43e3ee89ec726Adam Powell    }
373038f1c80af06da55056120e121d43e3ee89ec726Adam Powell
374696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void setCallback(Callback cb) {
375696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mCallback = cb;
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Adds an item to the menu.  The other add methods funnel to this.
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int ordering = getOrdering(categoryOrder);
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3844d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell        final MenuItemImpl item = new MenuItemImpl(this, group, id, categoryOrder,
3854d9861e7ec8488634d316b20981464de2ab7b6feAdam Powell                ordering, title, mDefaultShowAsAction);
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurrentMenuInfo != null) {
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Pass along the current menu info
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            item.setMenuInfo(mCurrentMenuInfo);
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItems.add(findInsertIndex(mItems, ordering), item);
393696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        onItemsChanged(true);
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return item;
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem add(CharSequence title) {
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addInternal(0, 0, 0, title);
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem add(int titleRes) {
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addInternal(0, 0, 0, mResources.getString(titleRes));
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem add(int group, int id, int categoryOrder, CharSequence title) {
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addInternal(group, id, categoryOrder, title);
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem add(int group, int id, int categoryOrder, int title) {
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addInternal(group, id, categoryOrder, mResources.getString(title));
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SubMenu addSubMenu(CharSequence title) {
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addSubMenu(0, 0, 0, title);
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SubMenu addSubMenu(int titleRes) {
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addSubMenu(0, 0, 0, mResources.getString(titleRes));
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SubMenu addSubMenu(int group, int id, int categoryOrder, CharSequence title) {
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final MenuItemImpl item = (MenuItemImpl) addInternal(group, id, categoryOrder, title);
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final SubMenuBuilder subMenu = new SubMenuBuilder(mContext, this, item);
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        item.setSubMenu(subMenu);
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return subMenu;
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SubMenu addSubMenu(int group, int id, int categoryOrder, int title) {
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return addSubMenu(group, id, categoryOrder, mResources.getString(title));
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int addIntentOptions(int group, int id, int categoryOrder, ComponentName caller,
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PackageManager pm = mContext.getPackageManager();
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final List<ResolveInfo> lri =
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pm.queryIntentActivityOptions(caller, specifics, intent, 0);
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = lri != null ? lri.size() : 0;
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags & FLAG_APPEND_TO_GROUP) == 0) {
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeGroup(group);
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i=0; i<N; i++) {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final ResolveInfo ri = lri.get(i);
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent rintent = new Intent(
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]);
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rintent.setComponent(new ComponentName(
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ri.activityInfo.applicationInfo.packageName,
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ri.activityInfo.name));
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final MenuItem item = add(group, id, categoryOrder, ri.loadLabel(pm))
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .setIcon(ri.loadIcon(pm))
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .setIntent(rintent);
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (outSpecificItems != null && ri.specificIndex >= 0) {
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                outSpecificItems[ri.specificIndex] = item;
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return N;
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeItem(int id) {
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        removeItemAtInt(findItemIndex(id), true);
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeGroup(int group) {
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int i = findGroupIndex(group);
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (i >= 0) {
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int maxRemovable = mItems.size() - i;
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int numRemoved = 0;
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while ((numRemoved++ < maxRemovable) && (mItems.get(i).getGroupId() == group)) {
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Don't force update for each one, this method will do it at the end
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                removeItemAtInt(i, false);
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Notify menu views
479696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            onItemsChanged(true);
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Remove the item at the given index and optionally forces menu views to
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * update.
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index The index of the item to be removed. If this index is
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            invalid an exception is thrown.
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param updateChildrenOnMenuViews Whether to force update on menu views.
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            Please make sure you eventually call this after your batch of
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            removals.
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void removeItemAtInt(int index, boolean updateChildrenOnMenuViews) {
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((index < 0) || (index >= mItems.size())) return;
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItems.remove(index);
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
498696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (updateChildrenOnMenuViews) onItemsChanged(true);
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeItemAt(int index) {
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        removeItemAtInt(index, true);
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clearAll() {
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPreventDispatchingItemsChanged = true;
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        clear();
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        clearHeader();
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPreventDispatchingItemsChanged = false;
510696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mItemsChangedWhileDispatchPrevented = false;
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onItemsChanged(true);
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clear() {
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItems.clear();
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onItemsChanged(true);
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setExclusiveItemChecked(MenuItem item) {
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int group = item.getGroupId();
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mItems.size();
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl curItem = mItems.get(i);
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (curItem.getGroupId() == group) {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!curItem.isExclusiveCheckable()) continue;
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!curItem.isCheckable()) continue;
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Check the item meant to be checked, uncheck the others (that are in the group)
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                curItem.setCheckedInt(curItem == item);
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mItems.size();
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getGroupId() == group) {
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                item.setExclusiveCheckable(exclusive);
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                item.setCheckable(checkable);
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGroupVisible(int group, boolean visible) {
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mItems.size();
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // We handle the notification of items being changed ourselves, so we use setVisibleInt rather
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // than setVisible and at the end notify of items being changed
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean changedAtLeastOneItem = false;
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getGroupId() == group) {
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (item.setVisibleInt(visible)) changedAtLeastOneItem = true;
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (changedAtLeastOneItem) onItemsChanged(false);
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGroupEnabled(int group, boolean enabled) {
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mItems.size();
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getGroupId() == group) {
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                item.setEnabled(enabled);
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean hasVisibleItems() {
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int size = size();
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < size; i++) {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.isVisible()) {
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem findItem(int id) {
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int size = size();
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < size; i++) {
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getItemId() == id) {
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return item;
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (item.hasSubMenu()) {
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                MenuItem possibleItem = item.getSubMenu().findItem(id);
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (possibleItem != null) {
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return possibleItem;
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int findItemIndex(int id) {
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int size = size();
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < size; i++) {
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getItemId() == id) {
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return i;
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int findGroupIndex(int group) {
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return findGroupIndex(group, 0);
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int findGroupIndex(int group, int start) {
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int size = size();
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (start < 0) {
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            start = 0;
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = start; i < size; i++) {
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final MenuItemImpl item = mItems.get(i);
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getGroupId() == group) {
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return i;
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int size() {
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mItems.size();
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** {@inheritDoc} */
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuItem getItem(int index) {
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mItems.get(index);
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isShortcutKey(int keyCode, KeyEvent event) {
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return findItemWithShortcutForKey(keyCode, event) != null;
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setQwertyMode(boolean isQwerty) {
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mQwertyMode = isQwerty;
657696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
658696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        onItemsChanged(false);
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the ordering across all items. This will grab the category from
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the upper bits, find out how to order the category with respect to other
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * categories, and combine it with the lower bits.
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param categoryOrder The category order for a particular item (if it has
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            not been or/add with a category, the default category is
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            assumed).
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return An ordering integer that can be used to order this item across
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         all the items (even from other categories).
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
672696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    private static int getOrdering(int categoryOrder) {
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int index = (categoryOrder & CATEGORY_MASK) >> CATEGORY_SHIFT;
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (index < 0 || index >= sCategoryToOrder.length) {
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("order does not contain a valid category.");
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (sCategoryToOrder[index] << CATEGORY_SHIFT) | (categoryOrder & USER_MASK);
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return whether the menu shortcuts are in qwerty mode or not
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean isQwertyMode() {
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mQwertyMode;
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets whether the shortcuts should be visible on menus.  Devices without hardware
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * key input will never make shortcuts visible even if this method is passed 'true'.
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param shortcutsVisible Whether shortcuts should be visible (if true and a
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            menu item does not have a shortcut defined, that item will
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            still NOT show a shortcut)
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setShortcutsVisible(boolean shortcutsVisible) {
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShortcutsVisible == shortcutsVisible) return;
6994aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown
7004aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown        setShortcutsVisibleInner(shortcutsVisible);
701696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        onItemsChanged(false);
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7044aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown    private void setShortcutsVisibleInner(boolean shortcutsVisible) {
7054aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown        mShortcutsVisible = shortcutsVisible
7064aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown                && mResources.getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS
7074aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown                && mResources.getBoolean(
7084aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown                        com.android.internal.R.bool.config_showMenuShortcutsWhenKeyboardPresent);
7094aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown    }
7104aed78b5056560f499e5953f659fa90a06ecc38aJeff Brown
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether shortcuts should be visible on menus.
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isShortcutsVisible() {
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mShortcutsVisible;
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Resources getResources() {
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mResources;
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Context getContext() {
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mContext;
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
726696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    boolean dispatchMenuItemSelected(MenuBuilder menu, MenuItem item) {
727696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return mCallback != null && mCallback.onMenuItemSelected(menu, item);
728696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
729696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
730696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
731696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Dispatch a mode change event to this menu's callback.
732696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
733696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void changeMenuMode() {
734696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mCallback != null) {
735696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mCallback.onMenuModeChange(this);
736696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
737696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
738696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static int findInsertIndex(ArrayList<MenuItemImpl> items, int ordering) {
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = items.size() - 1; i >= 0; i--) {
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = items.get(i);
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.getOrdering() <= ordering) {
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return i + 1;
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final MenuItemImpl item = findItemWithShortcutForKey(keyCode, event);
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = false;
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (item != null) {
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handled = performItemAction(item, flags);
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags & FLAG_ALWAYS_PERFORM_CLOSE) != 0) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            close(true);
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return handled;
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
766e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard    /*
767e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * This function will return all the menu and sub-menu items that can
768e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * be directly (the shortcut directly corresponds) and indirectly
769e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * (the ALT-enabled char corresponds to the shortcut) associated
770e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * with the keyCode.
771e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     */
772696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    void findItemsWithShortcutForKey(List<MenuItemImpl> items, int keyCode, KeyEvent event) {
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean qwerty = isQwertyMode();
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int metaState = event.getMetaState();
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData();
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Get the chars associated with the keyCode (i.e using any chording combo)
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean isKeyCodeMapped = event.getKeyData(possibleChars);
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // The delete key is not mapped to '\b' so we treat it specially
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!isKeyCodeMapped && (keyCode != KeyEvent.KEYCODE_DEL)) {
780696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            return;
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Look for an item whose shortcut is this key.
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mItems.size();
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < N; i++) {
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MenuItemImpl item = mItems.get(i);
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.hasSubMenu()) {
788696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                ((MenuBuilder)item.getSubMenu()).findItemsWithShortcutForKey(items, keyCode, event);
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
790e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut();
791e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) &&
792e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                  (shortcutChar != 0) &&
793e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                  (shortcutChar == possibleChars.meta[0]
794e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                      || shortcutChar == possibleChars.meta[2]
795e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                      || (qwerty && shortcutChar == '\b' &&
796e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                          keyCode == KeyEvent.KEYCODE_DEL)) &&
797e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                  item.isEnabled()) {
798e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                items.add(item);
799e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            }
800e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        }
801e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard    }
802e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
803e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard    /*
804e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * We want to return the menu item associated with the key, but if there is no
805e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * ambiguity (i.e. there is only one menu item corresponding to the key) we want
806e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * to return it even if it's not an exact match; this allow the user to
807e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * _not_ use the ALT key for example, making the use of shortcuts slightly more
808e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * user-friendly. An example is on the G1, '!' and '1' are on the same key, and
809e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * in Gmail, Menu+1 will trigger Menu+! (the actual shortcut).
810e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     *
811e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * On the other hand, if two (or more) shortcuts corresponds to the same key,
812e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     * we have to only return the exact match.
813e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard     */
814e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard    MenuItemImpl findItemWithShortcutForKey(int keyCode, KeyEvent event) {
815e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        // Get all items that can be associated directly or indirectly with the keyCode
816696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        ArrayList<MenuItemImpl> items = mTempShortcutItemList;
817696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        items.clear();
818696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        findItemsWithShortcutForKey(items, keyCode, event);
819e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
820696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (items.isEmpty()) {
821e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            return null;
822e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        }
823e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
824e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        final int metaState = event.getMetaState();
825e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData();
826e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        // Get the chars associated with the keyCode (i.e using any chording combo)
827e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        event.getKeyData(possibleChars);
828e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
829e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        // If we have only one element, we can safely returns it
830696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        final int size = items.size();
831696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (size == 1) {
832e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            return items.get(0);
833e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        }
834e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
835e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        final boolean qwerty = isQwertyMode();
836e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        // If we found more than one item associated with the key,
837e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard        // we have to return the exact match
838696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (int i = 0; i < size; i++) {
839696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuItemImpl item = items.get(i);
840696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final char shortcutChar = qwerty ? item.getAlphabeticShortcut() :
841696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    item.getNumericShortcut();
842e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard            if ((shortcutChar == possibleChars.meta[0] &&
843e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                    (metaState & KeyEvent.META_ALT_ON) == 0)
844e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                || (shortcutChar == possibleChars.meta[2] &&
845e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                    (metaState & KeyEvent.META_ALT_ON) != 0)
846e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                || (qwerty && shortcutChar == '\b' &&
847e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                    keyCode == KeyEvent.KEYCODE_DEL)) {
848e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard                return item;
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
853e0fc838ebc18e327a399902cacae16bdbbc09627Nicolas Roard
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performIdentifierAction(int id, int flags) {
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Look for an item whose identifier is the id.
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return performItemAction(findItem(id), flags);
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performItemAction(MenuItem item, int flags) {
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MenuItemImpl itemImpl = (MenuItemImpl) item;
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (itemImpl == null || !itemImpl.isEnabled()) {
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8648d02deabac62c4a68a335a7b3141795466362b89Adam Powell        }
86576559a65ad9d644f10beacf8895ceb217fdd0aebSvetoslav Ganov
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean invoked = itemImpl.invoke();
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8688d02deabac62c4a68a335a7b3141795466362b89Adam Powell        if (itemImpl.hasCollapsibleActionView()) {
8698d02deabac62c4a68a335a7b3141795466362b89Adam Powell            invoked |= itemImpl.expandActionView();
8708d02deabac62c4a68a335a7b3141795466362b89Adam Powell            if (invoked) close(true);
8718d02deabac62c4a68a335a7b3141795466362b89Adam Powell        } else if (item.hasSubMenu()) {
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            close(false);
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
874961dd11895ce72e59bca124ef5bea4e4c1183099Adam Powell            final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
875961dd11895ce72e59bca124ef5bea4e4c1183099Adam Powell            final ActionProvider provider = item.getActionProvider();
876961dd11895ce72e59bca124ef5bea4e4c1183099Adam Powell            if (provider != null && provider.hasSubMenu()) {
877961dd11895ce72e59bca124ef5bea4e4c1183099Adam Powell                provider.onPrepareSubMenu(subMenu);
878961dd11895ce72e59bca124ef5bea4e4c1183099Adam Powell            }
879961dd11895ce72e59bca124ef5bea4e4c1183099Adam Powell            invoked |= dispatchSubMenuSelected(subMenu);
880696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (!invoked) close(true);
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((flags & FLAG_PERFORM_NO_CLOSE) == 0) {
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                close(true);
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return invoked;
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Closes the visible menu.
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param allMenusAreClosing Whether the menus are completely closing (true),
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            or whether there is another menu coming in this menu's place
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            (false). For example, if the menu is closing because a
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            sub menu is about to be shown, <var>allMenusAreClosing</var>
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            is false.
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final void close(boolean allMenusAreClosing) {
900696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mIsClosing) return;
901696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
902696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mIsClosing = true;
903696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
904696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuPresenter presenter = ref.get();
905696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (presenter == null) {
906696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mPresenters.remove(ref);
907696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            } else {
908696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                presenter.onCloseMenu(this, allMenusAreClosing);
909696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
911696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mIsClosing = false;
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** {@inheritDoc} */
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void close() {
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        close(true);
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Called when an item is added or removed.
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
922696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * @param structureChanged true if the menu structure changed,
923696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     *                         false if only item properties changed.
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
925696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    void onItemsChanged(boolean structureChanged) {
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mPreventDispatchingItemsChanged) {
927696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (structureChanged) {
928696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mIsVisibleItemsStale = true;
929696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mIsActionItemsStale = true;
930696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            }
9311821ff9022f0ea5f5c5d82a96a05f46192d50c26Adam Powell
932696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            dispatchPresenterUpdate(structureChanged);
933696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        } else {
934696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mItemsChangedWhileDispatchPrevented = true;
935696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        }
936696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
9371821ff9022f0ea5f5c5d82a96a05f46192d50c26Adam Powell
938696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    /**
939696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * Stop dispatching item changed events to presenters until
940696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * {@link #startDispatchingItemsChanged()} is called. Useful when
941696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     * many menu operations are going to be performed as a batch.
942696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell     */
943696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void stopDispatchingItemsChanged() {
944a86b350977be53146d568bc0736d0f2b4aef8de5Adam Powell        if (!mPreventDispatchingItemsChanged) {
945a86b350977be53146d568bc0736d0f2b4aef8de5Adam Powell            mPreventDispatchingItemsChanged = true;
946a86b350977be53146d568bc0736d0f2b4aef8de5Adam Powell            mItemsChangedWhileDispatchPrevented = false;
947a86b350977be53146d568bc0736d0f2b4aef8de5Adam Powell        }
948696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
949696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
950696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void startDispatchingItemsChanged() {
951696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mPreventDispatchingItemsChanged = false;
952696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
953696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (mItemsChangedWhileDispatchPrevented) {
954696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mItemsChangedWhileDispatchPrevented = false;
955696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            onItemsChanged(true);
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Called by {@link MenuItemImpl} when its visible flag is changed.
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param item The item that has gone through a visibility change.
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void onItemVisibleChanged(MenuItemImpl item) {
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Notify of items being changed
965696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mIsVisibleItemsStale = true;
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onItemsChanged(false);
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
96996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    /**
97096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     * Called by {@link MenuItemImpl} when its action request status is changed.
97196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     * @param item The item that has gone through a change in action request status.
97296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell     */
97396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    void onItemActionRequestChanged(MenuItemImpl item) {
97496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        // Notify of items being changed
975696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mIsActionItemsStale = true;
97696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        onItemsChanged(false);
97796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
97896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ArrayList<MenuItemImpl> getVisibleItems() {
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mIsVisibleItemsStale) return mVisibleItems;
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Refresh the visible items
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVisibleItems.clear();
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int itemsSize = mItems.size();
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MenuItemImpl item;
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < itemsSize; i++) {
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            item = mItems.get(i);
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (item.isVisible()) mVisibleItems.add(item);
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsVisibleItemsStale = false;
99396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mIsActionItemsStale = true;
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mVisibleItems;
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
99736fced9b211255e2137014e21fb3259042d8da85Adam Powell
99836fced9b211255e2137014e21fb3259042d8da85Adam Powell    /**
99936fced9b211255e2137014e21fb3259042d8da85Adam Powell     * This method determines which menu items get to be 'action items' that will appear
100036fced9b211255e2137014e21fb3259042d8da85Adam Powell     * in an action bar and which items should be 'overflow items' in a secondary menu.
100136fced9b211255e2137014e21fb3259042d8da85Adam Powell     * The rules are as follows:
100236fced9b211255e2137014e21fb3259042d8da85Adam Powell     *
100336fced9b211255e2137014e21fb3259042d8da85Adam Powell     * <p>Items are considered for inclusion in the order specified within the menu.
100436fced9b211255e2137014e21fb3259042d8da85Adam Powell     * There is a limit of mMaxActionItems as a total count, optionally including the overflow
100536fced9b211255e2137014e21fb3259042d8da85Adam Powell     * menu button itself. This is a soft limit; if an item shares a group ID with an item
100636fced9b211255e2137014e21fb3259042d8da85Adam Powell     * previously included as an action item, the new item will stay with its group and become
100736fced9b211255e2137014e21fb3259042d8da85Adam Powell     * an action item itself even if it breaks the max item count limit. This is done to
100836fced9b211255e2137014e21fb3259042d8da85Adam Powell     * limit the conceptual complexity of the items presented within an action bar. Only a few
100936fced9b211255e2137014e21fb3259042d8da85Adam Powell     * unrelated concepts should be presented to the user in this space, and groups are treated
101036fced9b211255e2137014e21fb3259042d8da85Adam Powell     * as a single concept.
101136fced9b211255e2137014e21fb3259042d8da85Adam Powell     *
101236fced9b211255e2137014e21fb3259042d8da85Adam Powell     * <p>There is also a hard limit of consumed measurable space: mActionWidthLimit. This
101336fced9b211255e2137014e21fb3259042d8da85Adam Powell     * limit may be broken by a single item that exceeds the remaining space, but no further
101436fced9b211255e2137014e21fb3259042d8da85Adam Powell     * items may be added. If an item that is part of a group cannot fit within the remaining
101536fced9b211255e2137014e21fb3259042d8da85Adam Powell     * measured width, the entire group will be demoted to overflow. This is done to ensure room
101636fced9b211255e2137014e21fb3259042d8da85Adam Powell     * for navigation and other affordances in the action bar as well as reduce general UI clutter.
101736fced9b211255e2137014e21fb3259042d8da85Adam Powell     *
101836fced9b211255e2137014e21fb3259042d8da85Adam Powell     * <p>The space freed by demoting a full group cannot be consumed by future menu items.
101936fced9b211255e2137014e21fb3259042d8da85Adam Powell     * Once items begin to overflow, all future items become overflow items as well. This is
102036fced9b211255e2137014e21fb3259042d8da85Adam Powell     * to avoid inadvertent reordering that may break the app's intended design.
102136fced9b211255e2137014e21fb3259042d8da85Adam Powell     */
1022696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void flagActionItems() {
102396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        if (!mIsActionItemsStale) {
102496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell            return;
102596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        }
10268028dd32a4a04154050220dd0693583d5b750330Adam Powell
1027696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        // Presenters flag action items as needed.
1028696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        boolean flagged = false;
1029696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
1030696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final MenuPresenter presenter = ref.get();
1031696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            if (presenter == null) {
1032696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mPresenters.remove(ref);
10338028dd32a4a04154050220dd0693583d5b750330Adam Powell            } else {
1034696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                flagged |= presenter.flagActionItems();
103596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell            }
103696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        }
10378028dd32a4a04154050220dd0693583d5b750330Adam Powell
1038696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        if (flagged) {
1039696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mActionItems.clear();
1040696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mNonActionItems.clear();
1041696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            ArrayList<MenuItemImpl> visibleItems = getVisibleItems();
1042696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            final int itemsSize = visibleItems.size();
1043696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            for (int i = 0; i < itemsSize; i++) {
1044696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                MenuItemImpl item = visibleItems.get(i);
1045696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                if (item.isActionButton()) {
1046696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    mActionItems.add(item);
1047696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                } else {
1048696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    mNonActionItems.add(item);
104936fced9b211255e2137014e21fb3259042d8da85Adam Powell                }
105096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell            }
1051696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        } else if (mActionItems.size() + mNonActionItems.size() != getVisibleItems().size()) {
1052696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            // Nobody flagged anything, but if something doesn't add up then treat everything
1053696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            // as non-action items.
1054696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            // (This happens during a first pass with no action-item presenters.)
1055696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mActionItems.clear();
1056696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mNonActionItems.clear();
1057696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell            mNonActionItems.addAll(getVisibleItems());
105896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        }
105996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mIsActionItemsStale = false;
106096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
106196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
1062696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    ArrayList<MenuItemImpl> getActionItems() {
1063696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        flagActionItems();
106496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        return mActionItems;
106596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
106696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
1067696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    ArrayList<MenuItemImpl> getNonActionItems() {
1068696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        flagActionItems();
106996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        return mNonActionItems;
107096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
107136fced9b211255e2137014e21fb3259042d8da85Adam Powell
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clearHeader() {
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderIcon = null;
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderTitle = null;
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHeaderView = null;
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onItemsChanged(false);
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setHeaderInternal(final int titleRes, final CharSequence title, final int iconRes,
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Drawable icon, final View view) {
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Resources r = getResources();
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (view != null) {
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHeaderView = view;
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If using a custom view, then the title and icon aren't used
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHeaderTitle = null;
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHeaderIcon = null;
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (titleRes > 0) {
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHeaderTitle = r.getText(titleRes);
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (title != null) {
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHeaderTitle = title;
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (iconRes > 0) {
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHeaderIcon = r.getDrawable(iconRes);
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (icon != null) {
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHeaderIcon = icon;
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If using the title or icon, then a custom view isn't used
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHeaderView = null;
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Notify of change
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onItemsChanged(false);
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the header's title. This replaces the header view. Called by the
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * builder-style methods of subclasses.
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param title The new title.
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This MenuBuilder so additional setters can be called.
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected MenuBuilder setHeaderTitleInt(CharSequence title) {
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHeaderInternal(0, title, 0, null, null);
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the header's title. This replaces the header view. Called by the
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * builder-style methods of subclasses.
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param titleRes The new title (as a resource ID).
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This MenuBuilder so additional setters can be called.
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected MenuBuilder setHeaderTitleInt(int titleRes) {
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHeaderInternal(titleRes, null, 0, null, null);
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the header's icon. This replaces the header view. Called by the
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * builder-style methods of subclasses.
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param icon The new icon.
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This MenuBuilder so additional setters can be called.
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected MenuBuilder setHeaderIconInt(Drawable icon) {
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHeaderInternal(0, null, 0, icon, null);
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the header's icon. This replaces the header view. Called by the
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * builder-style methods of subclasses.
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param iconRes The new icon (as a resource ID).
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This MenuBuilder so additional setters can be called.
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected MenuBuilder setHeaderIconInt(int iconRes) {
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHeaderInternal(0, null, iconRes, null, null);
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the header's view. This replaces the title and icon. Called by the
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * builder-style methods of subclasses.
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view The new view.
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return This MenuBuilder so additional setters can be called.
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected MenuBuilder setHeaderViewInt(View view) {
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setHeaderInternal(0, null, 0, null, view);
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public CharSequence getHeaderTitle() {
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mHeaderTitle;
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable getHeaderIcon() {
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mHeaderIcon;
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public View getHeaderView() {
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mHeaderView;
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the root menu (if this is a submenu, find its root menu).
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The root menu.
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MenuBuilder getRootMenu() {
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the current menu info that is set on all items added to this menu
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (until this is called again with different menu info, in which case that
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * one will be added to all subsequent item additions).
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param menuInfo The extra menu information to add.
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setCurrentMenuInfo(ContextMenuInfo menuInfo) {
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurrentMenuInfo = menuInfo;
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setOptionalIconsVisible(boolean visible) {
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOptionalIconsVisible = visible;
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean getOptionalIconsVisible() {
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mOptionalIconsVisible;
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12098d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12108d02deabac62c4a68a335a7b3141795466362b89Adam Powell    public boolean expandItemActionView(MenuItemImpl item) {
12118d02deabac62c4a68a335a7b3141795466362b89Adam Powell        if (mPresenters.isEmpty()) return false;
12128d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12138d02deabac62c4a68a335a7b3141795466362b89Adam Powell        boolean expanded = false;
12148d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12158d02deabac62c4a68a335a7b3141795466362b89Adam Powell        stopDispatchingItemsChanged();
12168d02deabac62c4a68a335a7b3141795466362b89Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
12178d02deabac62c4a68a335a7b3141795466362b89Adam Powell            final MenuPresenter presenter = ref.get();
12188d02deabac62c4a68a335a7b3141795466362b89Adam Powell            if (presenter == null) {
12198d02deabac62c4a68a335a7b3141795466362b89Adam Powell                mPresenters.remove(ref);
12208d02deabac62c4a68a335a7b3141795466362b89Adam Powell            } else if ((expanded = presenter.expandItemActionView(this, item))) {
12218d02deabac62c4a68a335a7b3141795466362b89Adam Powell                break;
12228d02deabac62c4a68a335a7b3141795466362b89Adam Powell            }
12238d02deabac62c4a68a335a7b3141795466362b89Adam Powell        }
12248d02deabac62c4a68a335a7b3141795466362b89Adam Powell        startDispatchingItemsChanged();
12258d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12268d02deabac62c4a68a335a7b3141795466362b89Adam Powell        return expanded;
12278d02deabac62c4a68a335a7b3141795466362b89Adam Powell    }
12288d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12298d02deabac62c4a68a335a7b3141795466362b89Adam Powell    public boolean collapseItemActionView(MenuItemImpl item) {
12308d02deabac62c4a68a335a7b3141795466362b89Adam Powell        if (mPresenters.isEmpty()) return false;
12318d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12328d02deabac62c4a68a335a7b3141795466362b89Adam Powell        boolean collapsed = false;
12338d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12348d02deabac62c4a68a335a7b3141795466362b89Adam Powell        stopDispatchingItemsChanged();
12358d02deabac62c4a68a335a7b3141795466362b89Adam Powell        for (WeakReference<MenuPresenter> ref : mPresenters) {
12368d02deabac62c4a68a335a7b3141795466362b89Adam Powell            final MenuPresenter presenter = ref.get();
12378d02deabac62c4a68a335a7b3141795466362b89Adam Powell            if (presenter == null) {
12388d02deabac62c4a68a335a7b3141795466362b89Adam Powell                mPresenters.remove(ref);
12398d02deabac62c4a68a335a7b3141795466362b89Adam Powell            } else if ((collapsed = presenter.collapseItemActionView(this, item))) {
12408d02deabac62c4a68a335a7b3141795466362b89Adam Powell                break;
12418d02deabac62c4a68a335a7b3141795466362b89Adam Powell            }
12428d02deabac62c4a68a335a7b3141795466362b89Adam Powell        }
12438d02deabac62c4a68a335a7b3141795466362b89Adam Powell        startDispatchingItemsChanged();
12448d02deabac62c4a68a335a7b3141795466362b89Adam Powell
12458d02deabac62c4a68a335a7b3141795466362b89Adam Powell        return collapsed;
12468d02deabac62c4a68a335a7b3141795466362b89Adam Powell    }
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1248