14267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell/* 24267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * Copyright (C) 2010 The Android Open Source Project 34267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * 44267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 54267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * you may not use this file except in compliance with the License. 64267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * You may obtain a copy of the License at 74267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * 84267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * http://www.apache.org/licenses/LICENSE-2.0 94267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * 104267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * Unless required by applicable law or agreed to in writing, software 114267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * distributed under the License is distributed on an "AS IS" BASIS, 124267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * See the License for the specific language governing permissions and 144267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * limitations under the License. 154267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell */ 164267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 174267534d1c42af847ed0cefd1c88c99f66b36571Adam Powellpackage com.android.internal.view.menu; 184267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 194267534d1c42af847ed0cefd1c88c99f66b36571Adam Powellimport android.content.Context; 2038639b1d75933bfb720db79fce26f09478709614Adam Powellimport android.content.res.Resources; 2111ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powellimport android.os.Parcelable; 2254c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powellimport android.view.Gravity; 238028dd32a4a04154050220dd0693583d5b750330Adam Powellimport android.view.KeyEvent; 24696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.view.LayoutInflater; 259151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powellimport android.view.MenuItem; 264267534d1c42af847ed0cefd1c88c99f66b36571Adam Powellimport android.view.View; 274267534d1c42af847ed0cefd1c88c99f66b36571Adam Powellimport android.view.View.MeasureSpec; 28696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.view.ViewGroup; 290458796f1401732b38660794148f4c5e5602f432Adam Powellimport android.view.ViewTreeObserver; 304267534d1c42af847ed0cefd1c88c99f66b36571Adam Powellimport android.widget.AdapterView; 31696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.widget.BaseAdapter; 329151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powellimport android.widget.FrameLayout; 33696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.widget.ListAdapter; 344267534d1c42af847ed0cefd1c88c99f66b36571Adam Powellimport android.widget.ListPopupWindow; 356c6f575423d6718c3ff322224c1520901ce881e1Adam Powellimport android.widget.PopupWindow; 364267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 37696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport java.util.ArrayList; 388028dd32a4a04154050220dd0693583d5b750330Adam Powell 394267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell/** 40696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * Presents a menu as a small, simple popup anchored to another view. 414267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * @hide 424267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell */ 430458796f1401732b38660794148f4c5e5602f432Adam Powellpublic class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener, 444afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener, 45696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell View.OnAttachStateChangeListener, MenuPresenter { 464267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell private static final String TAG = "MenuPopupHelper"; 474267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 48696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout; 49696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 500bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final Context mContext; 510bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final LayoutInflater mInflater; 520bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final MenuBuilder mMenu; 530bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final MenuAdapter mAdapter; 540bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final boolean mOverflowOnly; 550bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final int mPopupMaxWidth; 56560f17098f90b15c8894cce127f2fed85f7aeb6bAlan Viverette private final int mPopupStyleAttr; 5729632521c36548d71b610fc4de864281bab4dfb4Alan Viverette private final int mPopupStyleRes; 580bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 594afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell private View mAnchorView; 600bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private ListPopupWindow mPopup; 610458796f1401732b38660794148f4c5e5602f432Adam Powell private ViewTreeObserver mTreeObserver; 62696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell private Callback mPresenterCallback; 63e2b03a62e5014ea60e24a989544fa549b493a520Adam Powell 649151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell boolean mForceShowIcon; 659151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell 669151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell private ViewGroup mMeasureParent; 679151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell 680bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette /** Whether the cached content width value is valid. */ 690bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private boolean mHasContentWidth; 700bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 710bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette /** Cached content width from {@link #measureContentWidth}. */ 720bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private int mContentWidth; 730bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 7454c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell private int mDropDownGravity = Gravity.NO_GRAVITY; 7554c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell 768028dd32a4a04154050220dd0693583d5b750330Adam Powell public MenuPopupHelper(Context context, MenuBuilder menu) { 7729632521c36548d71b610fc4de864281bab4dfb4Alan Viverette this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0); 788028dd32a4a04154050220dd0693583d5b750330Adam Powell } 794267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 808028dd32a4a04154050220dd0693583d5b750330Adam Powell public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) { 8129632521c36548d71b610fc4de864281bab4dfb4Alan Viverette this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle, 0); 828028dd32a4a04154050220dd0693583d5b750330Adam Powell } 838028dd32a4a04154050220dd0693583d5b750330Adam Powell 84560f17098f90b15c8894cce127f2fed85f7aeb6bAlan Viverette public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView, 85560f17098f90b15c8894cce127f2fed85f7aeb6bAlan Viverette boolean overflowOnly, int popupStyleAttr) { 8629632521c36548d71b610fc4de864281bab4dfb4Alan Viverette this(context, menu, anchorView, overflowOnly, popupStyleAttr, 0); 8729632521c36548d71b610fc4de864281bab4dfb4Alan Viverette } 8829632521c36548d71b610fc4de864281bab4dfb4Alan Viverette 8929632521c36548d71b610fc4de864281bab4dfb4Alan Viverette public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView, 9029632521c36548d71b610fc4de864281bab4dfb4Alan Viverette boolean overflowOnly, int popupStyleAttr, int popupStyleRes) { 914267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell mContext = context; 92696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mInflater = LayoutInflater.from(context); 938028dd32a4a04154050220dd0693583d5b750330Adam Powell mMenu = menu; 940bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mAdapter = new MenuAdapter(mMenu); 958028dd32a4a04154050220dd0693583d5b750330Adam Powell mOverflowOnly = overflowOnly; 96560f17098f90b15c8894cce127f2fed85f7aeb6bAlan Viverette mPopupStyleAttr = popupStyleAttr; 9729632521c36548d71b610fc4de864281bab4dfb4Alan Viverette mPopupStyleRes = popupStyleRes; 984267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 9938639b1d75933bfb720db79fce26f09478709614Adam Powell final Resources res = context.getResources(); 10038639b1d75933bfb720db79fce26f09478709614Adam Powell mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2, 10138639b1d75933bfb720db79fce26f09478709614Adam Powell res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth)); 1028028dd32a4a04154050220dd0693583d5b750330Adam Powell 1034afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mAnchorView = anchorView; 104696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 1053d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette // Present the menu using our context, not the menu builder's context. 1063d0f21dab8d891b9aebdd5277348d549eeb843e6Alan Viverette menu.addMenuPresenter(this, context); 1074267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 1084267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 109f0ad6e6eaf48ac8f4007232ad0a8511a7b5cfc0eAdam Powell public void setAnchorView(View anchor) { 1104afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mAnchorView = anchor; 111f0ad6e6eaf48ac8f4007232ad0a8511a7b5cfc0eAdam Powell } 112f0ad6e6eaf48ac8f4007232ad0a8511a7b5cfc0eAdam Powell 1139151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell public void setForceShowIcon(boolean forceShow) { 1149151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell mForceShowIcon = forceShow; 1159151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell } 1169151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell 11754c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell public void setGravity(int gravity) { 11854c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell mDropDownGravity = gravity; 11954c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell } 12054c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell 1214267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell public void show() { 1225e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell if (!tryShow()) { 1235e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); 1245e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell } 1255e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell } 1265e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell 127ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette public ListPopupWindow getPopup() { 128ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette return mPopup; 129ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 130ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1315e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell public boolean tryShow() { 13229632521c36548d71b610fc4de864281bab4dfb4Alan Viverette mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes); 1338515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell mPopup.setOnDismissListener(this); 134696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPopup.setOnItemClickListener(this); 135696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPopup.setAdapter(mAdapter); 1364267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell mPopup.setModal(true); 1374267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 1384afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell View anchor = mAnchorView; 1390458796f1401732b38660794148f4c5e5602f432Adam Powell if (anchor != null) { 1404afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell final boolean addGlobalListener = mTreeObserver == null; 1414afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest 1424afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this); 1434afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell anchor.addOnAttachStateChangeListener(this); 1440458796f1401732b38660794148f4c5e5602f432Adam Powell mPopup.setAnchorView(anchor); 14554c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell mPopup.setDropDownGravity(mDropDownGravity); 1464be0d52125b88dc992a4c500edbe95bf55484e0bAdam Powell } else { 1475e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell return false; 1488028dd32a4a04154050220dd0693583d5b750330Adam Powell } 1494267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 1500bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette if (!mHasContentWidth) { 1510bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mContentWidth = measureContentWidth(); 1520bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mHasContentWidth = true; 1530bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette } 1540bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 1550bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mPopup.setContentWidth(mContentWidth); 156aa0b92ce2b51987e9c864164234fe968ab5b9311Adam Powell mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); 1574267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell mPopup.show(); 1588028dd32a4a04154050220dd0693583d5b750330Adam Powell mPopup.getListView().setOnKeyListener(this); 1595e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell return true; 1604267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 1614267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 1624267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell public void dismiss() { 1633d3da27ab394108fd51771616cca3279baae99d1Adam Powell if (isShowing()) { 1643d3da27ab394108fd51771616cca3279baae99d1Adam Powell mPopup.dismiss(); 1653d3da27ab394108fd51771616cca3279baae99d1Adam Powell } 1668515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell } 1678515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell 1688515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell public void onDismiss() { 1698515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell mPopup = null; 17042b91bbcdaf64b2f19d0a9ce168964b31a5dc139Adam Powell mMenu.close(); 1714afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (mTreeObserver != null) { 1724afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver(); 173ca51e8788a58f2af3525b7214a675f2d0233e5daAdam Powell mTreeObserver.removeGlobalOnLayoutListener(this); 1744afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mTreeObserver = null; 175ed8b403cc8066bf76cdf98f8d9906ff810defc5bAdam Powell } 1764afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mAnchorView.removeOnAttachStateChangeListener(this); 1774267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 1784267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 1798028dd32a4a04154050220dd0693583d5b750330Adam Powell public boolean isShowing() { 1808028dd32a4a04154050220dd0693583d5b750330Adam Powell return mPopup != null && mPopup.isShowing(); 1818028dd32a4a04154050220dd0693583d5b750330Adam Powell } 1828028dd32a4a04154050220dd0693583d5b750330Adam Powell 183696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 1844267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 185696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell MenuAdapter adapter = mAdapter; 186696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); 1874267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 1884267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 1898028dd32a4a04154050220dd0693583d5b750330Adam Powell public boolean onKey(View v, int keyCode, KeyEvent event) { 1908028dd32a4a04154050220dd0693583d5b750330Adam Powell if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { 1918028dd32a4a04154050220dd0693583d5b750330Adam Powell dismiss(); 1928028dd32a4a04154050220dd0693583d5b750330Adam Powell return true; 1938028dd32a4a04154050220dd0693583d5b750330Adam Powell } 1948028dd32a4a04154050220dd0693583d5b750330Adam Powell return false; 1958028dd32a4a04154050220dd0693583d5b750330Adam Powell } 1968028dd32a4a04154050220dd0693583d5b750330Adam Powell 1970bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private int measureContentWidth() { 1984267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell // Menus don't tend to be long, so this is more sane than it looks. 1990bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette int maxWidth = 0; 2004267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell View itemView = null; 20150f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell int itemType = 0; 2020bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2030bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette final ListAdapter adapter = mAdapter; 2040bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 2050bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 2064267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell final int count = adapter.getCount(); 2074267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell for (int i = 0; i < count; i++) { 20850f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell final int positionType = adapter.getItemViewType(i); 20950f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell if (positionType != itemType) { 21050f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell itemType = positionType; 21150f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell itemView = null; 21250f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell } 2130bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2149151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell if (mMeasureParent == null) { 2159151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell mMeasureParent = new FrameLayout(mContext); 2169151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell } 2170bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2189151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell itemView = adapter.getView(i, itemView, mMeasureParent); 2194267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell itemView.measure(widthMeasureSpec, heightMeasureSpec); 2200bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2210bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette final int itemWidth = itemView.getMeasuredWidth(); 2220bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette if (itemWidth >= mPopupMaxWidth) { 2230bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette return mPopupMaxWidth; 2240bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette } else if (itemWidth > maxWidth) { 2250bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette maxWidth = itemWidth; 2260bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette } 2274267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 2280bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2290bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette return maxWidth; 2304267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 2310458796f1401732b38660794148f4c5e5602f432Adam Powell 2320458796f1401732b38660794148f4c5e5602f432Adam Powell @Override 2330458796f1401732b38660794148f4c5e5602f432Adam Powell public void onGlobalLayout() { 2344afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (isShowing()) { 2354afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell final View anchor = mAnchorView; 236ca51e8788a58f2af3525b7214a675f2d0233e5daAdam Powell if (anchor == null || !anchor.isShown()) { 2370458796f1401732b38660794148f4c5e5602f432Adam Powell dismiss(); 238ca51e8788a58f2af3525b7214a675f2d0233e5daAdam Powell } else if (isShowing()) { 239aa0b92ce2b51987e9c864164234fe968ab5b9311Adam Powell // Recompute window size and position 240aa0b92ce2b51987e9c864164234fe968ab5b9311Adam Powell mPopup.show(); 2410458796f1401732b38660794148f4c5e5602f432Adam Powell } 2420458796f1401732b38660794148f4c5e5602f432Adam Powell } 2430458796f1401732b38660794148f4c5e5602f432Adam Powell } 2444afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell 2454afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell @Override 2464afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell public void onViewAttachedToWindow(View v) { 2474afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell } 2484afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell 2494afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell @Override 2504afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell public void onViewDetachedFromWindow(View v) { 2514afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (mTreeObserver != null) { 2524afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver(); 2534afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mTreeObserver.removeGlobalOnLayoutListener(this); 2544afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell } 2554afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell v.removeOnAttachStateChangeListener(this); 2564afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell } 257696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 258696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 259696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public void initForMenu(Context context, MenuBuilder menu) { 260696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell // Don't need to do anything; we added as a presenter in the constructor. 261696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 262696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 263696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 264696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public MenuView getMenuView(ViewGroup root) { 265696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell throw new UnsupportedOperationException("MenuPopupHelpers manage their own views"); 266696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 267696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 268696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 269696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public void updateMenuView(boolean cleared) { 2700bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mHasContentWidth = false; 2710bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2720bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette if (mAdapter != null) { 2730bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mAdapter.notifyDataSetChanged(); 2740bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette } 275696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 276696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 277696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 278696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public void setCallback(Callback cb) { 279696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenterCallback = cb; 280696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 281696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 282696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 283696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 284696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (subMenu.hasVisibleItems()) { 285560f17098f90b15c8894cce127f2fed85f7aeb6bAlan Viverette MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView); 286696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell subPopup.setCallback(mPresenterCallback); 2879151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell 2889151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell boolean preserveIconSpacing = false; 2899151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell final int count = subMenu.size(); 2909151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell for (int i = 0; i < count; i++) { 2919151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell MenuItem childItem = subMenu.getItem(i); 2929151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell if (childItem.isVisible() && childItem.getIcon() != null) { 2939151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell preserveIconSpacing = true; 2949151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell break; 2959151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell } 2969151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell } 2979151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell subPopup.setForceShowIcon(preserveIconSpacing); 2989151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell 299696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (subPopup.tryShow()) { 300696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (mPresenterCallback != null) { 301696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenterCallback.onOpenSubMenu(subMenu); 302696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 303696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return true; 304696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 305696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 306696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return false; 307696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 308696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 309696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 310696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 311696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell // Only care about the (sub)menu we're presenting. 312696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (menu != mMenu) return; 313696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 314696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell dismiss(); 315696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (mPresenterCallback != null) { 316696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenterCallback.onCloseMenu(menu, allMenusAreClosing); 317696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 318696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 319696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 320696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 321696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public boolean flagActionItems() { 322696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return false; 323696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 324696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 3258d02deabac62c4a68a335a7b3141795466362b89Adam Powell public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { 3268d02deabac62c4a68a335a7b3141795466362b89Adam Powell return false; 3278d02deabac62c4a68a335a7b3141795466362b89Adam Powell } 3288d02deabac62c4a68a335a7b3141795466362b89Adam Powell 3298d02deabac62c4a68a335a7b3141795466362b89Adam Powell public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { 3308d02deabac62c4a68a335a7b3141795466362b89Adam Powell return false; 3318d02deabac62c4a68a335a7b3141795466362b89Adam Powell } 3328d02deabac62c4a68a335a7b3141795466362b89Adam Powell 333275702c2f47ed87ab642462530092d9777f32ecdAdam Powell @Override 334275702c2f47ed87ab642462530092d9777f32ecdAdam Powell public int getId() { 335275702c2f47ed87ab642462530092d9777f32ecdAdam Powell return 0; 336275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 337275702c2f47ed87ab642462530092d9777f32ecdAdam Powell 338275702c2f47ed87ab642462530092d9777f32ecdAdam Powell @Override 339275702c2f47ed87ab642462530092d9777f32ecdAdam Powell public Parcelable onSaveInstanceState() { 340275702c2f47ed87ab642462530092d9777f32ecdAdam Powell return null; 341275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 342275702c2f47ed87ab642462530092d9777f32ecdAdam Powell 343275702c2f47ed87ab642462530092d9777f32ecdAdam Powell @Override 344275702c2f47ed87ab642462530092d9777f32ecdAdam Powell public void onRestoreInstanceState(Parcelable state) { 345275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 346275702c2f47ed87ab642462530092d9777f32ecdAdam Powell 347696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell private class MenuAdapter extends BaseAdapter { 348696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell private MenuBuilder mAdapterMenu; 349275702c2f47ed87ab642462530092d9777f32ecdAdam Powell private int mExpandedIndex = -1; 350696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 351696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public MenuAdapter(MenuBuilder menu) { 352696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mAdapterMenu = menu; 353275702c2f47ed87ab642462530092d9777f32ecdAdam Powell findExpandedIndex(); 354696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 355696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 356696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public int getCount() { 357696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell ArrayList<MenuItemImpl> items = mOverflowOnly ? 358696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems(); 359275702c2f47ed87ab642462530092d9777f32ecdAdam Powell if (mExpandedIndex < 0) { 360275702c2f47ed87ab642462530092d9777f32ecdAdam Powell return items.size(); 361275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 362275702c2f47ed87ab642462530092d9777f32ecdAdam Powell return items.size() - 1; 363696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 364696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 365696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public MenuItemImpl getItem(int position) { 366696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell ArrayList<MenuItemImpl> items = mOverflowOnly ? 367696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems(); 368275702c2f47ed87ab642462530092d9777f32ecdAdam Powell if (mExpandedIndex >= 0 && position >= mExpandedIndex) { 369275702c2f47ed87ab642462530092d9777f32ecdAdam Powell position++; 370275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 371696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return items.get(position); 372696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 373696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 374696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public long getItemId(int position) { 375696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell // Since a menu item's ID is optional, we'll use the position as an 376696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell // ID for the item in the AdapterView 377696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return position; 378696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 379696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 380696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public View getView(int position, View convertView, ViewGroup parent) { 381696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (convertView == null) { 382696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell convertView = mInflater.inflate(ITEM_LAYOUT, parent, false); 383696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 384696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 385696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell MenuView.ItemView itemView = (MenuView.ItemView) convertView; 3869151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell if (mForceShowIcon) { 3879151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell ((ListMenuItemView) convertView).setForceShowIcon(true); 3889151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell } 389696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell itemView.initialize(getItem(position), 0); 390696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return convertView; 391696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 39211ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell 393275702c2f47ed87ab642462530092d9777f32ecdAdam Powell void findExpandedIndex() { 394275702c2f47ed87ab642462530092d9777f32ecdAdam Powell final MenuItemImpl expandedItem = mMenu.getExpandedItem(); 395275702c2f47ed87ab642462530092d9777f32ecdAdam Powell if (expandedItem != null) { 396275702c2f47ed87ab642462530092d9777f32ecdAdam Powell final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems(); 397275702c2f47ed87ab642462530092d9777f32ecdAdam Powell final int count = items.size(); 398275702c2f47ed87ab642462530092d9777f32ecdAdam Powell for (int i = 0; i < count; i++) { 399275702c2f47ed87ab642462530092d9777f32ecdAdam Powell final MenuItemImpl item = items.get(i); 400275702c2f47ed87ab642462530092d9777f32ecdAdam Powell if (item == expandedItem) { 401275702c2f47ed87ab642462530092d9777f32ecdAdam Powell mExpandedIndex = i; 402275702c2f47ed87ab642462530092d9777f32ecdAdam Powell return; 403275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 404275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 405275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 406275702c2f47ed87ab642462530092d9777f32ecdAdam Powell mExpandedIndex = -1; 407275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 40811ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell 409275702c2f47ed87ab642462530092d9777f32ecdAdam Powell @Override 41076889f3482d6391b17f0961f7356c1e8169c8813Adam Powell public void notifyDataSetChanged() { 41176889f3482d6391b17f0961f7356c1e8169c8813Adam Powell findExpandedIndex(); 41276889f3482d6391b17f0961f7356c1e8169c8813Adam Powell super.notifyDataSetChanged(); 413275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 41411ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell } 4154267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell} 416