MenuPopupHelper.java revision 44918a92e1d66a01a03063e2c5e68b2570f64b03
1bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/*
2bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Copyright (C) 2010 The Android Open Source Project
3bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *
4bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Licensed under the Apache License, Version 2.0 (the "License");
5bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * you may not use this file except in compliance with the License.
6bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * You may obtain a copy of the License at
7bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *
8bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *      http://www.apache.org/licenses/LICENSE-2.0
9bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell *
10bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Unless required by applicable law or agreed to in writing, software
11bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * distributed under the License is distributed on an "AS IS" BASIS,
12bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * See the License for the specific language governing permissions and
14bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * limitations under the License.
15bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */
16bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
17da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownpackage android.support.v7.internal.view.menu;
18bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
19bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.Context;
20bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.res.Resources;
21bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.os.Parcelable;
22da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.appcompat.R;
2349c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v7.widget.ListPopupWindow;
2449c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.Gravity;
25bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.KeyEvent;
26bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.LayoutInflater;
2730837f1095c803f332f4a1c3f0917c8afdd50156Adam Powellimport android.view.MenuItem;
28bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.View;
29bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.View.MeasureSpec;
30bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewGroup;
31bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewTreeObserver;
32bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.AdapterView;
33bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.BaseAdapter;
34bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.FrameLayout;
35bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.ListAdapter;
36bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.PopupWindow;
37bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
38bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport java.util.ArrayList;
39bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
40bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/**
41bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Presents a menu as a small, simple popup anchored to another view.
42ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani *
43bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * @hide
44bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */
45bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellpublic class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
4620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener,
4720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        MenuPresenter {
4820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
49ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private static final String TAG = "MenuPopupHelper";
50bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
51ee7c9fb199e9b9af8d40a1f9e27d85465acf8301Chris Banes    static final int ITEM_LAYOUT = R.layout.abc_popup_menu_item_layout;
52bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
5349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private final Context mContext;
5449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private final LayoutInflater mInflater;
5549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private final MenuBuilder mMenu;
5649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private final MenuAdapter mAdapter;
5749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private final boolean mOverflowOnly;
5849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private final int mPopupMaxWidth;
5949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private final int mPopupStyleAttr;
60a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette    private final int mPopupStyleRes;
6149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
62ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private View mAnchorView;
6349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private ListPopupWindow mPopup;
64ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private ViewTreeObserver mTreeObserver;
65ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private Callback mPresenterCallback;
66bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
67ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    boolean mForceShowIcon;
68bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
69ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private ViewGroup mMeasureParent;
70bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
7149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** Whether the cached content width value is valid. */
7249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private boolean mHasContentWidth;
7349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
7449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /** Cached content width from {@link #measureContentWidth}. */
7549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private int mContentWidth;
7649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
7749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private int mDropDownGravity = Gravity.NO_GRAVITY;
7849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
79ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public MenuPopupHelper(Context context, MenuBuilder menu) {
8049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        this(context, menu, null, false, R.attr.popupMenuStyle);
81ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
82bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
83ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
8449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        this(context, menu, anchorView, false, R.attr.popupMenuStyle);
85ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
86bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
8749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
8849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            boolean overflowOnly, int popupStyleAttr) {
89a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette        this(context, menu, anchorView, overflowOnly, popupStyleAttr, 0);
90a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette    }
91a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette
92a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette    public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
93a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette            boolean overflowOnly, int popupStyleAttr, int popupStyleRes) {
94ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mContext = context;
95ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mInflater = LayoutInflater.from(context);
96ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mMenu = menu;
9749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mAdapter = new MenuAdapter(mMenu);
98ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mOverflowOnly = overflowOnly;
9949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mPopupStyleAttr = popupStyleAttr;
100a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette        mPopupStyleRes = popupStyleRes;
101bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
102ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final Resources res = context.getResources();
103ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
10407a07ce59efb770e9fb9ca53a0133e5e64a63bbcChris Banes                res.getDimensionPixelSize(R.dimen.abc_config_prefDialogWidth));
105bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
106ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mAnchorView = anchorView;
107bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
10849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        // Present the menu using our context, not the menu builder's context.
10949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        menu.addMenuPresenter(this, context);
110ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
111bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
112ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void setAnchorView(View anchor) {
113ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mAnchorView = anchor;
114ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
115bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
116ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void setForceShowIcon(boolean forceShow) {
117ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mForceShowIcon = forceShow;
118bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
119ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
12049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public void setGravity(int gravity) {
12149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mDropDownGravity = gravity;
12249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
12349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
12444918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    public int getGravity() {
12544918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes        return mDropDownGravity;
12644918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes    }
12744918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes
128ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void show() {
129ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (!tryShow()) {
130ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
131ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
132bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
133bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
13449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public ListPopupWindow getPopup() {
13549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return mPopup;
13649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
13749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
138ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean tryShow() {
139a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette        mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes);
140ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.setOnDismissListener(this);
141ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.setOnItemClickListener(this);
142ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.setAdapter(mAdapter);
143ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.setModal(true);
144ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
145ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        View anchor = mAnchorView;
146ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (anchor != null) {
147ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final boolean addGlobalListener = mTreeObserver == null;
148ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
14949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
150ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mPopup.setAnchorView(anchor);
15149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mPopup.setDropDownGravity(mDropDownGravity);
152ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        } else {
153ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return false;
154ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
155bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
15649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (!mHasContentWidth) {
15749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mContentWidth = measureContentWidth();
15849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mHasContentWidth = true;
15949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
16049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
16149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mPopup.setContentWidth(mContentWidth);
162ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
163ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.show();
164ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.getListView().setOnKeyListener(this);
165ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return true;
166bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
167ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
168ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void dismiss() {
169ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (isShowing()) {
170ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mPopup.dismiss();
171ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
172bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
173ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
174ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onDismiss() {
175ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup = null;
176ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mMenu.close();
177ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTreeObserver != null) {
17849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
179ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTreeObserver.removeGlobalOnLayoutListener(this);
180ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTreeObserver = null;
181ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
182bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
183ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
184ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean isShowing() {
185ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return mPopup != null && mPopup.isShowing();
186bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
187bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
188ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
189ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
190ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        MenuAdapter adapter = mAdapter;
191ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
192ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
193bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
194ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean onKey(View v, int keyCode, KeyEvent event) {
195ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
196ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            dismiss();
197ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return true;
198ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
199ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
200bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
201ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
20249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private int measureContentWidth() {
203ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        // Menus don't tend to be long, so this is more sane than it looks.
20449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        int maxWidth = 0;
205ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        View itemView = null;
206ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        int itemType = 0;
20749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
20849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final ListAdapter adapter = mAdapter;
20949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
21049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
211ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final int count = adapter.getCount();
212ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        for (int i = 0; i < count; i++) {
213ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final int positionType = adapter.getItemViewType(i);
214ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (positionType != itemType) {
215ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                itemType = positionType;
216ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                itemView = null;
217ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
21849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
219ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (mMeasureParent == null) {
220ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                mMeasureParent = new FrameLayout(mContext);
221ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
22249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
223ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            itemView = adapter.getView(i, itemView, mMeasureParent);
224ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            itemView.measure(widthMeasureSpec, heightMeasureSpec);
22549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
22649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int itemWidth = itemView.getMeasuredWidth();
22749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (itemWidth >= mPopupMaxWidth) {
22849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                return mPopupMaxWidth;
22949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            } else if (itemWidth > maxWidth) {
23049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                maxWidth = itemWidth;
23149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
232bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        }
23349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
23449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return maxWidth;
235ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
236bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
237ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
238ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onGlobalLayout() {
239ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (isShowing()) {
240ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final View anchor = mAnchorView;
241ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (anchor == null || !anchor.isShown()) {
242ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                dismiss();
243ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            } else if (isShowing()) {
244ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                // Recompute window size and position
245ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                mPopup.show();
246ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
247bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        }
248bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
249bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
250ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
251ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void initForMenu(Context context, MenuBuilder menu) {
252ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        // Don't need to do anything; we added as a presenter in the constructor.
253bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
254bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
255ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
256ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public MenuView getMenuView(ViewGroup root) {
257ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        throw new UnsupportedOperationException("MenuPopupHelpers manage their own views");
258bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
259bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
260ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
261ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void updateMenuView(boolean cleared) {
26249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mHasContentWidth = false;
26349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
26420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (mAdapter != null) {
26520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            mAdapter.notifyDataSetChanged();
26620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
267bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
268bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
269ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
270ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void setCallback(Callback cb) {
271ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPresenterCallback = cb;
272bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
273bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
274ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
275ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
276ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (subMenu.hasVisibleItems()) {
27749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView);
278ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            subPopup.setCallback(mPresenterCallback);
279ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
280ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            boolean preserveIconSpacing = false;
281ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final int count = subMenu.size();
282ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            for (int i = 0; i < count; i++) {
283ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                MenuItem childItem = subMenu.getItem(i);
284ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                if (childItem.isVisible() && childItem.getIcon() != null) {
285ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    preserveIconSpacing = true;
286ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    break;
287ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
288ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
289ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            subPopup.setForceShowIcon(preserveIconSpacing);
290ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
291ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (subPopup.tryShow()) {
292ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                if (mPresenterCallback != null) {
293ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mPresenterCallback.onOpenSubMenu(subMenu);
294ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
295ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                return true;
296ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
297ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
298ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
299bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
300bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
301ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
302ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
303ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        // Only care about the (sub)menu we're presenting.
30449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (menu != mMenu) return;
305ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
306ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        dismiss();
307ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mPresenterCallback != null) {
308ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
309bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        }
310bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
311bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
312bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    @Override
313ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean flagActionItems() {
314ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
315ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
316ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
317ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
318ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
319ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
320ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
321ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
322ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
323ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
324ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
325ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
326ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public int getId() {
327ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return 0;
328ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
329ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
330ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
331ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public Parcelable onSaveInstanceState() {
332ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return null;
333ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
334ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
335ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
336ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onRestoreInstanceState(Parcelable state) {
337ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
338ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
339ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private class MenuAdapter extends BaseAdapter {
340ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        private MenuBuilder mAdapterMenu;
341ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        private int mExpandedIndex = -1;
342ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
343ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public MenuAdapter(MenuBuilder menu) {
344ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mAdapterMenu = menu;
345ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            findExpandedIndex();
346ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
347ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
348ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public int getCount() {
349ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            ArrayList<MenuItemImpl> items = mOverflowOnly ?
35020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
351ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (mExpandedIndex < 0) {
352ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                return items.size();
353ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
354ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return items.size() - 1;
355ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
356ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
357ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public MenuItemImpl getItem(int position) {
358ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            ArrayList<MenuItemImpl> items = mOverflowOnly ?
35920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
360ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
361ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                position++;
362ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
363ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return items.get(position);
364ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
365ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
366ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public long getItemId(int position) {
367ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            // Since a menu item's ID is optional, we'll use the position as an
368ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            // ID for the item in the AdapterView
369ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return position;
370ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
371ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
372ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public View getView(int position, View convertView, ViewGroup parent) {
373ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (convertView == null) {
374ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
375ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
376ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
377ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            MenuView.ItemView itemView = (MenuView.ItemView) convertView;
378ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (mForceShowIcon) {
379ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                ((ListMenuItemView) convertView).setForceShowIcon(true);
380ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
381ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            itemView.initialize(getItem(position), 0);
382ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return convertView;
383ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
384ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
385ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        void findExpandedIndex() {
386ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final MenuItemImpl expandedItem = mMenu.getExpandedItem();
387ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (expandedItem != null) {
388ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
389ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                final int count = items.size();
390ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                for (int i = 0; i < count; i++) {
391ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    final MenuItemImpl item = items.get(i);
392ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    if (item == expandedItem) {
393ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        mExpandedIndex = i;
394ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        return;
395ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    }
396ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
397ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
398ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mExpandedIndex = -1;
399ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
400ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
401ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        @Override
402ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public void notifyDataSetChanged() {
403ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            findExpandedIndex();
404ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            super.notifyDataSetChanged();
405ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
406bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
407bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell}
408ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
409