ActionMenuItemView.java revision ed1096ebffac8f3cac5e5b98f54b96ae2ce8579e
1bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/* 2bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Copyright (C) 2010 The Android Open Source Project 3bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * 4bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 5bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * you may not use this file except in compliance with the License. 6bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * You may obtain a copy of the License at 7bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * 8bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * http://www.apache.org/licenses/LICENSE-2.0 9bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * 10bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Unless required by applicable law or agreed to in writing, software 11bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * distributed under the License is distributed on an "AS IS" BASIS, 12bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * See the License for the specific language governing permissions and 14bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * limitations under the License. 15bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */ 16bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 1766698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banespackage android.support.v7.view.menu; 18bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 19bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.Context; 2049c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.content.res.Configuration; 21bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.res.Resources; 22bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.res.TypedArray; 23bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.graphics.Rect; 24bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.graphics.drawable.Drawable; 2549c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.os.Build; 2649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.GravityCompat; 274a201fef1a0116e987e82ee8fba1340ca9e6f1dbYigit Boyarimport android.support.v4.view.ViewCompat; 28da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.appcompat.R; 2949c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v7.widget.ActionMenuView; 302cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banesimport android.support.v7.widget.AppCompatTextView; 3149c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v7.widget.ListPopupWindow; 32bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.text.TextUtils; 33bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.util.AttributeSet; 34ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banesimport android.util.DisplayMetrics; 35bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.Gravity; 3649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.MotionEvent; 37bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.View; 38bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.Toast; 39bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 40bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/** 41bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * @hide 42bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */ 432cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banespublic class ActionMenuItemView extends AppCompatTextView 4420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener, 4520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns ActionMenuView.ActionMenuChildView { 4620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 47ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private static final String TAG = "ActionMenuItemView"; 48ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 49ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private MenuItemImpl mItemData; 50ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private CharSequence mTitle; 51ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private Drawable mIcon; 52ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private MenuBuilder.ItemInvoker mItemInvoker; 5349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private ListPopupWindow.ForwardingListener mForwardingListener; 5449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private PopupCallback mPopupCallback; 55ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 56ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private boolean mAllowTextWithIcon; 57ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private boolean mExpandedFormat; 58ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private int mMinWidth; 59ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private int mSavedPaddingLeft; 60ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 6149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private static final int MAX_ICON_SIZE = 32; // dp 6249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private int mMaxIconSize; 6349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 64ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ActionMenuItemView(Context context) { 65ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani this(context, null); 66ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 67ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 68ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ActionMenuItemView(Context context, AttributeSet attrs) { 69ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani this(context, attrs, 0); 70ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 71ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 72ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) { 73ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super(context, attrs, defStyle); 74ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final Resources res = context.getResources(); 758dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski mAllowTextWithIcon = shouldAllowTextWithIcon(); 76ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TypedArray a = context.obtainStyledAttributes(attrs, 7749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes R.styleable.ActionMenuItemView, defStyle, 0); 78ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMinWidth = a.getDimensionPixelSize( 7920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns R.styleable.ActionMenuItemView_android_minWidth, 0); 80ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani a.recycle(); 81ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 8249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final float density = res.getDisplayMetrics().density; 8349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mMaxIconSize = (int) (MAX_ICON_SIZE * density + 0.5f); 8449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 85ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setOnClickListener(this); 86ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setOnLongClickListener(this); 87ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 88ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mSavedPaddingLeft = -1; 89ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 90ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 9149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onConfigurationChanged(Configuration newConfig) { 9249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (Build.VERSION.SDK_INT >= 8) { 9349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onConfigurationChanged(newConfig); 9449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 9549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 968dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski mAllowTextWithIcon = shouldAllowTextWithIcon(); 9749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes updateTextButtonVisibility(); 9849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 9949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 1008dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski /** 1018dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski * Whether action menu items should obey the "withText" showAsAction flag. This may be set to 1028dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski * false for situations where space is extremely limited. --> 1038dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski */ 1048dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski private boolean shouldAllowTextWithIcon() { 105ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes final Configuration config = getContext().getResources().getConfiguration(); 106ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes 107ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes final int widthDp; 108ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes final int heightDp; 109ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { 110ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes widthDp = config.screenWidthDp; 111ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes heightDp = config.screenHeightDp; 112ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes } else { 113ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); 114ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes widthDp = (int) (metrics.widthPixels / metrics.density); 115ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes heightDp = (int) (metrics.heightPixels / metrics.density); 116ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes } 117ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes 118ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes return widthDp >= 480 || (widthDp >= 640 && heightDp >= 480) 119ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes || config.orientation == Configuration.ORIENTATION_LANDSCAPE; 1208dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski } 1218dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski 122ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 123ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setPadding(int l, int t, int r, int b) { 124ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mSavedPaddingLeft = l; 125ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.setPadding(l, t, r, b); 126ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 127ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 128ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public MenuItemImpl getItemData() { 129ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mItemData; 130ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 131ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 132ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void initialize(MenuItemImpl itemData, int menuType) { 133ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mItemData = itemData; 134ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 135ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setIcon(itemData.getIcon()); 136ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon 137ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setId(itemData.getItemId()); 138ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 139ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); 140ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setEnabled(itemData.isEnabled()); 14149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (itemData.hasSubMenu()) { 14249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mForwardingListener == null) { 14349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mForwardingListener = new ActionMenuItemForwardingListener(); 14449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 14549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 146ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 147ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 14849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 14949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean onTouchEvent(MotionEvent e) { 15049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mItemData.hasSubMenu() && mForwardingListener != null 15149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes && mForwardingListener.onTouch(this, e)) { 15249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return true; 15349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 15449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return super.onTouchEvent(e); 15549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 15649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 15749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 158ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onClick(View v) { 159ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mItemInvoker != null) { 160ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mItemInvoker.invokeItem(mItemData); 161ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 162ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 163ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 164ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setItemInvoker(MenuBuilder.ItemInvoker invoker) { 16520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mItemInvoker = invoker; 166ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 167ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 16849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setPopupCallback(PopupCallback popupCallback) { 16949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPopupCallback = popupCallback; 17049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 17149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 172ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean prefersCondensedTitle() { 173ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return true; 174ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 175ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 176ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setCheckable(boolean checkable) { 177ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // TODO Support checkable action items 178ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 179ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 180ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setChecked(boolean checked) { 181ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // TODO Support checkable action items 182ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 183ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 184ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setExpandedFormat(boolean expandedFormat) { 185ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mExpandedFormat != expandedFormat) { 186ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mExpandedFormat = expandedFormat; 187ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mItemData != null) { 188ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mItemData.actionFormatChanged(); 189ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 190ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 191ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 192ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 193ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private void updateTextButtonVisibility() { 194ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani boolean visible = !TextUtils.isEmpty(mTitle); 195ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani visible &= mIcon == null || 19620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns (mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat)); 197ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 198ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setText(visible ? mTitle : null); 199ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 200ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 201ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setIcon(Drawable icon) { 202ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIcon = icon; 20349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (icon != null) { 20449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int width = icon.getIntrinsicWidth(); 20549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int height = icon.getIntrinsicHeight(); 20649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (width > mMaxIconSize) { 20749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final float scale = (float) mMaxIconSize / width; 20849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes width = mMaxIconSize; 20949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes height *= scale; 21049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 21149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (height > mMaxIconSize) { 21249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final float scale = (float) mMaxIconSize / height; 21349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes height = mMaxIconSize; 21449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes width *= scale; 21549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 21649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes icon.setBounds(0, 0, width, height); 21749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 21849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setCompoundDrawables(icon, null, null, null); 219ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 220ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani updateTextButtonVisibility(); 221ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 222ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 223ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean hasText() { 224ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return !TextUtils.isEmpty(getText()); 225ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 226ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 227ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setShortcut(boolean showShortcut, char shortcutKey) { 228ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Action buttons don't show text for shortcut keys. 229ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 230ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 231ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setTitle(CharSequence title) { 232ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTitle = title; 233ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 234ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setContentDescription(mTitle); 235ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani updateTextButtonVisibility(); 236ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 237ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 238ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean showsIcon() { 239ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return true; 240ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 241ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 242ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean needsDividerBefore() { 243ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return hasText() && mItemData.getIcon() == null; 244ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 245ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 246ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean needsDividerAfter() { 247ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return hasText(); 248ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 249ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 250ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 251ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean onLongClick(View v) { 252ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (hasText()) { 253ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Don't show the cheat sheet for items that already show text. 254ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return false; 255ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 256ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 257ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int[] screenPos = new int[2]; 258ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final Rect displayFrame = new Rect(); 259ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani getLocationOnScreen(screenPos); 260ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani getWindowVisibleDisplayFrame(displayFrame); 261ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 262ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final Context context = getContext(); 263ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int width = getWidth(); 264ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int height = getHeight(); 265ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int midy = screenPos[1] + height / 2; 2664a201fef1a0116e987e82ee8fba1340ca9e6f1dbYigit Boyar int referenceX = screenPos[0] + width / 2; 2674a201fef1a0116e987e82ee8fba1340ca9e6f1dbYigit Boyar if (ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_LTR) { 2684a201fef1a0116e987e82ee8fba1340ca9e6f1dbYigit Boyar final int screenWidth = context.getResources().getDisplayMetrics().widthPixels; 2694a201fef1a0116e987e82ee8fba1340ca9e6f1dbYigit Boyar referenceX = screenWidth - referenceX; // mirror 2704a201fef1a0116e987e82ee8fba1340ca9e6f1dbYigit Boyar } 271ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT); 272ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (midy < displayFrame.height()) { 273ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Show along the top; follow action buttons 2748b18135662bd0531adfd66d06cf203fc98f6188aChris Banes cheatSheet.setGravity(Gravity.TOP | GravityCompat.END, referenceX, 2758b18135662bd0531adfd66d06cf203fc98f6188aChris Banes screenPos[1] + height - displayFrame.top); 276ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 277ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Show along the bottom center 278ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height); 279ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 280ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani cheatSheet.show(); 281ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return true; 282ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 283ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 284ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 285ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 286ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final boolean textVisible = hasText(); 287ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (textVisible && mSavedPaddingLeft >= 0) { 288ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.setPadding(mSavedPaddingLeft, getPaddingTop(), 28920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns getPaddingRight(), getPaddingBottom()); 290ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 291ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 292ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onMeasure(widthMeasureSpec, heightMeasureSpec); 293ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 294ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 295ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int widthSize = MeasureSpec.getSize(widthMeasureSpec); 296ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int oldMeasuredWidth = getMeasuredWidth(); 297ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(widthSize, mMinWidth) 29820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns : mMinWidth; 299ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 300ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) { 301ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Remeasure at exactly the minimum width. 302ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY), 30320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns heightMeasureSpec); 304ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 305ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 306ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (!textVisible && mIcon != null) { 307ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // TextView won't center compound drawables in both dimensions without 308ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // a little coercion. Pad in to center the icon after we've measured. 309ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int w = getMeasuredWidth(); 31049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int dw = mIcon.getBounds().width(); 311ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.setPadding((w - dw) / 2, getPaddingTop(), getPaddingRight(), getPaddingBottom()); 312ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 313ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 31430837f1095c803f332f4a1c3f0917c8afdd50156Adam Powell 31549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private class ActionMenuItemForwardingListener extends ListPopupWindow.ForwardingListener { 31649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public ActionMenuItemForwardingListener() { 31749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super(ActionMenuItemView.this); 31849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 31949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 32049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 32149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public ListPopupWindow getPopup() { 32249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mPopupCallback != null) { 32349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mPopupCallback.getPopup(); 32449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 32549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return null; 32649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 32749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 32849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 32949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected boolean onForwardingStarted() { 33049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // Call the invoker, then check if the expected popup is showing. 33149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mItemInvoker != null && mItemInvoker.invokeItem(mItemData)) { 33249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final ListPopupWindow popup = getPopup(); 33349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return popup != null && popup.isShowing(); 33449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 33549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return false; 33649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 33749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 3387e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // Do not backport the framework impl here. 3397e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // The framework's ListPopupWindow uses an animation before performing the item click 3407e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // after selecting an item. As AppCompat doesn't use an animation, the popup is 3417e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // dismissed and thus null'ed out before onForwardingStopped() has been called. 3427e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // This messes up ActionMenuItemView's onForwardingStopped() impl since it will now 3437e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // return false and make ListPopupWindow think it's still forwarding. 34449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 34549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 34649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public static abstract class PopupCallback { 34749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public abstract ListPopupWindow getPopup(); 34849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 349bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell} 350