MenuPopupHelper.java revision a9cf27da7f78d81db5ad482003a10d1a6562107c
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
124ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void show() {
125ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (!tryShow()) {
126ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
127ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
128bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
129bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
13049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public ListPopupWindow getPopup() {
13149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return mPopup;
13249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
13349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
134ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean tryShow() {
135a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette        mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes);
136ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.setOnDismissListener(this);
137ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.setOnItemClickListener(this);
138ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.setAdapter(mAdapter);
139ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.setModal(true);
140ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
141ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        View anchor = mAnchorView;
142ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (anchor != null) {
143ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final boolean addGlobalListener = mTreeObserver == null;
144ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
14549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
146ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mPopup.setAnchorView(anchor);
14749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mPopup.setDropDownGravity(mDropDownGravity);
148ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        } else {
149ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return false;
150ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
151bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
15249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (!mHasContentWidth) {
15349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mContentWidth = measureContentWidth();
15449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mHasContentWidth = true;
15549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
15649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
15749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mPopup.setContentWidth(mContentWidth);
158ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
159ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.show();
160ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup.getListView().setOnKeyListener(this);
161ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return true;
162bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
163ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
164ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void dismiss() {
165ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (isShowing()) {
166ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mPopup.dismiss();
167ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
168bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
169ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
170ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onDismiss() {
171ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPopup = null;
172ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mMenu.close();
173ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mTreeObserver != null) {
17449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
175ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTreeObserver.removeGlobalOnLayoutListener(this);
176ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mTreeObserver = null;
177ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
178bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
179ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
180ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean isShowing() {
181ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return mPopup != null && mPopup.isShowing();
182bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
183bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
184ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
185ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
186ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        MenuAdapter adapter = mAdapter;
187ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
188ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
189bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
190ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean onKey(View v, int keyCode, KeyEvent event) {
191ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
192ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            dismiss();
193ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return true;
194ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
195ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
196bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
197ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
19849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private int measureContentWidth() {
199ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        // Menus don't tend to be long, so this is more sane than it looks.
20049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        int maxWidth = 0;
201ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        View itemView = null;
202ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        int itemType = 0;
20349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
20449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final ListAdapter adapter = mAdapter;
20549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
20649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
207ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        final int count = adapter.getCount();
208ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        for (int i = 0; i < count; i++) {
209ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final int positionType = adapter.getItemViewType(i);
210ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (positionType != itemType) {
211ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                itemType = positionType;
212ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                itemView = null;
213ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
21449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
215ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (mMeasureParent == null) {
216ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                mMeasureParent = new FrameLayout(mContext);
217ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
21849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
219ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            itemView = adapter.getView(i, itemView, mMeasureParent);
220ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            itemView.measure(widthMeasureSpec, heightMeasureSpec);
22149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
22249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int itemWidth = itemView.getMeasuredWidth();
22349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (itemWidth >= mPopupMaxWidth) {
22449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                return mPopupMaxWidth;
22549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            } else if (itemWidth > maxWidth) {
22649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                maxWidth = itemWidth;
22749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
228bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        }
22949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
23049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return maxWidth;
231ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
232bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
233ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
234ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onGlobalLayout() {
235ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (isShowing()) {
236ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final View anchor = mAnchorView;
237ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (anchor == null || !anchor.isShown()) {
238ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                dismiss();
239ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            } else if (isShowing()) {
240ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                // Recompute window size and position
241ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                mPopup.show();
242ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
243bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        }
244bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
245bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
246ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
247ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void initForMenu(Context context, MenuBuilder menu) {
248ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        // Don't need to do anything; we added as a presenter in the constructor.
249bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
250bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
251ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
252ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public MenuView getMenuView(ViewGroup root) {
253ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        throw new UnsupportedOperationException("MenuPopupHelpers manage their own views");
254bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
255bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
256ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
257ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void updateMenuView(boolean cleared) {
25849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mHasContentWidth = false;
25949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
26020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        if (mAdapter != null) {
26120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns            mAdapter.notifyDataSetChanged();
26220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        }
263bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
264bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
265ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
266ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void setCallback(Callback cb) {
267ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        mPresenterCallback = cb;
268bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
269bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
270ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
271ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
272ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (subMenu.hasVisibleItems()) {
27349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView);
274ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            subPopup.setCallback(mPresenterCallback);
275ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
276ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            boolean preserveIconSpacing = false;
277ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final int count = subMenu.size();
278ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            for (int i = 0; i < count; i++) {
279ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                MenuItem childItem = subMenu.getItem(i);
280ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                if (childItem.isVisible() && childItem.getIcon() != null) {
281ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    preserveIconSpacing = true;
282ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    break;
283ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
284ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
285ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            subPopup.setForceShowIcon(preserveIconSpacing);
286ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
287ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (subPopup.tryShow()) {
288ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                if (mPresenterCallback != null) {
289ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    mPresenterCallback.onOpenSubMenu(subMenu);
290ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
291ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                return true;
292ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
293ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
294ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
295bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
296bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
297ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
298ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
299ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        // Only care about the (sub)menu we're presenting.
30049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (menu != mMenu) return;
301ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
302ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        dismiss();
303ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        if (mPresenterCallback != null) {
304ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
305bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell        }
306bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
307bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell
308bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    @Override
309ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean flagActionItems() {
310ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
311ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
312ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
313ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
314ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
315ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
316ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
317ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
318ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return false;
319ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
320ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
321ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
322ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public int getId() {
323ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return 0;
324ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
325ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
326ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
327ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public Parcelable onSaveInstanceState() {
328ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        return null;
329ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
330ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
331ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    @Override
332ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    public void onRestoreInstanceState(Parcelable state) {
333ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    }
334ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
335ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani    private class MenuAdapter extends BaseAdapter {
336ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        private MenuBuilder mAdapterMenu;
337ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        private int mExpandedIndex = -1;
338ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
339ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public MenuAdapter(MenuBuilder menu) {
340ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mAdapterMenu = menu;
341ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            findExpandedIndex();
342ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
343ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
344ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public int getCount() {
345ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            ArrayList<MenuItemImpl> items = mOverflowOnly ?
34620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
347ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (mExpandedIndex < 0) {
348ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                return items.size();
349ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
350ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return items.size() - 1;
351ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
352ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
353ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public MenuItemImpl getItem(int position) {
354ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            ArrayList<MenuItemImpl> items = mOverflowOnly ?
35520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                    mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
356ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
357ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                position++;
358ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
359ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return items.get(position);
360ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
361ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
362ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public long getItemId(int position) {
363ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            // Since a menu item's ID is optional, we'll use the position as an
364ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            // ID for the item in the AdapterView
365ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return position;
366ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
367ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
368ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public View getView(int position, View convertView, ViewGroup parent) {
369ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (convertView == null) {
370ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
371ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
372ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
373ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            MenuView.ItemView itemView = (MenuView.ItemView) convertView;
374ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (mForceShowIcon) {
375ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                ((ListMenuItemView) convertView).setForceShowIcon(true);
376ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
377ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            itemView.initialize(getItem(position), 0);
378ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            return convertView;
379ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
380ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
381ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        void findExpandedIndex() {
382ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            final MenuItemImpl expandedItem = mMenu.getExpandedItem();
383ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            if (expandedItem != null) {
384ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
385ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                final int count = items.size();
386ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                for (int i = 0; i < count; i++) {
387ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    final MenuItemImpl item = items.get(i);
388ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    if (item == expandedItem) {
389ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        mExpandedIndex = i;
390ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                        return;
391ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                    }
392ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani                }
393ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            }
394ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            mExpandedIndex = -1;
395ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
396ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
397ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        @Override
398ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        public void notifyDataSetChanged() {
399ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            findExpandedIndex();
400ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani            super.notifyDataSetChanged();
401ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani        }
402bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell    }
403bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell}
404ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani
405