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; 2680e72700858eb58b379f77a0da5fd3a98e1aa07cAlan Viveretteimport android.view.MotionEvent; 274267534d1c42af847ed0cefd1c88c99f66b36571Adam Powellimport android.view.View; 284267534d1c42af847ed0cefd1c88c99f66b36571Adam Powellimport android.view.View.MeasureSpec; 29696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.view.ViewGroup; 300458796f1401732b38660794148f4c5e5602f432Adam Powellimport android.view.ViewTreeObserver; 314267534d1c42af847ed0cefd1c88c99f66b36571Adam Powellimport android.widget.AdapterView; 32696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.widget.BaseAdapter; 339151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powellimport android.widget.FrameLayout; 34696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport android.widget.ListAdapter; 354267534d1c42af847ed0cefd1c88c99f66b36571Adam Powellimport android.widget.ListPopupWindow; 366c6f575423d6718c3ff322224c1520901ce881e1Adam Powellimport android.widget.PopupWindow; 374267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 38696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powellimport java.util.ArrayList; 398028dd32a4a04154050220dd0693583d5b750330Adam Powell 404267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell/** 41696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * Presents a menu as a small, simple popup anchored to another view. 424267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * @hide 434267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell */ 440458796f1401732b38660794148f4c5e5602f432Adam Powellpublic class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener, 454afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener, 46696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell View.OnAttachStateChangeListener, MenuPresenter { 474267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell private static final String TAG = "MenuPopupHelper"; 484267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 49696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout; 50696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 510bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final Context mContext; 520bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final LayoutInflater mInflater; 530bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final MenuBuilder mMenu; 540bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final MenuAdapter mAdapter; 550bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final boolean mOverflowOnly; 560bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private final int mPopupMaxWidth; 570bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 584afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell private View mAnchorView; 590bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private ListPopupWindow mPopup; 600458796f1401732b38660794148f4c5e5602f432Adam Powell private ViewTreeObserver mTreeObserver; 61696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell private Callback mPresenterCallback; 62e2b03a62e5014ea60e24a989544fa549b493a520Adam Powell 639151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell boolean mForceShowIcon; 649151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell 659151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell private ViewGroup mMeasureParent; 669151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell 670bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette /** Whether the cached content width value is valid. */ 680bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private boolean mHasContentWidth; 690bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 700bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette /** Cached content width from {@link #measureContentWidth}. */ 710bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private int mContentWidth; 720bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 7354c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell private int mDropDownGravity = Gravity.NO_GRAVITY; 7454c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell 758028dd32a4a04154050220dd0693583d5b750330Adam Powell public MenuPopupHelper(Context context, MenuBuilder menu) { 768028dd32a4a04154050220dd0693583d5b750330Adam Powell this(context, menu, null, false); 778028dd32a4a04154050220dd0693583d5b750330Adam Powell } 784267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 798028dd32a4a04154050220dd0693583d5b750330Adam Powell public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) { 808028dd32a4a04154050220dd0693583d5b750330Adam Powell this(context, menu, anchorView, false); 818028dd32a4a04154050220dd0693583d5b750330Adam Powell } 828028dd32a4a04154050220dd0693583d5b750330Adam Powell 838028dd32a4a04154050220dd0693583d5b750330Adam Powell public MenuPopupHelper(Context context, MenuBuilder menu, 848028dd32a4a04154050220dd0693583d5b750330Adam Powell View anchorView, boolean overflowOnly) { 854267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell mContext = context; 86696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mInflater = LayoutInflater.from(context); 878028dd32a4a04154050220dd0693583d5b750330Adam Powell mMenu = menu; 880bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mAdapter = new MenuAdapter(mMenu); 898028dd32a4a04154050220dd0693583d5b750330Adam Powell mOverflowOnly = overflowOnly; 904267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 9138639b1d75933bfb720db79fce26f09478709614Adam Powell final Resources res = context.getResources(); 9238639b1d75933bfb720db79fce26f09478709614Adam Powell mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2, 9338639b1d75933bfb720db79fce26f09478709614Adam Powell res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth)); 948028dd32a4a04154050220dd0693583d5b750330Adam Powell 954afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mAnchorView = anchorView; 96696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 97696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell menu.addMenuPresenter(this); 984267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 994267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 100f0ad6e6eaf48ac8f4007232ad0a8511a7b5cfc0eAdam Powell public void setAnchorView(View anchor) { 1014afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mAnchorView = anchor; 102f0ad6e6eaf48ac8f4007232ad0a8511a7b5cfc0eAdam Powell } 103f0ad6e6eaf48ac8f4007232ad0a8511a7b5cfc0eAdam Powell 1049151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell public void setForceShowIcon(boolean forceShow) { 1059151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell mForceShowIcon = forceShow; 1069151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell } 1079151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell 10854c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell public void setGravity(int gravity) { 10954c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell mDropDownGravity = gravity; 11054c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell } 11154c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell 1124267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell public void show() { 1135e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell if (!tryShow()) { 1145e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); 1155e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell } 1165e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell } 1175e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell 118ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette public ListPopupWindow getPopup() { 119ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette return mPopup; 120ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 121ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1225e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell public boolean tryShow() { 1230b2d306e7000f4c0c6ad4e00d494bb401d8a9fc2Adam Powell mPopup = new ListPopupWindow(mContext, null, com.android.internal.R.attr.popupMenuStyle); 1248515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell mPopup.setOnDismissListener(this); 125696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPopup.setOnItemClickListener(this); 126696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPopup.setAdapter(mAdapter); 1274267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell mPopup.setModal(true); 1284267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 1294afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell View anchor = mAnchorView; 1300458796f1401732b38660794148f4c5e5602f432Adam Powell if (anchor != null) { 1314afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell final boolean addGlobalListener = mTreeObserver == null; 1324afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest 1334afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this); 1344afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell anchor.addOnAttachStateChangeListener(this); 1350458796f1401732b38660794148f4c5e5602f432Adam Powell mPopup.setAnchorView(anchor); 13654c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell mPopup.setDropDownGravity(mDropDownGravity); 1374be0d52125b88dc992a4c500edbe95bf55484e0bAdam Powell } else { 1385e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell return false; 1398028dd32a4a04154050220dd0693583d5b750330Adam Powell } 1404267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 1410bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette if (!mHasContentWidth) { 1420bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mContentWidth = measureContentWidth(); 1430bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mHasContentWidth = true; 1440bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette } 1450bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 1460bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mPopup.setContentWidth(mContentWidth); 147aa0b92ce2b51987e9c864164234fe968ab5b9311Adam Powell mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); 1484267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell mPopup.show(); 1498028dd32a4a04154050220dd0693583d5b750330Adam Powell mPopup.getListView().setOnKeyListener(this); 1505e3f284baa271cb0fbf90e504d19fdd2e385382eAdam Powell return true; 1514267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 1524267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 1534267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell public void dismiss() { 1543d3da27ab394108fd51771616cca3279baae99d1Adam Powell if (isShowing()) { 1553d3da27ab394108fd51771616cca3279baae99d1Adam Powell mPopup.dismiss(); 1563d3da27ab394108fd51771616cca3279baae99d1Adam Powell } 1578515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell } 1588515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell 1598515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell public void onDismiss() { 1608515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell mPopup = null; 16142b91bbcdaf64b2f19d0a9ce168964b31a5dc139Adam Powell mMenu.close(); 1624afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (mTreeObserver != null) { 1634afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver(); 164ca51e8788a58f2af3525b7214a675f2d0233e5daAdam Powell mTreeObserver.removeGlobalOnLayoutListener(this); 1654afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mTreeObserver = null; 166ed8b403cc8066bf76cdf98f8d9906ff810defc5bAdam Powell } 1674afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mAnchorView.removeOnAttachStateChangeListener(this); 1684267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 1694267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 1708028dd32a4a04154050220dd0693583d5b750330Adam Powell public boolean isShowing() { 1718028dd32a4a04154050220dd0693583d5b750330Adam Powell return mPopup != null && mPopup.isShowing(); 1728028dd32a4a04154050220dd0693583d5b750330Adam Powell } 1738028dd32a4a04154050220dd0693583d5b750330Adam Powell 174696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 1754267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 176696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell MenuAdapter adapter = mAdapter; 177696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); 1784267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 1794267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 1808028dd32a4a04154050220dd0693583d5b750330Adam Powell public boolean onKey(View v, int keyCode, KeyEvent event) { 1818028dd32a4a04154050220dd0693583d5b750330Adam Powell if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { 1828028dd32a4a04154050220dd0693583d5b750330Adam Powell dismiss(); 1838028dd32a4a04154050220dd0693583d5b750330Adam Powell return true; 1848028dd32a4a04154050220dd0693583d5b750330Adam Powell } 1858028dd32a4a04154050220dd0693583d5b750330Adam Powell return false; 1868028dd32a4a04154050220dd0693583d5b750330Adam Powell } 1878028dd32a4a04154050220dd0693583d5b750330Adam Powell 1880bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette private int measureContentWidth() { 1894267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell // Menus don't tend to be long, so this is more sane than it looks. 1900bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette int maxWidth = 0; 1914267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell View itemView = null; 19250f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell int itemType = 0; 1930bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 1940bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette final ListAdapter adapter = mAdapter; 1950bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 1960bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 1974267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell final int count = adapter.getCount(); 1984267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell for (int i = 0; i < count; i++) { 19950f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell final int positionType = adapter.getItemViewType(i); 20050f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell if (positionType != itemType) { 20150f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell itemType = positionType; 20250f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell itemView = null; 20350f784cf2dc2dea8061153ac3a843f60a9d88781Adam Powell } 2040bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2059151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell if (mMeasureParent == null) { 2069151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell mMeasureParent = new FrameLayout(mContext); 2079151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell } 2080bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2099151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell itemView = adapter.getView(i, itemView, mMeasureParent); 2104267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell itemView.measure(widthMeasureSpec, heightMeasureSpec); 2110bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2120bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette final int itemWidth = itemView.getMeasuredWidth(); 2130bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette if (itemWidth >= mPopupMaxWidth) { 2140bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette return mPopupMaxWidth; 2150bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette } else if (itemWidth > maxWidth) { 2160bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette maxWidth = itemWidth; 2170bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette } 2184267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 2190bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2200bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette return maxWidth; 2214267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 2220458796f1401732b38660794148f4c5e5602f432Adam Powell 2230458796f1401732b38660794148f4c5e5602f432Adam Powell @Override 2240458796f1401732b38660794148f4c5e5602f432Adam Powell public void onGlobalLayout() { 2254afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (isShowing()) { 2264afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell final View anchor = mAnchorView; 227ca51e8788a58f2af3525b7214a675f2d0233e5daAdam Powell if (anchor == null || !anchor.isShown()) { 2280458796f1401732b38660794148f4c5e5602f432Adam Powell dismiss(); 229ca51e8788a58f2af3525b7214a675f2d0233e5daAdam Powell } else if (isShowing()) { 230aa0b92ce2b51987e9c864164234fe968ab5b9311Adam Powell // Recompute window size and position 231aa0b92ce2b51987e9c864164234fe968ab5b9311Adam Powell mPopup.show(); 2320458796f1401732b38660794148f4c5e5602f432Adam Powell } 2330458796f1401732b38660794148f4c5e5602f432Adam Powell } 2340458796f1401732b38660794148f4c5e5602f432Adam Powell } 2354afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell 2364afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell @Override 2374afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell public void onViewAttachedToWindow(View v) { 2384afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell } 2394afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell 2404afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell @Override 2414afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell public void onViewDetachedFromWindow(View v) { 2424afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (mTreeObserver != null) { 2434afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver(); 2444afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell mTreeObserver.removeGlobalOnLayoutListener(this); 2454afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell } 2464afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell v.removeOnAttachStateChangeListener(this); 2474afd62b18c52a55371ab923d54f93615ad68fd7aAdam Powell } 248696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 249696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 250696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public void initForMenu(Context context, MenuBuilder menu) { 251696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell // Don't need to do anything; we added as a presenter in the constructor. 252696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 253696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 254696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 255696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public MenuView getMenuView(ViewGroup root) { 256696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell throw new UnsupportedOperationException("MenuPopupHelpers manage their own views"); 257696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 258696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 259696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 260696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public void updateMenuView(boolean cleared) { 2610bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mHasContentWidth = false; 2620bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette 2630bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette if (mAdapter != null) { 2640bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette mAdapter.notifyDataSetChanged(); 2650bce6ab8cd8aadc9784dda2f3f4cc9dd91b796c7Alan Viverette } 266696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 267696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 268696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 269696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public void setCallback(Callback cb) { 270696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenterCallback = cb; 271696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 272696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 273696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 274696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 275696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (subMenu.hasVisibleItems()) { 276696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false); 277696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell subPopup.setCallback(mPresenterCallback); 2789151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell 2799151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell boolean preserveIconSpacing = false; 2809151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell final int count = subMenu.size(); 2819151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell for (int i = 0; i < count; i++) { 2829151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell MenuItem childItem = subMenu.getItem(i); 2839151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell if (childItem.isVisible() && childItem.getIcon() != null) { 2849151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell preserveIconSpacing = true; 2859151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell break; 2869151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell } 2879151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell } 2889151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell subPopup.setForceShowIcon(preserveIconSpacing); 2899151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell 290696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (subPopup.tryShow()) { 291696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (mPresenterCallback != null) { 292696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenterCallback.onOpenSubMenu(subMenu); 293696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 294696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return true; 295696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 296696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 297696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return false; 298696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 299696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 300696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 301696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 302696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell // Only care about the (sub)menu we're presenting. 303696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (menu != mMenu) return; 304696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 305696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell dismiss(); 306696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (mPresenterCallback != null) { 307696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenterCallback.onCloseMenu(menu, allMenusAreClosing); 308696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 309696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 310696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 311696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 312696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public boolean flagActionItems() { 313696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return false; 314696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 315696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 3168d02deabac62c4a68a335a7b3141795466362b89Adam Powell public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { 3178d02deabac62c4a68a335a7b3141795466362b89Adam Powell return false; 3188d02deabac62c4a68a335a7b3141795466362b89Adam Powell } 3198d02deabac62c4a68a335a7b3141795466362b89Adam Powell 3208d02deabac62c4a68a335a7b3141795466362b89Adam Powell public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { 3218d02deabac62c4a68a335a7b3141795466362b89Adam Powell return false; 3228d02deabac62c4a68a335a7b3141795466362b89Adam Powell } 3238d02deabac62c4a68a335a7b3141795466362b89Adam Powell 324275702c2f47ed87ab642462530092d9777f32ecdAdam Powell @Override 325275702c2f47ed87ab642462530092d9777f32ecdAdam Powell public int getId() { 326275702c2f47ed87ab642462530092d9777f32ecdAdam Powell return 0; 327275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 328275702c2f47ed87ab642462530092d9777f32ecdAdam Powell 329275702c2f47ed87ab642462530092d9777f32ecdAdam Powell @Override 330275702c2f47ed87ab642462530092d9777f32ecdAdam Powell public Parcelable onSaveInstanceState() { 331275702c2f47ed87ab642462530092d9777f32ecdAdam Powell return null; 332275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 333275702c2f47ed87ab642462530092d9777f32ecdAdam Powell 334275702c2f47ed87ab642462530092d9777f32ecdAdam Powell @Override 335275702c2f47ed87ab642462530092d9777f32ecdAdam Powell public void onRestoreInstanceState(Parcelable state) { 336275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 337275702c2f47ed87ab642462530092d9777f32ecdAdam Powell 338696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell private class MenuAdapter extends BaseAdapter { 339696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell private MenuBuilder mAdapterMenu; 340275702c2f47ed87ab642462530092d9777f32ecdAdam Powell private int mExpandedIndex = -1; 341696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 342696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public MenuAdapter(MenuBuilder menu) { 343696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mAdapterMenu = menu; 344275702c2f47ed87ab642462530092d9777f32ecdAdam Powell findExpandedIndex(); 345696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 346696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 347696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public int getCount() { 348696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell ArrayList<MenuItemImpl> items = mOverflowOnly ? 349696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems(); 350275702c2f47ed87ab642462530092d9777f32ecdAdam Powell if (mExpandedIndex < 0) { 351275702c2f47ed87ab642462530092d9777f32ecdAdam Powell return items.size(); 352275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 353275702c2f47ed87ab642462530092d9777f32ecdAdam Powell return items.size() - 1; 354696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 355696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 356696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public MenuItemImpl getItem(int position) { 357696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell ArrayList<MenuItemImpl> items = mOverflowOnly ? 358696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems(); 359275702c2f47ed87ab642462530092d9777f32ecdAdam Powell if (mExpandedIndex >= 0 && position >= mExpandedIndex) { 360275702c2f47ed87ab642462530092d9777f32ecdAdam Powell position++; 361275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 362696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return items.get(position); 363696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 364696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 365696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public long getItemId(int position) { 366696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell // Since a menu item's ID is optional, we'll use the position as an 367696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell // ID for the item in the AdapterView 368696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return position; 369696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 370696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 371696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public View getView(int position, View convertView, ViewGroup parent) { 372696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (convertView == null) { 373696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell convertView = mInflater.inflate(ITEM_LAYOUT, parent, false); 374696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 375696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 376696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell MenuView.ItemView itemView = (MenuView.ItemView) convertView; 3779151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell if (mForceShowIcon) { 3789151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell ((ListMenuItemView) convertView).setForceShowIcon(true); 3799151103ff20d28e8db2a2cc0386d57b8dad4b5d5Adam Powell } 380696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell itemView.initialize(getItem(position), 0); 381696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell return convertView; 382696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 38311ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell 384275702c2f47ed87ab642462530092d9777f32ecdAdam Powell void findExpandedIndex() { 385275702c2f47ed87ab642462530092d9777f32ecdAdam Powell final MenuItemImpl expandedItem = mMenu.getExpandedItem(); 386275702c2f47ed87ab642462530092d9777f32ecdAdam Powell if (expandedItem != null) { 387275702c2f47ed87ab642462530092d9777f32ecdAdam Powell final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems(); 388275702c2f47ed87ab642462530092d9777f32ecdAdam Powell final int count = items.size(); 389275702c2f47ed87ab642462530092d9777f32ecdAdam Powell for (int i = 0; i < count; i++) { 390275702c2f47ed87ab642462530092d9777f32ecdAdam Powell final MenuItemImpl item = items.get(i); 391275702c2f47ed87ab642462530092d9777f32ecdAdam Powell if (item == expandedItem) { 392275702c2f47ed87ab642462530092d9777f32ecdAdam Powell mExpandedIndex = i; 393275702c2f47ed87ab642462530092d9777f32ecdAdam Powell return; 394275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 395275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 396275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 397275702c2f47ed87ab642462530092d9777f32ecdAdam Powell mExpandedIndex = -1; 398275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 39911ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell 400275702c2f47ed87ab642462530092d9777f32ecdAdam Powell @Override 40176889f3482d6391b17f0961f7356c1e8169c8813Adam Powell public void notifyDataSetChanged() { 40276889f3482d6391b17f0961f7356c1e8169c8813Adam Powell findExpandedIndex(); 40376889f3482d6391b17f0961f7356c1e8169c8813Adam Powell super.notifyDataSetChanged(); 404275702c2f47ed87ab642462530092d9777f32ecdAdam Powell } 40511ed1d6cae9214335c92ac38498a4e6c7d1c8324Adam Powell } 4064267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell} 407