196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell/*
296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * Copyright (C) 2010 The Android Open Source Project
396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell *
496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * Licensed under the Apache License, Version 2.0 (the "License");
596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * you may not use this file except in compliance with the License.
696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * You may obtain a copy of the License at
796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell *
896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell *      http://www.apache.org/licenses/LICENSE-2.0
996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell *
1096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * Unless required by applicable law or agreed to in writing, software
1196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * distributed under the License is distributed on an "AS IS" BASIS,
1296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * See the License for the specific language governing permissions and
1496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * limitations under the License.
1596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell */
1696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
1796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellpackage com.android.internal.view.menu;
1896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
1996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.content.Context;
20d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powellimport android.content.res.Configuration;
2135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powellimport android.content.res.Resources;
2224340afbab8ad4c191784fda8023407205bc0a75Adam Powellimport android.content.res.TypedArray;
237b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powellimport android.graphics.Rect;
2496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.graphics.drawable.Drawable;
259c661a40c1f8adfbf84883fbf5efb51ed0cf2fe2Aurimas Liutikasimport android.os.Parcelable;
26c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunneimport android.text.TextUtils;
2796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.util.AttributeSet;
287b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powellimport android.view.Gravity;
297bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powellimport android.view.MotionEvent;
3096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.view.View;
317bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powellimport android.view.accessibility.AccessibilityEvent;
32fa18d182a3f37505940e73ae6cd76c2e939f7f7cAdam Powellimport android.widget.ActionMenuView;
33f44d90b5c247f0629201d1fa322b83fa55b20608Oren Blasbergimport android.widget.ForwardingListener;
3475d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powellimport android.widget.TextView;
357b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powellimport android.widget.Toast;
3696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
3796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell/**
3896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * @hide
3996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell */
4075d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powellpublic class ActionMenuItemView extends TextView
417b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener,
427b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        ActionMenuView.ActionMenuChildView {
4396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private static final String TAG = "ActionMenuItemView";
44a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
4596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private MenuItemImpl mItemData;
4696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private CharSequence mTitle;
4775d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell    private Drawable mIcon;
4896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private MenuBuilder.ItemInvoker mItemInvoker;
4956110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    private ForwardingListener mForwardingListener;
5056110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    private PopupCallback mPopupCallback;
51a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
5235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    private boolean mAllowTextWithIcon;
5335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    private boolean mExpandedFormat;
5424340afbab8ad4c191784fda8023407205bc0a75Adam Powell    private int mMinWidth;
5575d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell    private int mSavedPaddingLeft;
561f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell
57c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell    private static final int MAX_ICON_SIZE = 32; // dp
58c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell    private int mMaxIconSize;
59c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell
6096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public ActionMenuItemView(Context context) {
6196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        this(context, null);
6296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
63a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
6496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public ActionMenuItemView(Context context, AttributeSet attrs) {
6535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        this(context, attrs, 0);
6696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
67a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
68617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public ActionMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
69617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
70617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
71617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
72617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public ActionMenuItemView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
73617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
7435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final Resources res = context.getResources();
75b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski        mAllowTextWithIcon = shouldAllowTextWithIcon();
76617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(attrs,
77617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                com.android.internal.R.styleable.ActionMenuItemView, defStyleAttr, defStyleRes);
7824340afbab8ad4c191784fda8023407205bc0a75Adam Powell        mMinWidth = a.getDimensionPixelSize(
7924340afbab8ad4c191784fda8023407205bc0a75Adam Powell                com.android.internal.R.styleable.ActionMenuItemView_minWidth, 0);
8024340afbab8ad4c191784fda8023407205bc0a75Adam Powell        a.recycle();
8196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
82c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell        final float density = res.getDisplayMetrics().density;
83c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell        mMaxIconSize = (int) (MAX_ICON_SIZE * density + 0.5f);
84c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell
856bddd8771d05889024778caa78fb1eaae68a0802Adam Powell        setOnClickListener(this);
867b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        setOnLongClickListener(this);
8775d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell
88367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        mSavedPaddingLeft = -1;
899c661a40c1f8adfbf84883fbf5efb51ed0cf2fe2Aurimas Liutikas        setSaveEnabled(false);
90367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell    }
91367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell
92367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell    @Override
93d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell    public void onConfigurationChanged(Configuration newConfig) {
94d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell        super.onConfigurationChanged(newConfig);
95d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell
96b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski        mAllowTextWithIcon = shouldAllowTextWithIcon();
97d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell        updateTextButtonVisibility();
98d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell    }
99d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell
100b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski    /**
101b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski     * Whether action menu items should obey the "withText" showAsAction flag. This may be set to
102b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski     * false for situations where space is extremely limited. -->
103b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski     */
104b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski    private boolean shouldAllowTextWithIcon() {
105b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski        final Configuration configuration = getContext().getResources().getConfiguration();
106b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski        final int width = configuration.screenWidthDp;
107b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski        final int height = configuration.screenHeightDp;
108b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski        return  width >= 480 || (width >= 640 && height >= 480)
109b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski                || configuration.orientation == Configuration.ORIENTATION_LANDSCAPE;
110b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski    }
111b635fdaf22795817f9417c475e82bfb0191dd5bdFilip Gruszczynski
112d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell    @Override
113367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell    public void setPadding(int l, int t, int r, int b) {
114367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        mSavedPaddingLeft = l;
115367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        super.setPadding(l, t, r, b);
1161f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell    }
1171f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell
11896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public MenuItemImpl getItemData() {
11996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        return mItemData;
12096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
12196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
12256110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    @Override
12396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void initialize(MenuItemImpl itemData, int menuType) {
12496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mItemData = itemData;
125a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
12696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        setIcon(itemData.getIcon());
127e7d468410b3a783560d5158a5798cef1b4b67702Adam Powell        setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon
12896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        setId(itemData.getItemId());
129a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
13096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
13196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        setEnabled(itemData.isEnabled());
13256110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette
13356110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        if (itemData.hasSubMenu()) {
13456110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            if (mForwardingListener == null) {
13556110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette                mForwardingListener = new ActionMenuItemForwardingListener();
13656110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            }
13756110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        }
13856110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    }
13956110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette
14056110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    @Override
14156110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    public boolean onTouchEvent(MotionEvent e) {
14256110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        if (mItemData.hasSubMenu() && mForwardingListener != null
14356110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette                && mForwardingListener.onTouch(this, e)) {
14456110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            return true;
14556110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        }
14656110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        return super.onTouchEvent(e);
14796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
148a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
14956110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    @Override
1501f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell    public void onClick(View v) {
1511f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell        if (mItemInvoker != null) {
1521f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell            mItemInvoker.invokeItem(mItemData);
15396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        }
15496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
155a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
15696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setItemInvoker(MenuBuilder.ItemInvoker invoker) {
15796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mItemInvoker = invoker;
15896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
15996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
16056110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    public void setPopupCallback(PopupCallback popupCallback) {
16156110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        mPopupCallback = popupCallback;
16256110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    }
16356110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette
16496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public boolean prefersCondensedTitle() {
165e7d468410b3a783560d5158a5798cef1b4b67702Adam Powell        return true;
16696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
16796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
16896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setCheckable(boolean checkable) {
16996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        // TODO Support checkable action items
17096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
17196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
17296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setChecked(boolean checked) {
17396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        // TODO Support checkable action items
17496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
17596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
17635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    public void setExpandedFormat(boolean expandedFormat) {
17735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        if (mExpandedFormat != expandedFormat) {
17835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            mExpandedFormat = expandedFormat;
17935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            if (mItemData != null) {
18035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                mItemData.actionFormatChanged();
18135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            }
18235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
18335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    }
18435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
185c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne    private void updateTextButtonVisibility() {
18675d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        boolean visible = !TextUtils.isEmpty(mTitle);
18775d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        visible &= mIcon == null ||
18835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                (mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat));
18935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
19075d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        setText(visible ? mTitle : null);
191c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne    }
192c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne
19396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setIcon(Drawable icon) {
19475d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        mIcon = icon;
195c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell        if (icon != null) {
196c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            int width = icon.getIntrinsicWidth();
197c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            int height = icon.getIntrinsicHeight();
198c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            if (width > mMaxIconSize) {
199c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                final float scale = (float) mMaxIconSize / width;
200c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                width = mMaxIconSize;
201c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                height *= scale;
202c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            }
203c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            if (height > mMaxIconSize) {
204c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                final float scale = (float) mMaxIconSize / height;
205c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                height = mMaxIconSize;
206c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                width *= scale;
207c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            }
208c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            icon.setBounds(0, 0, width, height);
209c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell        }
210c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell        setCompoundDrawables(icon, null, null, null);
2119f125d341521efc8535e32e35a641be50d405c36Adam Powell
212c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne        updateTextButtonVisibility();
21396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
214c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne
215be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell    public boolean hasText() {
21675d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        return !TextUtils.isEmpty(getText());
217be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell    }
21896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
21996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setShortcut(boolean showShortcut, char shortcutKey) {
22096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        // Action buttons don't show text for shortcut keys.
22196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
22296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
22396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setTitle(CharSequence title) {
22496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mTitle = title;
225a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
2267bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        setContentDescription(mTitle);
227c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne        updateTextButtonVisibility();
22896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
22996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
2307bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    @Override
231a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
2327bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        onPopulateAccessibilityEvent(event);
2337bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        return true;
2347bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    }
2357bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell
2367bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    @Override
237a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette    public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
238a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette        super.onPopulateAccessibilityEventInternal(event);
2397bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        final CharSequence cdesc = getContentDescription();
2407bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        if (!TextUtils.isEmpty(cdesc)) {
2417bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell            event.getText().add(cdesc);
2427bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        }
2437bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    }
2447bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell
2457bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    @Override
2467bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    public boolean dispatchHoverEvent(MotionEvent event) {
2477bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        // Don't allow children to hover; we want this to be treated as a single component.
2487bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        return onHoverEvent(event);
2497bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    }
2507bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell
25196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public boolean showsIcon() {
25296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        return true;
25396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
254696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
255696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean needsDividerBefore() {
256696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return hasText() && mItemData.getIcon() == null;
257696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
258696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
259696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean needsDividerAfter() {
260696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return hasText();
261696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
2627b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell
2637b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell    @Override
2647b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell    public boolean onLongClick(View v) {
2657b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        if (hasText()) {
2667b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell            // Don't show the cheat sheet for items that already show text.
2677b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell            return false;
2687b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        }
2697b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell
2707b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final int[] screenPos = new int[2];
2717b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final Rect displayFrame = new Rect();
2727b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        getLocationOnScreen(screenPos);
2737b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        getWindowVisibleDisplayFrame(displayFrame);
2747b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell
2757b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final Context context = getContext();
2767b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final int width = getWidth();
2777b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final int height = getHeight();
2787b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final int midy = screenPos[1] + height / 2;
279d719539f91d4f5cf6c0f9be0b68b750dcd443433Yigit Boyar        int referenceX = screenPos[0] + width / 2;
280d719539f91d4f5cf6c0f9be0b68b750dcd443433Yigit Boyar        if (v.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) {
281d719539f91d4f5cf6c0f9be0b68b750dcd443433Yigit Boyar            final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
282d719539f91d4f5cf6c0f9be0b68b750dcd443433Yigit Boyar            referenceX = screenWidth - referenceX; // mirror
283d719539f91d4f5cf6c0f9be0b68b750dcd443433Yigit Boyar        }
2847b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT);
2857b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        if (midy < displayFrame.height()) {
2867b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell            // Show along the top; follow action buttons
287d74f960eceb98042ede53f74d02e174eb1ad5944Chris Banes            cheatSheet.setGravity(Gravity.TOP | Gravity.END, referenceX,
288d74f960eceb98042ede53f74d02e174eb1ad5944Chris Banes                    screenPos[1] + height - displayFrame.top);
2897b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        } else {
2907b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell            // Show along the bottom center
2917b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell            cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
2927b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        }
2937b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        cheatSheet.show();
2947b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        return true;
2957b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell    }
29624340afbab8ad4c191784fda8023407205bc0a75Adam Powell
29724340afbab8ad4c191784fda8023407205bc0a75Adam Powell    @Override
29824340afbab8ad4c191784fda8023407205bc0a75Adam Powell    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
29975d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        final boolean textVisible = hasText();
300367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        if (textVisible && mSavedPaddingLeft >= 0) {
301367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell            super.setPadding(mSavedPaddingLeft, getPaddingTop(),
302367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell                    getPaddingRight(), getPaddingBottom());
30375d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        }
30475d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell
30524340afbab8ad4c191784fda8023407205bc0a75Adam Powell        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
30624340afbab8ad4c191784fda8023407205bc0a75Adam Powell
30724340afbab8ad4c191784fda8023407205bc0a75Adam Powell        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
30875d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
30924340afbab8ad4c191784fda8023407205bc0a75Adam Powell        final int oldMeasuredWidth = getMeasuredWidth();
31075d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(widthSize, mMinWidth)
31124340afbab8ad4c191784fda8023407205bc0a75Adam Powell                : mMinWidth;
31224340afbab8ad4c191784fda8023407205bc0a75Adam Powell
31324340afbab8ad4c191784fda8023407205bc0a75Adam Powell        if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) {
31424340afbab8ad4c191784fda8023407205bc0a75Adam Powell            // Remeasure at exactly the minimum width.
31524340afbab8ad4c191784fda8023407205bc0a75Adam Powell            super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
31624340afbab8ad4c191784fda8023407205bc0a75Adam Powell                    heightMeasureSpec);
31724340afbab8ad4c191784fda8023407205bc0a75Adam Powell        }
31875d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell
31975d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        if (!textVisible && mIcon != null) {
32075d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell            // TextView won't center compound drawables in both dimensions without
32175d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell            // a little coercion. Pad in to center the icon after we've measured.
32275d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell            final int w = getMeasuredWidth();
323c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell            final int dw = mIcon.getBounds().width();
324367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell            super.setPadding((w - dw) / 2, getPaddingTop(), getPaddingRight(), getPaddingBottom());
32575d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        }
32624340afbab8ad4c191784fda8023407205bc0a75Adam Powell    }
32756110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette
32856110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    private class ActionMenuItemForwardingListener extends ForwardingListener {
32956110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        public ActionMenuItemForwardingListener() {
33056110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            super(ActionMenuItemView.this);
33156110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        }
33256110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette
33356110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        @Override
334f44d90b5c247f0629201d1fa322b83fa55b20608Oren Blasberg        public ShowableListMenu getPopup() {
33556110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            if (mPopupCallback != null) {
33656110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette                return mPopupCallback.getPopup();
33756110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            }
33856110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            return null;
33956110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        }
34056110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette
34156110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        @Override
34256110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        protected boolean onForwardingStarted() {
34356110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            // Call the invoker, then check if the expected popup is showing.
34456110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            if (mItemInvoker != null && mItemInvoker.invokeItem(mItemData)) {
345f44d90b5c247f0629201d1fa322b83fa55b20608Oren Blasberg                final ShowableListMenu popup = getPopup();
34656110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette                return popup != null && popup.isShowing();
34756110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            }
34856110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette            return false;
34956110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette        }
35056110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    }
35156110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette
3529c661a40c1f8adfbf84883fbf5efb51ed0cf2fe2Aurimas Liutikas    @Override
3539c661a40c1f8adfbf84883fbf5efb51ed0cf2fe2Aurimas Liutikas    public void onRestoreInstanceState(Parcelable state) {
3549c661a40c1f8adfbf84883fbf5efb51ed0cf2fe2Aurimas Liutikas        // This might get called with the state of ActionView since it shares the same ID with
3559c661a40c1f8adfbf84883fbf5efb51ed0cf2fe2Aurimas Liutikas        // ActionMenuItemView. Do not restore this state as ActionMenuItemView never saved it.
3569c661a40c1f8adfbf84883fbf5efb51ed0cf2fe2Aurimas Liutikas        super.onRestoreInstanceState(null);
3579c661a40c1f8adfbf84883fbf5efb51ed0cf2fe2Aurimas Liutikas    }
3589c661a40c1f8adfbf84883fbf5efb51ed0cf2fe2Aurimas Liutikas
35956110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    public static abstract class PopupCallback {
360f44d90b5c247f0629201d1fa322b83fa55b20608Oren Blasberg        public abstract ShowableListMenu getPopup();
36156110725f2a0b3f09703f2cbe9705d97609ee1e5Alan Viverette    }
36296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell}
363