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 198e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikasimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 208e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas 21bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.Context; 2249c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.content.res.Configuration; 23bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.res.Resources; 24bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.res.TypedArray; 25bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.graphics.drawable.Drawable; 261ebe1d4ab755d1a852413bb0845f45caa000fed4Aurimas Liutikasimport android.os.Parcelable; 27c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo; 28da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.appcompat.R; 2949c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v7.widget.ActionMenuView; 302cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banesimport android.support.v7.widget.AppCompatTextView; 316142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.support.v7.widget.ForwardingListener; 32a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.support.v7.widget.TooltipCompat; 33bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.text.TextUtils; 34bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.util.AttributeSet; 3549c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.MotionEvent; 36bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.View; 37bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 38bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/** 39bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * @hide 40bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */ 418e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas@RestrictTo(LIBRARY_GROUP) 422cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banespublic class ActionMenuItemView extends AppCompatTextView 43daa85ce5c5aa5d44fabf6675ede7e7be55a79034Vladislav Kaznacheev implements MenuView.ItemView, View.OnClickListener, ActionMenuView.ActionMenuChildView { 4420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 45ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private static final String TAG = "ActionMenuItemView"; 46ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 472c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas MenuItemImpl mItemData; 48ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private CharSequence mTitle; 49ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private Drawable mIcon; 502c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas MenuBuilder.ItemInvoker mItemInvoker; 516142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private ForwardingListener mForwardingListener; 522c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas PopupCallback mPopupCallback; 53ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 54ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private boolean mAllowTextWithIcon; 55ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private boolean mExpandedFormat; 56ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private int mMinWidth; 57ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private int mSavedPaddingLeft; 58ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 5949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private static final int MAX_ICON_SIZE = 32; // dp 6049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private int mMaxIconSize; 6149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 62ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ActionMenuItemView(Context context) { 63ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani this(context, null); 64ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 65ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 66ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ActionMenuItemView(Context context, AttributeSet attrs) { 67ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani this(context, attrs, 0); 68ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 69ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 70ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) { 71ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super(context, attrs, defStyle); 72ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final Resources res = context.getResources(); 738dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski mAllowTextWithIcon = shouldAllowTextWithIcon(); 74ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TypedArray a = context.obtainStyledAttributes(attrs, 7549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes R.styleable.ActionMenuItemView, defStyle, 0); 76ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMinWidth = a.getDimensionPixelSize( 7720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns R.styleable.ActionMenuItemView_android_minWidth, 0); 78ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani a.recycle(); 79ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 8049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final float density = res.getDisplayMetrics().density; 8149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mMaxIconSize = (int) (MAX_ICON_SIZE * density + 0.5f); 8249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 83ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setOnClickListener(this); 84ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 85ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mSavedPaddingLeft = -1; 861ebe1d4ab755d1a852413bb0845f45caa000fed4Aurimas Liutikas setSaveEnabled(false); 87ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 88ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 89e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 9049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onConfigurationChanged(Configuration newConfig) { 9164dbe1d454f1190b3cd8426d09b9119949a10709Kirill Grouchnikov super.onConfigurationChanged(newConfig); 9249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 938dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski mAllowTextWithIcon = shouldAllowTextWithIcon(); 9449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes updateTextButtonVisibility(); 9549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 9649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 978dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski /** 988dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski * Whether action menu items should obey the "withText" showAsAction flag. This may be set to 998dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski * false for situations where space is extremely limited. --> 1008dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski */ 1018dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski private boolean shouldAllowTextWithIcon() { 102ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes final Configuration config = getContext().getResources().getConfiguration(); 103ee55bf441b2728d359675d9899c6b5efa7bf6a60Aurimas Liutikas final int widthDp = config.screenWidthDp; 104ee55bf441b2728d359675d9899c6b5efa7bf6a60Aurimas Liutikas final int heightDp = config.screenHeightDp; 105ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes 106ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes return widthDp >= 480 || (widthDp >= 640 && heightDp >= 480) 107ed1096ebffac8f3cac5e5b98f54b96ae2ce8579eChris Banes || config.orientation == Configuration.ORIENTATION_LANDSCAPE; 1088dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski } 1098dd9fe7e5a46645cc7a0ec950df7ff7d76b90abaFilip Gruszczynski 110ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 111ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setPadding(int l, int t, int r, int b) { 112ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mSavedPaddingLeft = l; 113ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.setPadding(l, t, r, b); 114ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 115ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 116e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 117ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public MenuItemImpl getItemData() { 118ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mItemData; 119ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 120ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 121e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 122ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void initialize(MenuItemImpl itemData, int menuType) { 123ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mItemData = itemData; 124ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 125ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setIcon(itemData.getIcon()); 126ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon 127ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setId(itemData.getItemId()); 128ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 129ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); 130ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setEnabled(itemData.isEnabled()); 13149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (itemData.hasSubMenu()) { 13249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mForwardingListener == null) { 13349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mForwardingListener = new ActionMenuItemForwardingListener(); 13449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 13549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 136ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 137ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 13849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 13949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean onTouchEvent(MotionEvent e) { 14049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mItemData.hasSubMenu() && mForwardingListener != null 14149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes && mForwardingListener.onTouch(this, e)) { 14249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return true; 14349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 14449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return super.onTouchEvent(e); 14549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 14649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 14749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 148ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onClick(View v) { 149ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mItemInvoker != null) { 150ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mItemInvoker.invokeItem(mItemData); 151ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 152ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 153ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 154ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setItemInvoker(MenuBuilder.ItemInvoker invoker) { 15520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mItemInvoker = invoker; 156ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 157ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 15849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setPopupCallback(PopupCallback popupCallback) { 15949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPopupCallback = popupCallback; 16049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 16149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 162e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 163ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean prefersCondensedTitle() { 164ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return true; 165ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 166ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 167e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 168ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setCheckable(boolean checkable) { 169ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // TODO Support checkable action items 170ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 171ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 172e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 173ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setChecked(boolean checked) { 174ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // TODO Support checkable action items 175ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 176ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 177ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setExpandedFormat(boolean expandedFormat) { 178ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mExpandedFormat != expandedFormat) { 179ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mExpandedFormat = expandedFormat; 180ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mItemData != null) { 181ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mItemData.actionFormatChanged(); 182ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 183ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 184ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 185ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 186ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private void updateTextButtonVisibility() { 187ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani boolean visible = !TextUtils.isEmpty(mTitle); 188ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani visible &= mIcon == null || 18920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns (mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat)); 190ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 191ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setText(visible ? mTitle : null); 192daa85ce5c5aa5d44fabf6675ede7e7be55a79034Vladislav Kaznacheev 193daa85ce5c5aa5d44fabf6675ede7e7be55a79034Vladislav Kaznacheev // Show the tooltip for items that do not already show text. 194fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev final CharSequence contentDescription = mItemData.getContentDescription(); 195fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev if (TextUtils.isEmpty(contentDescription)) { 196722327e27579c196b92883c07f4b47e9efada8adKirill Grouchnikov // Use the uncondensed title for content description, but only if the title is not 197722327e27579c196b92883c07f4b47e9efada8adKirill Grouchnikov // shown already. 198722327e27579c196b92883c07f4b47e9efada8adKirill Grouchnikov setContentDescription(visible ? null : mItemData.getTitle()); 199fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev } else { 200fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev setContentDescription(contentDescription); 201fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev } 202fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev 203fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev final CharSequence tooltipText = mItemData.getTooltipText(); 204fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev if (TextUtils.isEmpty(tooltipText)) { 205fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev // Use the uncondensed title for tooltip, but only if the title is not shown already. 206a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev TooltipCompat.setTooltipText(this, visible ? null : mItemData.getTitle()); 207fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev } else { 208a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev TooltipCompat.setTooltipText(this, tooltipText); 209fd3c4560bf2348f6a06272a9f02105c9e1bf927eVladislav Kaznacheev } 210ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 211ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 212e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 213ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setIcon(Drawable icon) { 214ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIcon = icon; 21549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (icon != null) { 21649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int width = icon.getIntrinsicWidth(); 21749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int height = icon.getIntrinsicHeight(); 21849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (width > mMaxIconSize) { 21949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final float scale = (float) mMaxIconSize / width; 22049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes width = mMaxIconSize; 221ad1b0e82100ee31e70040d77bfa4d847b2bf0864Aurimas Liutikas height = (int) (width * scale); 22249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 22349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (height > mMaxIconSize) { 22449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final float scale = (float) mMaxIconSize / height; 22549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes height = mMaxIconSize; 226ad1b0e82100ee31e70040d77bfa4d847b2bf0864Aurimas Liutikas width = (int) (width * scale); 22749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 22849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes icon.setBounds(0, 0, width, height); 22949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 23049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setCompoundDrawables(icon, null, null, null); 231ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 232ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani updateTextButtonVisibility(); 233ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 234ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 235ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean hasText() { 236ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return !TextUtils.isEmpty(getText()); 237ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 238ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 239e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 240ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setShortcut(boolean showShortcut, char shortcutKey) { 241ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Action buttons don't show text for shortcut keys. 242ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 243ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 244e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 245ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setTitle(CharSequence title) { 246ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTitle = title; 247ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 248ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani updateTextButtonVisibility(); 249ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 250ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 251e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 252ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean showsIcon() { 253ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return true; 254ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 255ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 256e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 257ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean needsDividerBefore() { 258ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return hasText() && mItemData.getIcon() == null; 259ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 260ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 261e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 262ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean needsDividerAfter() { 263ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return hasText(); 264ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 265ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 266ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 267ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 268ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final boolean textVisible = hasText(); 269ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (textVisible && mSavedPaddingLeft >= 0) { 270ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.setPadding(mSavedPaddingLeft, getPaddingTop(), 27120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns getPaddingRight(), getPaddingBottom()); 272ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 273ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 274ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onMeasure(widthMeasureSpec, heightMeasureSpec); 275ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 276ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 277ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int widthSize = MeasureSpec.getSize(widthMeasureSpec); 278ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int oldMeasuredWidth = getMeasuredWidth(); 279ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(widthSize, mMinWidth) 28020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns : mMinWidth; 281ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 282ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) { 283ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Remeasure at exactly the minimum width. 284ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY), 28520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns heightMeasureSpec); 286ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 287ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 288ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (!textVisible && mIcon != null) { 289ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // TextView won't center compound drawables in both dimensions without 290ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // a little coercion. Pad in to center the icon after we've measured. 291ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int w = getMeasuredWidth(); 29249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int dw = mIcon.getBounds().width(); 293ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.setPadding((w - dw) / 2, getPaddingTop(), getPaddingRight(), getPaddingBottom()); 294ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 295ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 29630837f1095c803f332f4a1c3f0917c8afdd50156Adam Powell 2976142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private class ActionMenuItemForwardingListener extends ForwardingListener { 29849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public ActionMenuItemForwardingListener() { 29949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super(ActionMenuItemView.this); 30049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 30149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 30249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 3036142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public ShowableListMenu getPopup() { 30449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mPopupCallback != null) { 30549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mPopupCallback.getPopup(); 30649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 30749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return null; 30849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 30949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 31049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 31149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected boolean onForwardingStarted() { 31249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // Call the invoker, then check if the expected popup is showing. 31349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mItemInvoker != null && mItemInvoker.invokeItem(mItemData)) { 3146142a54baae3289f734947c6b5375b12eb0fb722Chris Banes final ShowableListMenu popup = getPopup(); 31549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return popup != null && popup.isShowing(); 31649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 31749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return false; 31849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 31949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 3207e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // Do not backport the framework impl here. 3217e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // The framework's ListPopupWindow uses an animation before performing the item click 3227e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // after selecting an item. As AppCompat doesn't use an animation, the popup is 3237e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // dismissed and thus null'ed out before onForwardingStopped() has been called. 3247e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // This messes up ActionMenuItemView's onForwardingStopped() impl since it will now 3257e3865a3c83a2c85af215bf1d9ec9c4f37438e19Chris Banes // return false and make ListPopupWindow think it's still forwarding. 32649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 32749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 3281ebe1d4ab755d1a852413bb0845f45caa000fed4Aurimas Liutikas @Override 3291ebe1d4ab755d1a852413bb0845f45caa000fed4Aurimas Liutikas public void onRestoreInstanceState(Parcelable state) { 3301ebe1d4ab755d1a852413bb0845f45caa000fed4Aurimas Liutikas // This might get called with the state of ActionView since it shares the same ID with 3311ebe1d4ab755d1a852413bb0845f45caa000fed4Aurimas Liutikas // ActionMenuItemView. Do not restore this state as ActionMenuItemView never saved it. 3321ebe1d4ab755d1a852413bb0845f45caa000fed4Aurimas Liutikas super.onRestoreInstanceState(null); 3331ebe1d4ab755d1a852413bb0845f45caa000fed4Aurimas Liutikas } 3341ebe1d4ab755d1a852413bb0845f45caa000fed4Aurimas Liutikas 33549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public static abstract class PopupCallback { 3366142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public abstract ShowableListMenu getPopup(); 33749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 338bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell} 339