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