MenuPopupHelper.java revision bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17f
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 17bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellpackage android.support.appcompat.view.menu; 18bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 19bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.support.appcompat.view.MenuItem; 20bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 21bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.Context; 22bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.res.Resources; 23bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.database.DataSetObserver; 24bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.os.Parcelable; 25bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.support.appcompat.R; 26bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.KeyEvent; 27bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.LayoutInflater; 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.ListPopupWindow; 37bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.PopupWindow; 38bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 39bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport java.util.ArrayList; 40bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 41bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/** 42bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Presents a menu as a small, simple popup anchored to another view. 43bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * @hide 44bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */ 45bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellpublic class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener, 46bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener, 47bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell View.OnAttachStateChangeListener, MenuPresenter { 48bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private static final String TAG = "MenuPopupHelper"; 49bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 50bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell static final int ITEM_LAYOUT = R.layout.popup_menu_item_layout; 51bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 52bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private Context mContext; 53bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private LayoutInflater mInflater; 54bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private ListPopupWindow mPopup; 55bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private MenuBuilder mMenu; 56bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private int mPopupMaxWidth; 57bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private View mAnchorView; 58bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private boolean mOverflowOnly; 59bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private ViewTreeObserver mTreeObserver; 60bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 61bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private MenuAdapter mAdapter; 62bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 63bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private Callback mPresenterCallback; 64bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 65bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell boolean mForceShowIcon; 66bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 67bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private ViewGroup mMeasureParent; 68bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 69bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public MenuPopupHelper(Context context, MenuBuilder menu) { 70bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell this(context, menu, null, false); 71bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 72bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 73bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) { 74bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell this(context, menu, anchorView, false); 75bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 76bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 77bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public MenuPopupHelper(Context context, MenuBuilder menu, 78bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell View anchorView, boolean overflowOnly) { 79bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mContext = context; 80bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mInflater = LayoutInflater.from(context); 81bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mMenu = menu; 82bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mOverflowOnly = overflowOnly; 83bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 84bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final Resources res = context.getResources(); 85bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2, 86bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell res.getDimensionPixelSize(R.dimen.config_prefDialogWidth)); 87bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 88bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mAnchorView = anchorView; 89bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 90bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell menu.addMenuPresenter(this); 91bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 92bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 93bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void setAnchorView(View anchor) { 94bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mAnchorView = anchor; 95bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 96bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 97bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void setForceShowIcon(boolean forceShow) { 98bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mForceShowIcon = forceShow; 99bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 100bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 101bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void show() { 102bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (!tryShow()) { 103bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); 104bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 105bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 106bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 107bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public boolean tryShow() { 108bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup = new ListPopupWindow(mContext, null, R.attr.popupMenuStyle); 109bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.setOnDismissListener(this); 110bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.setOnItemClickListener(this); 111bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 112bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mAdapter = new MenuAdapter(mMenu); 113bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.setAdapter(mAdapter); 114bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.setModal(true); 115bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 116bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell View anchor = mAnchorView; 117bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (anchor != null) { 118bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final boolean addGlobalListener = mTreeObserver == null; 119bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest 120bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this); 121bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell anchor.addOnAttachStateChangeListener(this); 122bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.setAnchorView(anchor); 123bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } else { 124bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return false; 125bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 126bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 127bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.setContentWidth(Math.min(measureContentWidth(mAdapter), mPopupMaxWidth)); 128bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); 129bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.show(); 130bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.getListView().setOnKeyListener(this); 131bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return true; 132bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 133bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 134bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void dismiss() { 135bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (isShowing()) { 136bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.dismiss(); 137bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 138bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 139bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 140bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void onDismiss() { 141bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup = null; 142bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mMenu.close(); 143bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (mTreeObserver != null) { 144bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver(); 145bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mTreeObserver.removeGlobalOnLayoutListener(this); 146bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mTreeObserver = null; 147bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 148bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mAnchorView.removeOnAttachStateChangeListener(this); 149bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 150bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 151bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public boolean isShowing() { 152bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return mPopup != null && mPopup.isShowing(); 153bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 154bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 155bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 156bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 157bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell MenuAdapter adapter = mAdapter; 158bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); 159bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 160bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 161bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public boolean onKey(View v, int keyCode, KeyEvent event) { 162bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { 163bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell dismiss(); 164bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return true; 165bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 166bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return false; 167bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 168bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 169bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private int measureContentWidth(ListAdapter adapter) { 170bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell // Menus don't tend to be long, so this is more sane than it looks. 171bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell int width = 0; 172bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell View itemView = null; 173bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell int itemType = 0; 174bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final int widthMeasureSpec = 175bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 176bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final int heightMeasureSpec = 177bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 178bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final int count = adapter.getCount(); 179bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell for (int i = 0; i < count; i++) { 180bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final int positionType = adapter.getItemViewType(i); 181bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (positionType != itemType) { 182bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell itemType = positionType; 183bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell itemView = null; 184bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 185bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (mMeasureParent == null) { 186bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mMeasureParent = new FrameLayout(mContext); 187bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 188bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell itemView = adapter.getView(i, itemView, mMeasureParent); 189bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell itemView.measure(widthMeasureSpec, heightMeasureSpec); 190bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell width = Math.max(width, itemView.getMeasuredWidth()); 191bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 192bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return width; 193bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 194bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 195bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 196bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void onGlobalLayout() { 197bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (isShowing()) { 198bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final View anchor = mAnchorView; 199bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (anchor == null || !anchor.isShown()) { 200bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell dismiss(); 201bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } else if (isShowing()) { 202bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell // Recompute window size and position 203bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPopup.show(); 204bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 205bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 206bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 207bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 208bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 209bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void onViewAttachedToWindow(View v) { 210bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 211bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 212bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 213bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void onViewDetachedFromWindow(View v) { 214bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (mTreeObserver != null) { 215bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver(); 216bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mTreeObserver.removeGlobalOnLayoutListener(this); 217bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 218bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell v.removeOnAttachStateChangeListener(this); 219bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 220bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 221bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 222bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void initForMenu(Context context, MenuBuilder menu) { 223bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell // Don't need to do anything; we added as a presenter in the constructor. 224bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 225bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 226bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 227bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public MenuView getMenuView(ViewGroup root) { 228bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell throw new UnsupportedOperationException("MenuPopupHelpers manage their own views"); 229bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 230bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 231bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 232bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void updateMenuView(boolean cleared) { 233bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (mAdapter != null) mAdapter.notifyDataSetChanged(); 234bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 235bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 236bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 237bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void setCallback(Callback cb) { 238bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPresenterCallback = cb; 239bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 240bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 241bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 242bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 243bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (subMenu.hasVisibleItems()) { 244bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false); 245bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell subPopup.setCallback(mPresenterCallback); 246bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 247bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell boolean preserveIconSpacing = false; 248bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final int count = subMenu.size(); 249bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell for (int i = 0; i < count; i++) { 250bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell MenuItem childItem = subMenu.getItem(i); 251bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (childItem.isVisible() && childItem.getIcon() != null) { 252bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell preserveIconSpacing = true; 253bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell break; 254bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 255bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 256bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell subPopup.setForceShowIcon(preserveIconSpacing); 257bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 258bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (subPopup.tryShow()) { 259bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (mPresenterCallback != null) { 260bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPresenterCallback.onOpenSubMenu(subMenu); 261bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 262bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return true; 263bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 264bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 265bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return false; 266bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 267bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 268bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 269bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 270bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell // Only care about the (sub)menu we're presenting. 271bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (menu != mMenu) return; 272bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 273bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell dismiss(); 274bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (mPresenterCallback != null) { 275bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mPresenterCallback.onCloseMenu(menu, allMenusAreClosing); 276bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 277bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 278bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 279bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 280bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public boolean flagActionItems() { 281bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return false; 282bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 283bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 284bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { 285bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return false; 286bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 287bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 288bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { 289bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return false; 290bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 291bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 292bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 293bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public int getId() { 294bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return 0; 295bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 296bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 297bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 298bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public Parcelable onSaveInstanceState() { 299bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return null; 300bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 301bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 302bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 303bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void onRestoreInstanceState(Parcelable state) { 304bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 305bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 306bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private class MenuAdapter extends BaseAdapter { 307bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private MenuBuilder mAdapterMenu; 308bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell private int mExpandedIndex = -1; 309bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 310bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public MenuAdapter(MenuBuilder menu) { 311bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mAdapterMenu = menu; 312bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell findExpandedIndex(); 313bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 314bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 315bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public int getCount() { 316bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell ArrayList<MenuItemImpl> items = mOverflowOnly ? 317bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems(); 318bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (mExpandedIndex < 0) { 319bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return items.size(); 320bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 321bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return items.size() - 1; 322bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 323bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 324bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public MenuItemImpl getItem(int position) { 325bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell ArrayList<MenuItemImpl> items = mOverflowOnly ? 326bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems(); 327bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (mExpandedIndex >= 0 && position >= mExpandedIndex) { 328bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell position++; 329bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 330bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return items.get(position); 331bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 332bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 333bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public long getItemId(int position) { 334bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell // Since a menu item's ID is optional, we'll use the position as an 335bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell // ID for the item in the AdapterView 336bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return position; 337bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 338bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 339bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public View getView(int position, View convertView, ViewGroup parent) { 340bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (convertView == null) { 341bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell convertView = mInflater.inflate(ITEM_LAYOUT, parent, false); 342bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 343bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 344bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell MenuView.ItemView itemView = (MenuView.ItemView) convertView; 345bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (mForceShowIcon) { 346bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell ((ListMenuItemView) convertView).setForceShowIcon(true); 347bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 348bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell itemView.initialize(getItem(position), 0); 349bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return convertView; 350bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 351bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 352bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell void findExpandedIndex() { 353bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final MenuItemImpl expandedItem = mMenu.getExpandedItem(); 354bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (expandedItem != null) { 355bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems(); 356bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final int count = items.size(); 357bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell for (int i = 0; i < count; i++) { 358bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final MenuItemImpl item = items.get(i); 359bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell if (item == expandedItem) { 360bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mExpandedIndex = i; 361bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell return; 362bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 363bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 364bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 365bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell mExpandedIndex = -1; 366bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 367bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 368bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 369bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell public void notifyDataSetChanged() { 370bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell findExpandedIndex(); 371bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell super.notifyDataSetChanged(); 372bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 373bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 374bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell} 375