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; 6049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 61ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private View mAnchorView; 6249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private ListPopupWindow mPopup; 63ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private ViewTreeObserver mTreeObserver; 64ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private Callback mPresenterCallback; 65bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 66ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani boolean mForceShowIcon; 67bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 68ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private ViewGroup mMeasureParent; 69bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 7049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** Whether the cached content width value is valid. */ 7149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private boolean mHasContentWidth; 7249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 7349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** Cached content width from {@link #measureContentWidth}. */ 7449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private int mContentWidth; 7549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 7649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private int mDropDownGravity = Gravity.NO_GRAVITY; 7749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 78ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public MenuPopupHelper(Context context, MenuBuilder menu) { 7949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes this(context, menu, null, false, R.attr.popupMenuStyle); 80ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 81bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 82ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) { 8349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes this(context, menu, anchorView, false, R.attr.popupMenuStyle); 84ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 85bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 8649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView, 8749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes boolean overflowOnly, int popupStyleAttr) { 88ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mContext = context; 89ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mInflater = LayoutInflater.from(context); 90ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMenu = menu; 9149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mAdapter = new MenuAdapter(mMenu); 92ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mOverflowOnly = overflowOnly; 9349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPopupStyleAttr = popupStyleAttr; 94bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 95ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final Resources res = context.getResources(); 96ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2, 9707a07ce59efb770e9fb9ca53a0133e5e64a63bbcChris Banes res.getDimensionPixelSize(R.dimen.abc_config_prefDialogWidth)); 98bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 99ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mAnchorView = anchorView; 100bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 10149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // Present the menu using our context, not the menu builder's context. 10249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes menu.addMenuPresenter(this, context); 103ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 104bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 105ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setAnchorView(View anchor) { 106ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mAnchorView = anchor; 107ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 108bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 109ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setForceShowIcon(boolean forceShow) { 110ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mForceShowIcon = forceShow; 111bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 112ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 11349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setGravity(int gravity) { 11449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mDropDownGravity = gravity; 11549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 11649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 117ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void show() { 118ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (!tryShow()) { 119ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); 120ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 121bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 122bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 12349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public ListPopupWindow getPopup() { 12449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mPopup; 12549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 12649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 127ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean tryShow() { 12849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr); 129ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup.setOnDismissListener(this); 130ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup.setOnItemClickListener(this); 131ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup.setAdapter(mAdapter); 132ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup.setModal(true); 133ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 134ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani View anchor = mAnchorView; 135ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (anchor != null) { 136ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final boolean addGlobalListener = mTreeObserver == null; 137ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest 13849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this); 139ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup.setAnchorView(anchor); 14049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPopup.setDropDownGravity(mDropDownGravity); 141ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 142ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return false; 143ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 144bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 14549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!mHasContentWidth) { 14649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mContentWidth = measureContentWidth(); 14749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mHasContentWidth = true; 14849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 14949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 15049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPopup.setContentWidth(mContentWidth); 151ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); 152ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup.show(); 153ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup.getListView().setOnKeyListener(this); 154ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return true; 155bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 156ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 157ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void dismiss() { 158ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (isShowing()) { 159ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup.dismiss(); 160ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 161bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 162ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 163ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onDismiss() { 164ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup = null; 165ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMenu.close(); 166ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTreeObserver != null) { 16749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver(); 168ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTreeObserver.removeGlobalOnLayoutListener(this); 169ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTreeObserver = null; 170ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 171bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 172ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 173ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean isShowing() { 174ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mPopup != null && mPopup.isShowing(); 175bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 176bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 177ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 178ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 179ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani MenuAdapter adapter = mAdapter; 180ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); 181ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 182bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 183ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean onKey(View v, int keyCode, KeyEvent event) { 184ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { 185ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani dismiss(); 186ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return true; 187ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 188ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return false; 189bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 190ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 19149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private int measureContentWidth() { 192ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Menus don't tend to be long, so this is more sane than it looks. 19349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int maxWidth = 0; 194ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani View itemView = null; 195ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani int itemType = 0; 19649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 19749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final ListAdapter adapter = mAdapter; 19849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 19949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 200ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int count = adapter.getCount(); 201ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani for (int i = 0; i < count; i++) { 202ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int positionType = adapter.getItemViewType(i); 203ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (positionType != itemType) { 204ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani itemType = positionType; 205ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani itemView = null; 206ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 20749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 208ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mMeasureParent == null) { 209ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMeasureParent = new FrameLayout(mContext); 210ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 21149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 212ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani itemView = adapter.getView(i, itemView, mMeasureParent); 213ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani itemView.measure(widthMeasureSpec, heightMeasureSpec); 21449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 21549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int itemWidth = itemView.getMeasuredWidth(); 21649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (itemWidth >= mPopupMaxWidth) { 21749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mPopupMaxWidth; 21849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else if (itemWidth > maxWidth) { 21949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes maxWidth = itemWidth; 22049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 221bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 22249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 22349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return maxWidth; 224ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 225bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 226ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 227ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onGlobalLayout() { 228ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (isShowing()) { 229ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View anchor = mAnchorView; 230ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (anchor == null || !anchor.isShown()) { 231ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani dismiss(); 232ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else if (isShowing()) { 233ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Recompute window size and position 234ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPopup.show(); 235ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 236bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 237bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 238bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 239ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 240ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void initForMenu(Context context, MenuBuilder menu) { 241ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Don't need to do anything; we added as a presenter in the constructor. 242bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 243bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 244ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 245ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public MenuView getMenuView(ViewGroup root) { 246ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani throw new UnsupportedOperationException("MenuPopupHelpers manage their own views"); 247bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 248bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 249ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 250ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void updateMenuView(boolean cleared) { 25149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mHasContentWidth = false; 25249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 25320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (mAdapter != null) { 25420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mAdapter.notifyDataSetChanged(); 25520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 256bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 257bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 258ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 259ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setCallback(Callback cb) { 260ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPresenterCallback = cb; 261bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 262bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 263ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 264ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 265ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (subMenu.hasVisibleItems()) { 26649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView); 267ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani subPopup.setCallback(mPresenterCallback); 268ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 269ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani boolean preserveIconSpacing = false; 270ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int count = subMenu.size(); 271ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani for (int i = 0; i < count; i++) { 272ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani MenuItem childItem = subMenu.getItem(i); 273ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (childItem.isVisible() && childItem.getIcon() != null) { 274ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani preserveIconSpacing = true; 275ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani break; 276ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 277ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 278ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani subPopup.setForceShowIcon(preserveIconSpacing); 279ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 280ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (subPopup.tryShow()) { 281ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mPresenterCallback != null) { 282ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPresenterCallback.onOpenSubMenu(subMenu); 283ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 284ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return true; 285ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 286ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 287ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return false; 288bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 289bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 290ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 291ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 292ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Only care about the (sub)menu we're presenting. 29349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (menu != mMenu) return; 294ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 295ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani dismiss(); 296ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mPresenterCallback != null) { 297ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mPresenterCallback.onCloseMenu(menu, allMenusAreClosing); 298bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 299bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 300bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 301bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell @Override 302ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean flagActionItems() { 303ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return false; 304ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 305ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 306ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { 307ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return false; 308ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 309ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 310ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { 311ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return false; 312ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 313ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 314ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 315ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public int getId() { 316ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return 0; 317ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 318ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 319ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 320ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public Parcelable onSaveInstanceState() { 321ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return null; 322ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 323ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 324ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 325ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onRestoreInstanceState(Parcelable state) { 326ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 327ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 328ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private class MenuAdapter extends BaseAdapter { 329ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private MenuBuilder mAdapterMenu; 330ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private int mExpandedIndex = -1; 331ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 332ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public MenuAdapter(MenuBuilder menu) { 333ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mAdapterMenu = menu; 334ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani findExpandedIndex(); 335ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 336ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 337ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public int getCount() { 338ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ArrayList<MenuItemImpl> items = mOverflowOnly ? 33920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems(); 340ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mExpandedIndex < 0) { 341ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return items.size(); 342ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 343ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return items.size() - 1; 344ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 345ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 346ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public MenuItemImpl getItem(int position) { 347ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ArrayList<MenuItemImpl> items = mOverflowOnly ? 34820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems(); 349ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mExpandedIndex >= 0 && position >= mExpandedIndex) { 350ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani position++; 351ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 352ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return items.get(position); 353ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 354ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 355ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public long getItemId(int position) { 356ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Since a menu item's ID is optional, we'll use the position as an 357ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // ID for the item in the AdapterView 358ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return position; 359ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 360ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 361ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public View getView(int position, View convertView, ViewGroup parent) { 362ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (convertView == null) { 363ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani convertView = mInflater.inflate(ITEM_LAYOUT, parent, false); 364ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 365ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 366ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani MenuView.ItemView itemView = (MenuView.ItemView) convertView; 367ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mForceShowIcon) { 368ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((ListMenuItemView) convertView).setForceShowIcon(true); 369ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 370ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani itemView.initialize(getItem(position), 0); 371ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return convertView; 372ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 373ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 374ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani void findExpandedIndex() { 375ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final MenuItemImpl expandedItem = mMenu.getExpandedItem(); 376ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (expandedItem != null) { 377ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems(); 378ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int count = items.size(); 379ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani for (int i = 0; i < count; i++) { 380ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final MenuItemImpl item = items.get(i); 381ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (item == expandedItem) { 382ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mExpandedIndex = i; 383ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return; 384ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 385ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 386ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 387ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mExpandedIndex = -1; 388ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 389ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 390ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 391ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void notifyDataSetChanged() { 392ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani findExpandedIndex(); 393ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.notifyDataSetChanged(); 394ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 395bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 396bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell} 397ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 398