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;
25c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunneimport android.text.TextUtils;
2696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.util.AttributeSet;
277b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powellimport android.view.Gravity;
287bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powellimport android.view.MotionEvent;
2996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.view.View;
307bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powellimport android.view.accessibility.AccessibilityEvent;
3175d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powellimport android.widget.TextView;
327b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powellimport android.widget.Toast;
3396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
3496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell/**
3596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * @hide
3696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell */
3775d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powellpublic class ActionMenuItemView extends TextView
387b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener,
397b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        ActionMenuView.ActionMenuChildView {
4096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private static final String TAG = "ActionMenuItemView";
41a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
4296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private MenuItemImpl mItemData;
4396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private CharSequence mTitle;
4475d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell    private Drawable mIcon;
4596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    private MenuBuilder.ItemInvoker mItemInvoker;
46a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
4735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    private boolean mAllowTextWithIcon;
4835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    private boolean mExpandedFormat;
4924340afbab8ad4c191784fda8023407205bc0a75Adam Powell    private int mMinWidth;
5075d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell    private int mSavedPaddingLeft;
511f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell
52c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell    private static final int MAX_ICON_SIZE = 32; // dp
53c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell    private int mMaxIconSize;
54c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell
5596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public ActionMenuItemView(Context context) {
5696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        this(context, null);
5796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
58a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
5996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public ActionMenuItemView(Context context, AttributeSet attrs) {
6035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        this(context, attrs, 0);
6196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
62a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
6396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) {
6496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        super(context, attrs, defStyle);
6535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        final Resources res = context.getResources();
6635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        mAllowTextWithIcon = res.getBoolean(
6735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
6824340afbab8ad4c191784fda8023407205bc0a75Adam Powell        TypedArray a = context.obtainStyledAttributes(attrs,
6924340afbab8ad4c191784fda8023407205bc0a75Adam Powell                com.android.internal.R.styleable.ActionMenuItemView, 0, 0);
7024340afbab8ad4c191784fda8023407205bc0a75Adam Powell        mMinWidth = a.getDimensionPixelSize(
7124340afbab8ad4c191784fda8023407205bc0a75Adam Powell                com.android.internal.R.styleable.ActionMenuItemView_minWidth, 0);
7224340afbab8ad4c191784fda8023407205bc0a75Adam Powell        a.recycle();
7396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
74c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell        final float density = res.getDisplayMetrics().density;
75c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell        mMaxIconSize = (int) (MAX_ICON_SIZE * density + 0.5f);
76c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell
776bddd8771d05889024778caa78fb1eaae68a0802Adam Powell        setOnClickListener(this);
787b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        setOnLongClickListener(this);
7975d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell
80367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        mSavedPaddingLeft = -1;
81367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell    }
82367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell
83367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell    @Override
84d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell    public void onConfigurationChanged(Configuration newConfig) {
85d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell        super.onConfigurationChanged(newConfig);
86d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell
87d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell        mAllowTextWithIcon = getContext().getResources().getBoolean(
88d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell                com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
89d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell        updateTextButtonVisibility();
90d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell    }
91d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell
92d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell    @Override
93367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell    public void setPadding(int l, int t, int r, int b) {
94367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        mSavedPaddingLeft = l;
95367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        super.setPadding(l, t, r, b);
961f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell    }
971f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell
9896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public MenuItemImpl getItemData() {
9996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        return mItemData;
10096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
10196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
10296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void initialize(MenuItemImpl itemData, int menuType) {
10396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mItemData = itemData;
104a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
10596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        setIcon(itemData.getIcon());
106e7d468410b3a783560d5158a5798cef1b4b67702Adam Powell        setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon
10796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        setId(itemData.getItemId());
108a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
10996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
11096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        setEnabled(itemData.isEnabled());
11196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
112a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
1131f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell    public void onClick(View v) {
1141f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell        if (mItemInvoker != null) {
1151f9c7afc5a06576e327a4b1c12688202f53d9462Adam Powell            mItemInvoker.invokeItem(mItemData);
11696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        }
11796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
118a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
11996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setItemInvoker(MenuBuilder.ItemInvoker invoker) {
12096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mItemInvoker = invoker;
12196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
12296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
12396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public boolean prefersCondensedTitle() {
124e7d468410b3a783560d5158a5798cef1b4b67702Adam Powell        return true;
12596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
12696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
12796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setCheckable(boolean checkable) {
12896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        // TODO Support checkable action items
12996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
13096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
13196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setChecked(boolean checked) {
13296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        // TODO Support checkable action items
13396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
13496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
13535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    public void setExpandedFormat(boolean expandedFormat) {
13635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        if (mExpandedFormat != expandedFormat) {
13735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            mExpandedFormat = expandedFormat;
13835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            if (mItemData != null) {
13935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                mItemData.actionFormatChanged();
14035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell            }
14135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell        }
14235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell    }
14335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
144c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne    private void updateTextButtonVisibility() {
14575d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        boolean visible = !TextUtils.isEmpty(mTitle);
14675d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        visible &= mIcon == null ||
14735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell                (mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat));
14835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell
14975d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        setText(visible ? mTitle : null);
150c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne    }
151c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne
15296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setIcon(Drawable icon) {
15375d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        mIcon = icon;
154c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell        if (icon != null) {
155c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            int width = icon.getIntrinsicWidth();
156c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            int height = icon.getIntrinsicHeight();
157c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            if (width > mMaxIconSize) {
158c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                final float scale = (float) mMaxIconSize / width;
159c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                width = mMaxIconSize;
160c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                height *= scale;
161c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            }
162c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            if (height > mMaxIconSize) {
163c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                final float scale = (float) mMaxIconSize / height;
164c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                height = mMaxIconSize;
165c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell                width *= scale;
166c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            }
167c1eea136eaae62091b44d7b06a3d61ac694e4fd7Adam Powell            icon.setBounds(0, 0, width, height);
168c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell        }
169c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell        setCompoundDrawables(icon, null, null, null);
1709f125d341521efc8535e32e35a641be50d405c36Adam Powell
171c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne        updateTextButtonVisibility();
17296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
173c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne
174be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell    public boolean hasText() {
17575d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        return !TextUtils.isEmpty(getText());
176be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell    }
17796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
17896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setShortcut(boolean showShortcut, char shortcutKey) {
17996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        // Action buttons don't show text for shortcut keys.
18096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
18196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
18296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public void setTitle(CharSequence title) {
18396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        mTitle = title;
184a8a72c38fec3879f5d346840b0d186d5903931b8Jeff Sharkey
1857bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        setContentDescription(mTitle);
186c619e74cc62678cef09b5f92e87e762a1f02aab7Gilles Debunne        updateTextButtonVisibility();
18796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
18896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell
1897bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    @Override
1907bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1917bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        onPopulateAccessibilityEvent(event);
1927bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        return true;
1937bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    }
1947bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell
1957bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    @Override
1967bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
1977bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        super.onPopulateAccessibilityEvent(event);
1987bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        final CharSequence cdesc = getContentDescription();
1997bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        if (!TextUtils.isEmpty(cdesc)) {
2007bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell            event.getText().add(cdesc);
2017bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        }
2027bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    }
2037bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell
2047bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    @Override
2057bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    public boolean dispatchHoverEvent(MotionEvent event) {
2067bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        // Don't allow children to hover; we want this to be treated as a single component.
2077bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell        return onHoverEvent(event);
2087bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell    }
2097bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell
21096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    public boolean showsIcon() {
21196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell        return true;
21296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell    }
213696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
214696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean needsDividerBefore() {
215696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return hasText() && mItemData.getIcon() == null;
216696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
217696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
218696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public boolean needsDividerAfter() {
219696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return hasText();
220696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
2217b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell
2227b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell    @Override
2237b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell    public boolean onLongClick(View v) {
2247b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        if (hasText()) {
2257b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell            // Don't show the cheat sheet for items that already show text.
2267b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell            return false;
2277b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        }
2287b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell
2297b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final int[] screenPos = new int[2];
2307b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final Rect displayFrame = new Rect();
2317b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        getLocationOnScreen(screenPos);
2327b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        getWindowVisibleDisplayFrame(displayFrame);
2337b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell
2347b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final Context context = getContext();
2357b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final int width = getWidth();
2367b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final int height = getHeight();
2377b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final int midy = screenPos[1] + height / 2;
2387b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
2397b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell
2407b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT);
2417b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        if (midy < displayFrame.height()) {
2427b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell            // Show along the top; follow action buttons
243aac0d4ed026d1cfbcf3fa81c6e4eb96f4347ca17Fabrice Di Meglio            cheatSheet.setGravity(Gravity.TOP | Gravity.END,
2447b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell                    screenWidth - screenPos[0] - width / 2, height);
2457b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        } else {
2467b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell            // Show along the bottom center
2477b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell            cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
2487b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        }
2497b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        cheatSheet.show();
2507b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell        return true;
2517b5e9e6c1c7098b6d7b2c6f9ab0c316f0f66109eAdam Powell    }
25224340afbab8ad4c191784fda8023407205bc0a75Adam Powell
25324340afbab8ad4c191784fda8023407205bc0a75Adam Powell    @Override
25424340afbab8ad4c191784fda8023407205bc0a75Adam Powell    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
255d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
256d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell            // Fill all available height.
257d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell            heightMeasureSpec = MeasureSpec.makeMeasureSpec(
258d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell                    MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY);
259d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell        }
26075d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        final boolean textVisible = hasText();
261367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell        if (textVisible && mSavedPaddingLeft >= 0) {
262367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell            super.setPadding(mSavedPaddingLeft, getPaddingTop(),
263367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell                    getPaddingRight(), getPaddingBottom());
26475d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        }
26575d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell
26624340afbab8ad4c191784fda8023407205bc0a75Adam Powell        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
26724340afbab8ad4c191784fda8023407205bc0a75Adam Powell
26824340afbab8ad4c191784fda8023407205bc0a75Adam Powell        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
26975d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
27024340afbab8ad4c191784fda8023407205bc0a75Adam Powell        final int oldMeasuredWidth = getMeasuredWidth();
27175d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(widthSize, mMinWidth)
27224340afbab8ad4c191784fda8023407205bc0a75Adam Powell                : mMinWidth;
27324340afbab8ad4c191784fda8023407205bc0a75Adam Powell
27424340afbab8ad4c191784fda8023407205bc0a75Adam Powell        if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) {
27524340afbab8ad4c191784fda8023407205bc0a75Adam Powell            // Remeasure at exactly the minimum width.
27624340afbab8ad4c191784fda8023407205bc0a75Adam Powell            super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
27724340afbab8ad4c191784fda8023407205bc0a75Adam Powell                    heightMeasureSpec);
27824340afbab8ad4c191784fda8023407205bc0a75Adam Powell        }
27975d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell
28075d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        if (!textVisible && mIcon != null) {
28175d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell            // TextView won't center compound drawables in both dimensions without
28275d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell            // a little coercion. Pad in to center the icon after we've measured.
28375d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell            final int w = getMeasuredWidth();
284c0047d4e111b8cfbffdbebb55f846c7ae935e53eAdam Powell            final int dw = mIcon.getBounds().width();
285367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell            super.setPadding((w - dw) / 2, getPaddingTop(), getPaddingRight(), getPaddingBottom());
28675d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell        }
28724340afbab8ad4c191784fda8023407205bc0a75Adam Powell    }
28896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell}
289