1bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/* 249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Copyright (C) 2014 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 */ 1649c78900da0d43140fb602431fb93212bd7f6c70Chris Banespackage android.support.v7.widget; 17bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 18bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.Context; 19bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.res.Configuration; 207325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banesimport android.graphics.drawable.Drawable; 21b34bdc0555f758dccd9307ce696c5134f5ce5042Trevor Johnsimport android.os.Build; 227325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banesimport android.support.annotation.Nullable; 23f694ca99453213b7ce3c2a46e237209fcb5841cdTor Norbyeimport android.support.annotation.StyleRes; 2466698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.ActionMenuItemView; 2566698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuBuilder; 2666698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuItemImpl; 2766698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuPresenter; 2866698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuView; 29bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.util.AttributeSet; 3049c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.ContextThemeWrapper; 31bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.Gravity; 3249c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.Menu; 3349c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.MenuItem; 34bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.View; 35bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewDebug; 36bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewGroup; 37bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.accessibility.AccessibilityEvent; 38bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 39bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/** 4049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * ActionMenuView is a presentation of a series of menu options as a View. It provides 4149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * several top level options as action buttons while spilling remaining options over as 4249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * items in an overflow menu. This allows applications to present packs of actions inline with 4349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * specific or repeating content. 44bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */ 4549c78900da0d43140fb602431fb93212bd7f6c70Chris Banespublic class ActionMenuView extends LinearLayoutCompat implements MenuBuilder.ItemInvoker, 4649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes MenuView { 47b34bdc0555f758dccd9307ce696c5134f5ce5042Trevor Johns 4820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns private static final String TAG = "ActionMenuView"; 49bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 5020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns static final int MIN_CELL_SIZE = 56; // dips 5120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns static final int GENERATED_ITEM_PADDING = 4; // dips 5220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 5320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns private MenuBuilder mMenu; 54bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 5549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** Context against which to inflate popup menus. */ 5649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private Context mPopupContext; 5749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 5849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** Theme resource against which to inflate popup menus. */ 5949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private int mPopupTheme; 6049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 6120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns private boolean mReserveOverflow; 6220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns private ActionMenuPresenter mPresenter; 63c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes private MenuPresenter.Callback mActionMenuPresenterCallback; 64c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes private MenuBuilder.Callback mMenuBuilderCallback; 6520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns private boolean mFormatItems; 6620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns private int mFormatItemsWidth; 6720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns private int mMinCellSize; 6820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns private int mGeneratedItemPadding; 6949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 7049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private OnMenuItemClickListener mOnMenuItemClickListener; 71bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 7220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public ActionMenuView(Context context) { 7320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns this(context, null); 74bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 75bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 7620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public ActionMenuView(Context context, AttributeSet attrs) { 7720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns super(context, attrs); 7820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns setBaselineAligned(false); 7920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final float density = context.getResources().getDisplayMetrics().density; 8020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mMinCellSize = (int) (MIN_CELL_SIZE * density); 8120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density); 8249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPopupContext = context; 8349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPopupTheme = 0; 8449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 8520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 8649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 8749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Specifies the theme to use when inflating popup menus. By default, uses 8849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * the same theme as the action menu view itself. 8949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 9049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param resId theme used to inflate popup menus 9149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @see #getPopupTheme() 9249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 93f694ca99453213b7ce3c2a46e237209fcb5841cdTor Norbye public void setPopupTheme(@StyleRes int resId) { 9449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mPopupTheme != resId) { 9549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPopupTheme = resId; 9649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (resId == 0) { 977325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes mPopupContext = getContext(); 9849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else { 997325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes mPopupContext = new ContextThemeWrapper(getContext(), resId); 10049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 10149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 102bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 103bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 10449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 10549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @return resource identifier of the theme used to inflate popup menus, or 10649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 0 if menus are inflated against the action menu view theme 10749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @see #setPopupTheme(int) 10849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 10949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public int getPopupTheme() { 11049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mPopupTheme; 111bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 112bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 11349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 11449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param presenter Menu presenter used to display popup menu 11549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @hide 11649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 11749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setPresenter(ActionMenuPresenter presenter) { 11849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPresenter = presenter; 11949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPresenter.setMenuView(this); 12020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 121bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 12220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @Override 12320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public void onConfigurationChanged(Configuration newConfig) { 12420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (Build.VERSION.SDK_INT >= 8) { 12520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns super.onConfigurationChanged(newConfig); 12620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 127bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 1281f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes if (mPresenter != null) { 1291f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes mPresenter.updateMenuView(false); 130bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 1311f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes if (mPresenter.isOverflowMenuShowing()) { 1321f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes mPresenter.hideOverflowMenu(); 1331f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes mPresenter.showOverflowMenu(); 1341f7be3e1e4ba20e32c479d50d4ca66252b7c0969Chris Banes } 13520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 13620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 137bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 13849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setOnMenuItemClickListener(OnMenuItemClickListener listener) { 13949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mOnMenuItemClickListener = listener; 14049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 14149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 14220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @Override 14320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 14420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // If we've been given an exact size to match, apply special formatting during layout. 14520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final boolean wasFormatted = mFormatItems; 14620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY; 147bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 14820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (wasFormatted != mFormatItems) { 14920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mFormatItemsWidth = 0; // Reset this when switching modes 15020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 151bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 15220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Special formatting can change whether items can fit as action buttons. 15320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Kick the menu and update presenters when this changes. 15449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int widthSize = MeasureSpec.getSize(widthMeasureSpec); 15520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) { 15620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mFormatItemsWidth = widthSize; 15720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mMenu.onItemsChanged(true); 15820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 159bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 16049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int childCount = getChildCount(); 16149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mFormatItems && childCount > 0) { 16220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec); 16320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } else { 16420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Previous measurement at exact format may have set margins - reset them. 16520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns for (int i = 0; i < childCount; i++) { 16620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final View child = getChildAt(i); 16720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.leftMargin = lp.rightMargin = 0; 16920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 17020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns super.onMeasure(widthMeasureSpec, heightMeasureSpec); 17120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 17220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 173bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 17420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) { 17520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // We already know the width mode is EXACTLY if we're here. 17620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 17720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int widthSize = MeasureSpec.getSize(widthMeasureSpec); 17820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int heightSize = MeasureSpec.getSize(heightMeasureSpec); 179bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 18020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int widthPadding = getPaddingLeft() + getPaddingRight(); 18120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int heightPadding = getPaddingTop() + getPaddingBottom(); 182bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 18349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int itemHeightSpec = getChildMeasureSpec(heightMeasureSpec, heightPadding, 18449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewGroup.LayoutParams.WRAP_CONTENT); 185bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 18620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns widthSize -= widthPadding; 187bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 18820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Divide the view into cells. 18920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int cellCount = widthSize / mMinCellSize; 19020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int cellSizeRemaining = widthSize % mMinCellSize; 191bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 19220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (cellCount == 0) { 19320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Give up, nothing fits. 19420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns setMeasuredDimension(widthSize, 0); 19520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return; 19620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 197bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 19820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int cellSize = mMinCellSize + cellSizeRemaining / cellCount; 19920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 20020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int cellsRemaining = cellCount; 20120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int maxChildHeight = 0; 20220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int maxCellsUsed = 0; 20320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int expandableItemCount = 0; 20420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int visibleItemCount = 0; 20520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns boolean hasOverflow = false; 20620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 20720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // This is used as a bitfield to locate the smallest items present. Assumes childCount < 64. 20820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns long smallestItemsAt = 0; 20920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 21020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int childCount = getChildCount(); 21120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns for (int i = 0; i < childCount; i++) { 21220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final View child = getChildAt(i); 21349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (child.getVisibility() == GONE) continue; 21420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 21520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final boolean isGeneratedItem = child instanceof ActionMenuItemView; 21620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns visibleItemCount++; 21720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 21820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (isGeneratedItem) { 21920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Reset padding for generated menu item views; it may change below 22020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // and views are recycled. 22120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0); 22220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 22320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 22420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 22520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.expanded = false; 22620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.extraPixels = 0; 22720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.cellsUsed = 0; 22820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.expandable = false; 22920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.leftMargin = 0; 23020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.rightMargin = 0; 23120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText(); 23220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 23320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Overflow always gets 1 cell. No more, no less. 23420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining; 23520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 23620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable, 23720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns itemHeightSpec, heightPadding); 23820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 23920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns maxCellsUsed = Math.max(maxCellsUsed, cellsUsed); 24049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (lp.expandable) expandableItemCount++; 24149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (lp.isOverflowButton) hasOverflow = true; 24220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 24320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns cellsRemaining -= cellsUsed; 24420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight()); 24549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (cellsUsed == 1) smallestItemsAt |= (1 << i); 246bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 247bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 24820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // When we have overflow and a single expanded (text) item, we want to try centering it 24920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // visually in the available space even though overflow consumes some of it. 25020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2; 25120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 25220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Divide space for remaining cells if we have items that can expand. 25320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Try distributing whole leftover cells to smaller items first. 25420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 25520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns boolean needsExpansion = false; 25620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns while (expandableItemCount > 0 && cellsRemaining > 0) { 25720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int minCells = Integer.MAX_VALUE; 25820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns long minCellsAt = 0; // Bit locations are indices of relevant child views 25920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int minCellsItemCount = 0; 26020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns for (int i = 0; i < childCount; i++) { 26120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final View child = getChildAt(i); 26220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 26320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 26420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Don't try to expand items that shouldn't. 26549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!lp.expandable) continue; 26620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 26720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Mark indices of children that can receive an extra cell. 26820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (lp.cellsUsed < minCells) { 26920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns minCells = lp.cellsUsed; 27020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns minCellsAt = 1 << i; 27120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns minCellsItemCount = 1; 27220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } else if (lp.cellsUsed == minCells) { 27320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns minCellsAt |= 1 << i; 27420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns minCellsItemCount++; 27520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 27620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 27720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 27820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Items that get expanded will always be in the set of smallest items when we're done. 27920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns smallestItemsAt |= minCellsAt; 28020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 28149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop. 28220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 28320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // We have enough cells, all minimum size items will be incremented. 28420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns minCells++; 28520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 28620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns for (int i = 0; i < childCount; i++) { 28720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final View child = getChildAt(i); 28820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 28920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if ((minCellsAt & (1 << i)) == 0) { 29020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // If this item is already at our small item count, mark it for later. 29149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i; 29220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns continue; 29320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 29420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 29520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) { 29620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Add padding to this item such that it centers. 29720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0); 29820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 29920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.cellsUsed++; 30020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.expanded = true; 30120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns cellsRemaining--; 30220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 30320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 30420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns needsExpansion = true; 305bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 306bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 30720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Divide any space left that wouldn't divide along cell boundaries 30820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // evenly among the smallest items 30920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 31020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final boolean singleItem = !hasOverflow && visibleItemCount == 1; 31120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (cellsRemaining > 0 && smallestItemsAt != 0 && 31220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns (cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) { 31320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns float expandCount = Long.bitCount(smallestItemsAt); 31420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 31520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (!singleItem) { 31620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // The items at the far edges may only expand by half in order to pin to either side. 31720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if ((smallestItemsAt & 1) != 0) { 31820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams(); 31949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!lp.preventEdgeOffset) expandCount -= 0.5f; 32020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 32120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if ((smallestItemsAt & (1 << (childCount - 1))) != 0) { 32220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams()); 32349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!lp.preventEdgeOffset) expandCount -= 0.5f; 32420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 32520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 32620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 32720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int extraPixels = expandCount > 0 ? 32820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns (int) (cellsRemaining * cellSize / expandCount) : 0; 32920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 33020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns for (int i = 0; i < childCount; i++) { 33149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if ((smallestItemsAt & (1 << i)) == 0) continue; 33220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 33320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final View child = getChildAt(i); 33420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 33520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (child instanceof ActionMenuItemView) { 33620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // If this is one of our views, expand and measure at the larger size. 33720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.extraPixels = extraPixels; 33820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.expanded = true; 33920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (i == 0 && !lp.preventEdgeOffset) { 34020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // First item gets part of its new padding pushed out of sight. 34120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // The last item will get this implicitly from layout. 34220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.leftMargin = -extraPixels / 2; 34320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 34420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns needsExpansion = true; 34520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } else if (lp.isOverflowButton) { 34620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.extraPixels = extraPixels; 34720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.expanded = true; 34820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.rightMargin = -extraPixels / 2; 34920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns needsExpansion = true; 35020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } else { 35120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // If we don't know what it is, give it some margins instead 35220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // and let it center within its space. We still want to pin 35320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // against the edges. 35420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (i != 0) { 35520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.leftMargin = extraPixels / 2; 35620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 35720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (i != childCount - 1) { 35820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.rightMargin = extraPixels / 2; 35920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 36020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 36120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 36220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 36320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns cellsRemaining = 0; 36420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 365bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 36620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Remeasure any items that have had extra space allocated to them. 36720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (needsExpansion) { 36820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns for (int i = 0; i < childCount; i++) { 36920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final View child = getChildAt(i); 37020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 371bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 37249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!lp.expanded) continue; 373bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 37420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int width = lp.cellsUsed * cellSize + lp.extraPixels; 37520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 37620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns itemHeightSpec); 37720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 378bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 379bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 38020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (heightMode != MeasureSpec.EXACTLY) { 38120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns heightSize = maxChildHeight; 382bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 383bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 38420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns setMeasuredDimension(widthSize, heightSize); 385bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 386bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 38720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns /** 38849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Measure a child view to fit within cell-based formatting. The child's width 38949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * will be measured to a whole multiple of cellSize. 39020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * 39120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * <p>Sets the expandable and cellsUsed fields of LayoutParams. 39220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * 39349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param child Child to measure 39449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param cellSize Size of one cell 39549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param cellsRemaining Number of cells remaining that this view can expand to fill 39620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * @param parentHeightMeasureSpec MeasureSpec used by the parent view 39749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param parentHeightPadding Padding present in the parent view 39820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * @return Number of cells this child was measured to occupy 39920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns */ 40020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns static int measureChildForCells(View child, int cellSize, int cellsRemaining, 40120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int parentHeightMeasureSpec, int parentHeightPadding) { 402bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 403bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 40420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) - 40520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns parentHeightPadding; 40620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec); 40720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode); 40820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 40920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final ActionMenuItemView itemView = child instanceof ActionMenuItemView ? 41020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns (ActionMenuItemView) child : null; 41120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final boolean hasText = itemView != null && itemView.hasText(); 41220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 41320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int cellsUsed = 0; 41420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (cellsRemaining > 0 && (!hasText || cellsRemaining >= 2)) { 41520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int childWidthSpec = MeasureSpec.makeMeasureSpec( 41620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns cellSize * cellsRemaining, MeasureSpec.AT_MOST); 41720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns child.measure(childWidthSpec, childHeightSpec); 41820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 41920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int measuredWidth = child.getMeasuredWidth(); 42020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns cellsUsed = measuredWidth / cellSize; 42149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (measuredWidth % cellSize != 0) cellsUsed++; 42249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (hasText && cellsUsed < 2) cellsUsed = 2; 42320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 424bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 42520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final boolean expandable = !lp.isOverflowButton && hasText; 42620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.expandable = expandable; 427bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 42820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns lp.cellsUsed = cellsUsed; 42920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int targetWidth = cellsUsed * cellSize; 43020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY), 43120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns childHeightSpec); 43220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return cellsUsed; 433bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 434bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 43520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @Override 43620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 43720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (!mFormatItems) { 43820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns super.onLayout(changed, left, top, right, bottom); 43920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return; 44020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 441bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 44220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int childCount = getChildCount(); 4432f4abc2b347f34ba070a2a5e87cf16ee2c373192Chris Banes final int midVertical = (bottom - top) / 2; 44449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int dividerWidth = getDividerWidth(); 44520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int overflowWidth = 0; 44620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int nonOverflowWidth = 0; 44720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int nonOverflowCount = 0; 44820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int widthRemaining = right - left - getPaddingRight() - getPaddingLeft(); 44920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns boolean hasOverflow = false; 450a2c72b87007d10202c25e78e904938f770c6337dChris Banes final boolean isLayoutRtl = ViewUtils.isLayoutRtl(this); 45120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns for (int i = 0; i < childCount; i++) { 45220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final View v = getChildAt(i); 45320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (v.getVisibility() == GONE) { 45420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns continue; 45520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 45620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 45720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams p = (LayoutParams) v.getLayoutParams(); 45820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (p.isOverflowButton) { 45920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns overflowWidth = v.getMeasuredWidth(); 4601582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes if (hasSupportDividerBeforeChildAt(i)) { 4611582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes overflowWidth += dividerWidth; 4621582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes } 46320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int height = v.getMeasuredHeight(); 464a2c72b87007d10202c25e78e904938f770c6337dChris Banes int r; 465a2c72b87007d10202c25e78e904938f770c6337dChris Banes int l; 466a2c72b87007d10202c25e78e904938f770c6337dChris Banes if (isLayoutRtl) { 467a2c72b87007d10202c25e78e904938f770c6337dChris Banes l = getPaddingLeft() + p.leftMargin; 468a2c72b87007d10202c25e78e904938f770c6337dChris Banes r = l + overflowWidth; 469a2c72b87007d10202c25e78e904938f770c6337dChris Banes } else { 470a2c72b87007d10202c25e78e904938f770c6337dChris Banes r = getWidth() - getPaddingRight() - p.rightMargin; 471a2c72b87007d10202c25e78e904938f770c6337dChris Banes l = r - overflowWidth; 472a2c72b87007d10202c25e78e904938f770c6337dChris Banes } 47320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int t = midVertical - (height / 2); 47420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns int b = t + height; 47520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns v.layout(l, t, r, b); 47620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 47720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns widthRemaining -= overflowWidth; 47820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns hasOverflow = true; 47920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } else { 48020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin; 48120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns nonOverflowWidth += size; 48220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns widthRemaining -= size; 4831582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes if (hasSupportDividerBeforeChildAt(i)) { 4841582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes nonOverflowWidth += dividerWidth; 4851582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes } 48620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns nonOverflowCount++; 48720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 48820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 48920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 49020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (childCount == 1 && !hasOverflow) { 49120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns // Center a single child 49220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final View v = getChildAt(0); 49320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int width = v.getMeasuredWidth(); 49420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int height = v.getMeasuredHeight(); 49520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int midHorizontal = (right - left) / 2; 49620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int l = midHorizontal - width / 2; 49720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int t = midVertical - height / 2; 49820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns v.layout(l, t, l + width, t + height); 49920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return; 50020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 50120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 50220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1); 50320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0); 50420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 505a2c72b87007d10202c25e78e904938f770c6337dChris Banes if (isLayoutRtl) { 506a2c72b87007d10202c25e78e904938f770c6337dChris Banes int startRight = getWidth() - getPaddingRight(); 507a2c72b87007d10202c25e78e904938f770c6337dChris Banes for (int i = 0; i < childCount; i++) { 508a2c72b87007d10202c25e78e904938f770c6337dChris Banes final View v = getChildAt(i); 509a2c72b87007d10202c25e78e904938f770c6337dChris Banes final LayoutParams lp = (LayoutParams) v.getLayoutParams(); 510a2c72b87007d10202c25e78e904938f770c6337dChris Banes if (v.getVisibility() == GONE || lp.isOverflowButton) { 511a2c72b87007d10202c25e78e904938f770c6337dChris Banes continue; 512a2c72b87007d10202c25e78e904938f770c6337dChris Banes } 513a2c72b87007d10202c25e78e904938f770c6337dChris Banes 514a2c72b87007d10202c25e78e904938f770c6337dChris Banes startRight -= lp.rightMargin; 515a2c72b87007d10202c25e78e904938f770c6337dChris Banes int width = v.getMeasuredWidth(); 516a2c72b87007d10202c25e78e904938f770c6337dChris Banes int height = v.getMeasuredHeight(); 517a2c72b87007d10202c25e78e904938f770c6337dChris Banes int t = midVertical - height / 2; 518a2c72b87007d10202c25e78e904938f770c6337dChris Banes v.layout(startRight - width, t, startRight, t + height); 519a2c72b87007d10202c25e78e904938f770c6337dChris Banes startRight -= width + lp.leftMargin + spacerSize; 52020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 521a2c72b87007d10202c25e78e904938f770c6337dChris Banes } else { 522a2c72b87007d10202c25e78e904938f770c6337dChris Banes int startLeft = getPaddingLeft(); 523a2c72b87007d10202c25e78e904938f770c6337dChris Banes for (int i = 0; i < childCount; i++) { 524a2c72b87007d10202c25e78e904938f770c6337dChris Banes final View v = getChildAt(i); 525a2c72b87007d10202c25e78e904938f770c6337dChris Banes final LayoutParams lp = (LayoutParams) v.getLayoutParams(); 526a2c72b87007d10202c25e78e904938f770c6337dChris Banes if (v.getVisibility() == GONE || lp.isOverflowButton) { 527a2c72b87007d10202c25e78e904938f770c6337dChris Banes continue; 528a2c72b87007d10202c25e78e904938f770c6337dChris Banes } 52920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 530a2c72b87007d10202c25e78e904938f770c6337dChris Banes startLeft += lp.leftMargin; 531a2c72b87007d10202c25e78e904938f770c6337dChris Banes int width = v.getMeasuredWidth(); 532a2c72b87007d10202c25e78e904938f770c6337dChris Banes int height = v.getMeasuredHeight(); 533a2c72b87007d10202c25e78e904938f770c6337dChris Banes int t = midVertical - height / 2; 534a2c72b87007d10202c25e78e904938f770c6337dChris Banes v.layout(startLeft, t, startLeft + width, t + height); 535a2c72b87007d10202c25e78e904938f770c6337dChris Banes startLeft += width + lp.rightMargin + spacerSize; 536a2c72b87007d10202c25e78e904938f770c6337dChris Banes } 53720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 53820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 53920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 54020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @Override 54120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public void onDetachedFromWindow() { 54220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns super.onDetachedFromWindow(); 54349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes dismissPopupMenus(); 54420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 54520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 546c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes /** 5477325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes * Set the icon to use for the overflow button. 548c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes * 5497325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes * @param icon Drawable to set, may be null to clear the icon 550c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes */ 5517325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes public void setOverflowIcon(@Nullable Drawable icon) { 5527325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes getMenu(); 5537325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes mPresenter.setOverflowIcon(icon); 554c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes } 555c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes 556c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes /** 5577325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes * Return the current drawable used as the overflow icon. 558c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes * 5597325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes * @return The overflow icon drawable 560c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes */ 5617325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes @Nullable 5627325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes public Drawable getOverflowIcon() { 5637325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes getMenu(); 5647325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes return mPresenter.getOverflowIcon(); 5657325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes } 5667325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes 5677325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes /** @hide */ 5687325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes public boolean isOverflowReserved() { 5697325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes return mReserveOverflow; 5707325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes } 5717325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes 5727325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes /** @hide */ 5737325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes public void setOverflowReserved(boolean reserveOverflow) { 5747325cdad103472c460c1dd492ec9f9ac0df57d50Chris Banes mReserveOverflow = reserveOverflow; 575c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes } 576c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes 57720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @Override 57820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns protected LayoutParams generateDefaultLayoutParams() { 57920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, 58020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams.WRAP_CONTENT); 58120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns params.gravity = Gravity.CENTER_VERTICAL; 58220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return params; 583bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 584bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 58520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @Override 58620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public LayoutParams generateLayoutParams(AttributeSet attrs) { 58720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return new LayoutParams(getContext(), attrs); 588bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 589bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 59020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @Override 59120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 59249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (p != null) { 59349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final LayoutParams result = p instanceof LayoutParams 59449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ? new LayoutParams((LayoutParams) p) 59549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes : new LayoutParams(p); 59620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (result.gravity <= Gravity.NO_GRAVITY) { 59720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns result.gravity = Gravity.CENTER_VERTICAL; 59820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 59920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return result; 60020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 60120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return generateDefaultLayoutParams(); 602bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 60320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 60420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @Override 60520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 60620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return p != null && p instanceof LayoutParams; 607bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 60820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 60949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** @hide */ 61020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public LayoutParams generateOverflowButtonLayoutParams() { 61120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams result = generateDefaultLayoutParams(); 61220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns result.isOverflowButton = true; 61320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return result; 614bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 61520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 61649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** @hide */ 61720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public boolean invokeItem(MenuItemImpl item) { 61820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return mMenu.performItemAction(item, 0); 619bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 62020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 62149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** @hide */ 62220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public int getWindowAnimations() { 62320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return 0; 62420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 62520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 62649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** @hide */ 62720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public void initialize(MenuBuilder menu) { 62820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mMenu = menu; 62920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 63020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 63149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 63249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Returns the Menu object that this ActionMenuView is currently presenting. 63349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 63449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * <p>Applications should use this method to obtain the ActionMenuView's Menu object 63549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * and inflate or add content to it as necessary.</p> 63649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 63749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @return the Menu presented by this view 63849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 63949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public Menu getMenu() { 64049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mMenu == null) { 64149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final Context context = getContext(); 64249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mMenu = new MenuBuilder(context); 64349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mMenu.setCallback(new MenuBuilderCallback()); 64449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPresenter = new ActionMenuPresenter(context); 645ae5248b8902c62325fafbdac3fe18783aec06073Chris Banes mPresenter.setReserveOverflow(true); 646c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes mPresenter.setCallback(mActionMenuPresenterCallback != null 647c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes ? mActionMenuPresenterCallback : new ActionMenuPresenterCallback()); 64849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mMenu.addMenuPresenter(mPresenter, mPopupContext); 64949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPresenter.setMenuView(this); 65049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 65149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 65249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mMenu; 65349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 65449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 65549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 656c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes * Must be called before the first call to getMenu() 657c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes * @hide 658c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes */ 659c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes public void setMenuCallbacks(MenuPresenter.Callback pcb, MenuBuilder.Callback mcb) { 660c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes mActionMenuPresenterCallback = pcb; 661c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes mMenuBuilderCallback = mcb; 662c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes } 663c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes 664c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes /** 66549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Returns the current menu or null if one has not yet been configured. 66649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @hide Internal use only for action bar integration 66749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 66849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public MenuBuilder peekMenu() { 66949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mMenu; 67049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 67149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 67249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 67349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Show the overflow items from the associated menu. 67449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 67549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @return true if the menu was able to be shown, false otherwise 67649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 67749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean showOverflowMenu() { 67849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mPresenter != null && mPresenter.showOverflowMenu(); 67949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 68049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 68149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 68249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Hide the overflow items from the associated menu. 68349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 68449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @return true if the menu was able to be hidden, false otherwise 68549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 68649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean hideOverflowMenu() { 68749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mPresenter != null && mPresenter.hideOverflowMenu(); 68849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 68949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 69049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 69149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Check whether the overflow menu is currently showing. This may not reflect 69249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * a pending show operation in progress. 69349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 69449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @return true if the overflow menu is currently showing 69549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 69649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean isOverflowMenuShowing() { 69749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mPresenter != null && mPresenter.isOverflowMenuShowing(); 69849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 69949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 70049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** @hide */ 70149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean isOverflowMenuShowPending() { 70249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mPresenter != null && mPresenter.isOverflowMenuShowPending(); 70349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 70449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 70549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 70649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Dismiss any popups associated with this menu view. 70749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 70849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void dismissPopupMenus() { 70949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mPresenter != null) { 71049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPresenter.dismissPopupMenus(); 71149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 71249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 71349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 714a2c72b87007d10202c25e78e904938f770c6337dChris Banes /** 715a2c72b87007d10202c25e78e904938f770c6337dChris Banes * @hide Private LinearLayout (superclass) API. Un-hide if LinearLayout API is made public. 716a2c72b87007d10202c25e78e904938f770c6337dChris Banes */ 7171582fcfe4f727e3547ed17a2df3067234c9a4141Chris Banes protected boolean hasSupportDividerBeforeChildAt(int childIndex) { 71849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (childIndex == 0) { 71949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return false; 72049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 72120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final View childBefore = getChildAt(childIndex - 1); 72220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns final View child = getChildAt(childIndex); 72320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns boolean result = false; 72420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) { 72520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns result |= ((ActionMenuChildView) childBefore).needsDividerAfter(); 72620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 72720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns if (childIndex > 0 && child instanceof ActionMenuChildView) { 72820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns result |= ((ActionMenuChildView) child).needsDividerBefore(); 72920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 73020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return result; 731bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 732bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 73320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 73420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns return false; 735bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 736bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 73749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** @hide */ 73849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setExpandedActionViewsExclusive(boolean exclusive) { 73949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPresenter.setExpandedActionViewsExclusive(exclusive); 74049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 74120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 74249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 74349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Interface responsible for receiving menu item click events if the items themselves 74449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * do not have individual item click listeners. 74549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 74649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public interface OnMenuItemClickListener { 74749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 74849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * This method will be invoked when a menu item is clicked if the item itself did 74949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * not already handle the event. 75049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 75149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param item {@link MenuItem} that was clicked 75249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @return <code>true</code> if the event was handled, <code>false</code> otherwise. 75349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 75449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean onMenuItemClick(MenuItem item); 75549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 75620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 75749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private class MenuBuilderCallback implements MenuBuilder.Callback { 75849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 75949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { 76049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mOnMenuItemClickListener != null && 76149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mOnMenuItemClickListener.onMenuItemClick(item); 76249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 76349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 76449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 76549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onMenuModeChange(MenuBuilder menu) { 766c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes if (mMenuBuilderCallback != null) { 767c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes mMenuBuilderCallback.onMenuModeChange(menu); 768c4b9e0cb716a4caff218b27d86f37ef8117d257bChris Banes } 76949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 77049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 77149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 77249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private class ActionMenuPresenterCallback implements ActionMenuPresenter.Callback { 77349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 77449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 77549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 77649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 77749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 77849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean onOpenSubMenu(MenuBuilder subMenu) { 77949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return false; 78049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 78149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 78249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 78349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** @hide */ 78449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public interface ActionMenuChildView { 78549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean needsDividerBefore(); 78620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public boolean needsDividerAfter(); 787bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 788bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 78949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public static class LayoutParams extends LinearLayoutCompat.LayoutParams { 79020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 79120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @ViewDebug.ExportedProperty() 79220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public boolean isOverflowButton; 79320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 79420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @ViewDebug.ExportedProperty() 79520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public int cellsUsed; 79620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 79720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @ViewDebug.ExportedProperty() 79820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public int extraPixels; 79920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 80020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @ViewDebug.ExportedProperty() 80120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public boolean expandable; 80220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 80320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns @ViewDebug.ExportedProperty() 80420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public boolean preventEdgeOffset; 80520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 80649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes boolean expanded; 80720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 80820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public LayoutParams(Context c, AttributeSet attrs) { 80920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns super(c, attrs); 81020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 81120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 81249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public LayoutParams(ViewGroup.LayoutParams other) { 81349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super(other); 81449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 81549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 81620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public LayoutParams(LayoutParams other) { 81749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super((ViewGroup.LayoutParams) other); 81820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns isOverflowButton = other.isOverflowButton; 81920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 82020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 82120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns public LayoutParams(int width, int height) { 82220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns super(width, height); 82320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns isOverflowButton = false; 82420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 82520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 82649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes LayoutParams(int width, int height, boolean isOverflowButton) { 82720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns super(width, height); 82820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns this.isOverflowButton = isOverflowButton; 82920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 830bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 831bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell} 832