196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell/* 296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * Copyright (C) 2010 The Android Open Source Project 396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * 496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * you may not use this file except in compliance with the License. 696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * You may obtain a copy of the License at 796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * 896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * http://www.apache.org/licenses/LICENSE-2.0 996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * 1096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * Unless required by applicable law or agreed to in writing, software 1196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * distributed under the License is distributed on an "AS IS" BASIS, 1296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * See the License for the specific language governing permissions and 1496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * limitations under the License. 1596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell */ 1696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellpackage com.android.internal.view.menu; 1796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell 18d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powellimport com.android.internal.R; 19d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell 2096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.content.Context; 218028dd32a4a04154050220dd0693583d5b750330Adam Powellimport android.content.res.Configuration; 22367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powellimport android.content.res.TypedArray; 2396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.util.AttributeSet; 246b336f835d637853800b94689375a03f337139a4Adam Powellimport android.view.Gravity; 25cf78b3e5101349fdddbde14b3a55140f9562ae66Adam Powellimport android.view.View; 26640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powellimport android.view.ViewDebug; 277ade1be822ed05a143b059319dccd5e9f623b56dAdam Powellimport android.view.ViewGroup; 287bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powellimport android.view.accessibility.AccessibilityEvent; 2996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellimport android.widget.LinearLayout; 3096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell 3196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell/** 3296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell * @hide 3396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell */ 3496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powellpublic class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvoker, MenuView { 3596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell private static final String TAG = "ActionMenuView"; 3696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell 3735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell static final int MIN_CELL_SIZE = 56; // dips 38be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell static final int GENERATED_ITEM_PADDING = 4; // dips 3935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 4096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell private MenuBuilder mMenu; 417ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell 428028dd32a4a04154050220dd0693583d5b750330Adam Powell private boolean mReserveOverflow; 43696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell private ActionMenuPresenter mPresenter; 44640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell private boolean mFormatItems; 4589b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell private int mFormatItemsWidth; 4635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell private int mMinCellSize; 47be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell private int mGeneratedItemPadding; 4835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell private int mMeasuredExtraWidth; 49367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell private int mMaxItemHeight; 508515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell 5196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell public ActionMenuView(Context context) { 5296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell this(context, null); 5396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell } 5496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell 5596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell public ActionMenuView(Context context, AttributeSet attrs) { 5696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell super(context, attrs); 57f16888f1e849b0bc0b9c17e5f833c4e2cd54c382Adam Powell setBaselineAligned(false); 58be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell final float density = context.getResources().getDisplayMetrics().density; 59be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell mMinCellSize = (int) (MIN_CELL_SIZE * density); 60be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density); 61367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell 62367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, 63367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell R.attr.actionBarStyle, 0); 64367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell mMaxItemHeight = a.getDimensionPixelSize(R.styleable.ActionBar_height, 0); 65367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell a.recycle(); 66773b1b97fc0f01efc8cf1e17a1250a9b654b1b85Adam Powell } 67773b1b97fc0f01efc8cf1e17a1250a9b654b1b85Adam Powell 68696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public void setPresenter(ActionMenuPresenter presenter) { 69696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenter = presenter; 70696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 71696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 7235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell public boolean isExpandedFormat() { 7335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell return mFormatItems; 7435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 7535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 76d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell public void setMaxItemHeight(int maxItemHeight) { 77d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell mMaxItemHeight = maxItemHeight; 78d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell requestLayout(); 79d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell } 80d5c81db1e78e98f3e0a1a5cf206865c3056294c4Adam Powell 816c6f575423d6718c3ff322224c1520901ce881e1Adam Powell @Override 82773b1b97fc0f01efc8cf1e17a1250a9b654b1b85Adam Powell public void onConfigurationChanged(Configuration newConfig) { 838515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell super.onConfigurationChanged(newConfig); 84696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenter.updateMenuView(false); 856c6f575423d6718c3ff322224c1520901ce881e1Adam Powell 86696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (mPresenter != null && mPresenter.isOverflowMenuShowing()) { 87696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenter.hideOverflowMenu(); 88696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenter.showOverflowMenu(); 896c6f575423d6718c3ff322224c1520901ce881e1Adam Powell } 90773b1b97fc0f01efc8cf1e17a1250a9b654b1b85Adam Powell } 91773b1b97fc0f01efc8cf1e17a1250a9b654b1b85Adam Powell 928515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell @Override 93640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 9435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // If we've been given an exact size to match, apply special formatting during layout. 9589b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell final boolean wasFormatted = mFormatItems; 9635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY; 9789b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell 9889b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell if (wasFormatted != mFormatItems) { 9989b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell mFormatItemsWidth = 0; // Reset this when switching modes 10089b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell } 10189b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell 10289b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell // Special formatting can change whether items can fit as action buttons. 10389b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell // Kick the menu and update presenters when this changes. 10489b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell final int widthSize = MeasureSpec.getMode(widthMeasureSpec); 10589b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) { 10689b09da7b3b1e69264d9ec710c66eb2f891b313eAdam Powell mFormatItemsWidth = widthSize; 107640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell mMenu.onItemsChanged(true); 108640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 10935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 11035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell if (mFormatItems) { 11135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec); 11235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } else { 11375d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell // Previous measurement at exact format may have set margins - reset them. 11475d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell final int childCount = getChildCount(); 11575d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell for (int i = 0; i < childCount; i++) { 11675d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell final View child = getChildAt(i); 11775d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 11875d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell lp.leftMargin = lp.rightMargin = 0; 11975d022af1f24cf2d8a7551183ea5bbe943d25d21Adam Powell } 12035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell super.onMeasure(widthMeasureSpec, heightMeasureSpec); 12135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 12235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 12335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 12435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) { 12535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // We already know the width mode is EXACTLY if we're here. 12635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 12735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell int widthSize = MeasureSpec.getSize(widthMeasureSpec); 12835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell int heightSize = MeasureSpec.getSize(heightMeasureSpec); 12935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 13035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int widthPadding = getPaddingLeft() + getPaddingRight(); 13135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int heightPadding = getPaddingTop() + getPaddingBottom(); 13235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 133367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell final int itemHeightSpec = heightMode == MeasureSpec.EXACTLY 134367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell ? MeasureSpec.makeMeasureSpec(heightSize - heightPadding, MeasureSpec.EXACTLY) 135367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell : MeasureSpec.makeMeasureSpec( 136367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell Math.min(mMaxItemHeight, heightSize - heightPadding), MeasureSpec.AT_MOST); 137367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell 13835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell widthSize -= widthPadding; 13935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 14035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // Divide the view into cells. 14135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int cellCount = widthSize / mMinCellSize; 14235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int cellSizeRemaining = widthSize % mMinCellSize; 1433bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell 1443bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell if (cellCount == 0) { 1453bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell // Give up, nothing fits. 1463bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell setMeasuredDimension(widthSize, 0); 1473bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell return; 1483bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell } 1493bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell 15035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int cellSize = mMinCellSize + cellSizeRemaining / cellCount; 15135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 15235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell int cellsRemaining = cellCount; 15335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell int maxChildHeight = 0; 15435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell int maxCellsUsed = 0; 155160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell int expandableItemCount = 0; 15614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell int visibleItemCount = 0; 15714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell boolean hasOverflow = false; 15835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 15914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell // This is used as a bitfield to locate the smallest items present. Assumes childCount < 64. 16014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell long smallestItemsAt = 0; 16135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 16235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int childCount = getChildCount(); 16335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell for (int i = 0; i < childCount; i++) { 16435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final View child = getChildAt(i); 16514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if (child.getVisibility() == GONE) continue; 16614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell 167be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell final boolean isGeneratedItem = child instanceof ActionMenuItemView; 16814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell visibleItemCount++; 16914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell 170be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell if (isGeneratedItem) { 171be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell // Reset padding for generated menu item views; it may change below 172be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell // and views are recycled. 173be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0); 174be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell } 175be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell 17635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 17735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell lp.expanded = false; 17835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell lp.extraPixels = 0; 17935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell lp.cellsUsed = 0; 180160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell lp.expandable = false; 18114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell lp.leftMargin = 0; 18214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell lp.rightMargin = 0; 183be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText(); 18435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 18535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // Overflow always gets 1 cell. No more, no less. 18635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining; 18735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 18835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable, 189367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell itemHeightSpec, heightPadding); 19035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 19135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell maxCellsUsed = Math.max(maxCellsUsed, cellsUsed); 192160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell if (lp.expandable) expandableItemCount++; 19314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if (lp.isOverflowButton) hasOverflow = true; 19435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 19535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell cellsRemaining -= cellsUsed; 19635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight()); 19714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if (cellsUsed == 1) smallestItemsAt |= (1 << i); 19835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 19935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 200be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell // When we have overflow and a single expanded (text) item, we want to try centering it 201be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell // visually in the available space even though overflow consumes some of it. 202be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2; 203be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell 20435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // Divide space for remaining cells if we have items that can expand. 20535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // Try distributing whole leftover cells to smaller items first. 20635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 20735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell boolean needsExpansion = false; 208160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell while (expandableItemCount > 0 && cellsRemaining > 0) { 20935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell int minCells = Integer.MAX_VALUE; 21035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell long minCellsAt = 0; // Bit locations are indices of relevant child views 21135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell int minCellsItemCount = 0; 21235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell for (int i = 0; i < childCount; i++) { 21335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final View child = getChildAt(i); 21435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 21535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 21635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // Don't try to expand items that shouldn't. 217160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell if (!lp.expandable) continue; 21835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 21935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // Mark indices of children that can receive an extra cell. 22035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell if (lp.cellsUsed < minCells) { 22135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell minCells = lp.cellsUsed; 22235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell minCellsAt = 1 << i; 22335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell minCellsItemCount = 1; 22435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } else if (lp.cellsUsed == minCells) { 22535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell minCellsAt |= 1 << i; 22635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell minCellsItemCount++; 22735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 22835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 22935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 23035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // Items that get expanded will always be in the set of smallest items when we're done. 23114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell smallestItemsAt |= minCellsAt; 23235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 233be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop. 23435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 235be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell // We have enough cells, all minimum size items will be incremented. 236be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell minCells++; 237be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell 238be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell for (int i = 0; i < childCount; i++) { 23935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final View child = getChildAt(i); 24035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 241be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell if ((minCellsAt & (1 << i)) == 0) { 242be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell // If this item is already at our small item count, mark it for later. 243be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i; 244be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell continue; 245be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell } 246be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell 247be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) { 248be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell // Add padding to this item such that it centers. 249be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0); 250be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell } 25135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell lp.cellsUsed++; 25235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell lp.expanded = true; 25335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell cellsRemaining--; 25435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 25535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 25635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell needsExpansion = true; 25735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 25835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 25935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // Divide any space left that wouldn't divide along cell boundaries 26014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell // evenly among the smallest items 26114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell 26214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell final boolean singleItem = !hasOverflow && visibleItemCount == 1; 26314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if (cellsRemaining > 0 && smallestItemsAt != 0 && 264be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell (cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) { 26514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell float expandCount = Long.bitCount(smallestItemsAt); 26614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell 26714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if (!singleItem) { 26814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell // The items at the far edges may only expand by half in order to pin to either side. 26914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if ((smallestItemsAt & 1) != 0) { 270be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams(); 271be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell if (!lp.preventEdgeOffset) expandCount -= 0.5f; 27214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell } 27314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if ((smallestItemsAt & (1 << (childCount - 1))) != 0) { 274be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams()); 275be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell if (!lp.preventEdgeOffset) expandCount -= 0.5f; 27614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell } 27714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell } 27835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 2793bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell final int extraPixels = expandCount > 0 ? 2803bb421d5b85a8a99c408d16e4f80163a53bc0505Adam Powell (int) (cellsRemaining * cellSize / expandCount) : 0; 28135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 28235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell for (int i = 0; i < childCount; i++) { 28314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if ((smallestItemsAt & (1 << i)) == 0) continue; 28435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 28535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final View child = getChildAt(i); 28635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 28714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if (child instanceof ActionMenuItemView) { 28814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell // If this is one of our views, expand and measure at the larger size. 28914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell lp.extraPixels = extraPixels; 29014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell lp.expanded = true; 291be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell if (i == 0 && !lp.preventEdgeOffset) { 29214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell // First item gets part of its new padding pushed out of sight. 29314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell // The last item will get this implicitly from layout. 29414b7e2c1688914ba8b6854738981337d7c0653beAdam Powell lp.leftMargin = -extraPixels / 2; 29514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell } 29614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell needsExpansion = true; 29714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell } else if (lp.isOverflowButton) { 29814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell lp.extraPixels = extraPixels; 29914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell lp.expanded = true; 30014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell lp.rightMargin = -extraPixels / 2; 30114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell needsExpansion = true; 30214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell } else { 30314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell // If we don't know what it is, give it some margins instead 30414b7e2c1688914ba8b6854738981337d7c0653beAdam Powell // and let it center within its space. We still want to pin 30514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell // against the edges. 30614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if (i != 0) { 30714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell lp.leftMargin = extraPixels / 2; 30814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell } 30914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if (i != childCount - 1) { 31014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell lp.rightMargin = extraPixels / 2; 31114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell } 31214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell } 31335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 31435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 31535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell cellsRemaining = 0; 31635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 31735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 31835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell // Remeasure any items that have had extra space allocated to them. 31935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell if (needsExpansion) { 32035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell for (int i = 0; i < childCount; i++) { 32135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final View child = getChildAt(i); 32235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 32335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 32435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell if (!lp.expanded) continue; 32535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 32635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int width = lp.cellsUsed * cellSize + lp.extraPixels; 327367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 328367ee326058bbee6fc179b8b1eb2174fe7ba8f45Adam Powell itemHeightSpec); 32935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 33035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 33135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 33235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell if (heightMode != MeasureSpec.EXACTLY) { 33335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell heightSize = maxChildHeight; 33435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 33535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 33635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell setMeasuredDimension(widthSize, heightSize); 33735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell mMeasuredExtraWidth = cellsRemaining * cellSize; 33835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 33935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 34035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell /** 34135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell * Measure a child view to fit within cell-based formatting. The child's width 34235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell * will be measured to a whole multiple of cellSize. 34335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell * 344160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell * <p>Sets the expandable and cellsUsed fields of LayoutParams. 34535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell * 34635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell * @param child Child to measure 34735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell * @param cellSize Size of one cell 34835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell * @param cellsRemaining Number of cells remaining that this view can expand to fill 34935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell * @param parentHeightMeasureSpec MeasureSpec used by the parent view 35035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell * @param parentHeightPadding Padding present in the parent view 35135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell * @return Number of cells this child was measured to occupy 35235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell */ 35335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell static int measureChildForCells(View child, int cellSize, int cellsRemaining, 35435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell int parentHeightMeasureSpec, int parentHeightPadding) { 35535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 35635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 35735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) - 35835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell parentHeightPadding; 35935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec); 36035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode); 36135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 362a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell final ActionMenuItemView itemView = child instanceof ActionMenuItemView ? 363a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell (ActionMenuItemView) child : null; 364a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell final boolean hasText = itemView != null && itemView.hasText(); 365a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell 366160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell int cellsUsed = 0; 367a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell if (cellsRemaining > 0 && (!hasText || cellsRemaining >= 2)) { 36835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int childWidthSpec = MeasureSpec.makeMeasureSpec( 36935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell cellSize * cellsRemaining, MeasureSpec.AT_MOST); 37035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell child.measure(childWidthSpec, childHeightSpec); 37135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 37235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int measuredWidth = child.getMeasuredWidth(); 37335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell cellsUsed = measuredWidth / cellSize; 37435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell if (measuredWidth % cellSize != 0) cellsUsed++; 375a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell if (hasText && cellsUsed < 2) cellsUsed = 2; 37635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 377160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell 378a7dec6d9734bdc3a9e39ffd357002e25c6fdc99bAdam Powell final boolean expandable = !lp.isOverflowButton && hasText; 379160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell lp.expandable = expandable; 380160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell 38135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell lp.cellsUsed = cellsUsed; 38235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int targetWidth = cellsUsed * cellSize; 38335aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY), 38435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell childHeightSpec); 38535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell return cellsUsed; 386640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 387640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 388640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell @Override 389640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 390640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell if (!mFormatItems) { 391640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell super.onLayout(changed, left, top, right, bottom); 392640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell return; 393640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 394640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 395640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell final int childCount = getChildCount(); 396640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell final int midVertical = (top + bottom) / 2; 397640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell final int dividerWidth = getDividerWidth(); 398640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell int overflowWidth = 0; 399640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell int nonOverflowWidth = 0; 400640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell int nonOverflowCount = 0; 401640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell int widthRemaining = right - left - getPaddingRight() - getPaddingLeft(); 40235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell boolean hasOverflow = false; 4030762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio final boolean isLayoutRtl = isLayoutRtl(); 404640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell for (int i = 0; i < childCount; i++) { 405640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell final View v = getChildAt(i); 406640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell if (v.getVisibility() == GONE) { 407640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell continue; 408640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 409640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 410640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell LayoutParams p = (LayoutParams) v.getLayoutParams(); 411640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell if (p.isOverflowButton) { 412640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell overflowWidth = v.getMeasuredWidth(); 413640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell if (hasDividerBeforeChildAt(i)) { 414640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell overflowWidth += dividerWidth; 415640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 416640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 417640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell int height = v.getMeasuredHeight(); 4180762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio int r; 4190762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio int l; 4200762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio if (isLayoutRtl) { 4210762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio l = getPaddingLeft() + p.leftMargin; 4220762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio r = l + overflowWidth; 4230762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio } else { 4240762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio r = getWidth() - getPaddingRight() - p.rightMargin; 4250762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio l = r - overflowWidth; 4260762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio } 427640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell int t = midVertical - (height / 2); 428640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell int b = t + height; 429640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell v.layout(l, t, r, b); 430640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 431640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell widthRemaining -= overflowWidth; 43235aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell hasOverflow = true; 433640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } else { 43435aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin; 43535aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell nonOverflowWidth += size; 43635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell widthRemaining -= size; 437640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell if (hasDividerBeforeChildAt(i)) { 438640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell nonOverflowWidth += dividerWidth; 439640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 440640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell nonOverflowCount++; 441640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 442640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 443640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 44414b7e2c1688914ba8b6854738981337d7c0653beAdam Powell if (childCount == 1 && !hasOverflow) { 44514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell // Center a single child 44614b7e2c1688914ba8b6854738981337d7c0653beAdam Powell final View v = getChildAt(0); 44714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell final int width = v.getMeasuredWidth(); 44814b7e2c1688914ba8b6854738981337d7c0653beAdam Powell final int height = v.getMeasuredHeight(); 44914b7e2c1688914ba8b6854738981337d7c0653beAdam Powell final int midHorizontal = (right - left) / 2; 45014b7e2c1688914ba8b6854738981337d7c0653beAdam Powell final int l = midHorizontal - width / 2; 45114b7e2c1688914ba8b6854738981337d7c0653beAdam Powell final int t = midVertical - height / 2; 45214b7e2c1688914ba8b6854738981337d7c0653beAdam Powell v.layout(l, t, l + width, t + height); 45314b7e2c1688914ba8b6854738981337d7c0653beAdam Powell return; 45414b7e2c1688914ba8b6854738981337d7c0653beAdam Powell } 45514b7e2c1688914ba8b6854738981337d7c0653beAdam Powell 45635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1); 45714b7e2c1688914ba8b6854738981337d7c0653beAdam Powell final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0); 458640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 4590762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio if (isLayoutRtl) { 4600762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio int startRight = getWidth() - getPaddingRight(); 4610762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio for (int i = 0; i < childCount; i++) { 4620762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio final View v = getChildAt(i); 4630762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio final LayoutParams lp = (LayoutParams) v.getLayoutParams(); 4640762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio if (v.getVisibility() == GONE || lp.isOverflowButton) { 4650762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio continue; 4660762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio } 4670762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio 4680762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio startRight -= lp.rightMargin; 4690762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio int width = v.getMeasuredWidth(); 4700762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio int height = v.getMeasuredHeight(); 4710762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio int t = midVertical - height / 2; 4720762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio v.layout(startRight - width, t, startRight, t + height); 4730762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio startRight -= width + lp.leftMargin + spacerSize; 474640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 4750762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio } else { 4760762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio int startLeft = getPaddingLeft(); 4770762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio for (int i = 0; i < childCount; i++) { 4780762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio final View v = getChildAt(i); 4790762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio final LayoutParams lp = (LayoutParams) v.getLayoutParams(); 4800762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio if (v.getVisibility() == GONE || lp.isOverflowButton) { 4810762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio continue; 4820762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio } 483640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 4840762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio startLeft += lp.leftMargin; 4850762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio int width = v.getMeasuredWidth(); 4860762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio int height = v.getMeasuredHeight(); 4870762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio int t = midVertical - height / 2; 4880762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio v.layout(startLeft, t, startLeft + width, t + height); 4890762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio startLeft += width + lp.rightMargin + spacerSize; 4900762cec04fa5ce65a2adc6d70ea1396041b1a88dFabrice Di Meglio } 491640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 492640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 493640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 494640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell @Override 4958515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell public void onDetachedFromWindow() { 4968515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell super.onDetachedFromWindow(); 497696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell mPresenter.dismissPopupMenus(); 4988028dd32a4a04154050220dd0693583d5b750330Adam Powell } 4998028dd32a4a04154050220dd0693583d5b750330Adam Powell 5008028dd32a4a04154050220dd0693583d5b750330Adam Powell public boolean isOverflowReserved() { 5018028dd32a4a04154050220dd0693583d5b750330Adam Powell return mReserveOverflow; 5027ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell } 5037ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell 504b366bbae2b5a3009893ef64246e3430cea4b7736Adam Powell public void setOverflowReserved(boolean reserveOverflow) { 505b366bbae2b5a3009893ef64246e3430cea4b7736Adam Powell mReserveOverflow = reserveOverflow; 506b366bbae2b5a3009893ef64246e3430cea4b7736Adam Powell } 507f0ad6e6eaf48ac8f4007232ad0a8511a7b5cfc0eAdam Powell 5087ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell @Override 5097ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell protected LayoutParams generateDefaultLayoutParams() { 5107ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, 5117ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell LayoutParams.WRAP_CONTENT); 5126b336f835d637853800b94689375a03f337139a4Adam Powell params.gravity = Gravity.CENTER_VERTICAL; 5137ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell return params; 5147ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell } 5157ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell 5167ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell @Override 51735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell public LayoutParams generateLayoutParams(AttributeSet attrs) { 51835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell return new LayoutParams(getContext(), attrs); 51935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell } 52035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell 52135aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell @Override 5227ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 5238c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell if (p != null) { 5248c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell final LayoutParams result = p instanceof LayoutParams 5258c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell ? new LayoutParams((LayoutParams) p) 5268c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell : new LayoutParams(p); 5273f476b34049d062942eafcf48396f593e00bd324Adam Powell if (result.gravity <= Gravity.NO_GRAVITY) { 5283f476b34049d062942eafcf48396f593e00bd324Adam Powell result.gravity = Gravity.CENTER_VERTICAL; 5293f476b34049d062942eafcf48396f593e00bd324Adam Powell } 5303f476b34049d062942eafcf48396f593e00bd324Adam Powell return result; 5313f476b34049d062942eafcf48396f593e00bd324Adam Powell } 5327ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell return generateDefaultLayoutParams(); 5337ade1be822ed05a143b059319dccd5e9f623b56dAdam Powell } 53496675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell 535696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 536696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 53735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell return p != null && p instanceof LayoutParams; 538696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell } 539696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell 540640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell public LayoutParams generateOverflowButtonLayoutParams() { 541640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell LayoutParams result = generateDefaultLayoutParams(); 542640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell result.isOverflowButton = true; 543640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell return result; 544640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 545640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 54696675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell public boolean invokeItem(MenuItemImpl item) { 54796675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell return mMenu.performItemAction(item, 0); 54896675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell } 54996675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell 55096675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell public int getWindowAnimations() { 55196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell return 0; 55296675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell } 55396675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell 554696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public void initialize(MenuBuilder menu) { 55596675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell mMenu = menu; 556f6148c53f93978af678cc0559a4417b608a33ae1Adam Powell } 557f6148c53f93978af678cc0559a4417b608a33ae1Adam Powell 558696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell @Override 559696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell protected boolean hasDividerBeforeChildAt(int childIndex) { 560825992f503439bc87d9d7e698a487f17b5acc243Jake Wharton if (childIndex == 0) { 561825992f503439bc87d9d7e698a487f17b5acc243Jake Wharton return false; 562825992f503439bc87d9d7e698a487f17b5acc243Jake Wharton } 563696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell final View childBefore = getChildAt(childIndex - 1); 564696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell final View child = getChildAt(childIndex); 565696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell boolean result = false; 566696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) { 567696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell result |= ((ActionMenuChildView) childBefore).needsDividerAfter(); 5688028dd32a4a04154050220dd0693583d5b750330Adam Powell } 569696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell if (childIndex > 0 && child instanceof ActionMenuChildView) { 570696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell result |= ((ActionMenuChildView) child).needsDividerBefore(); 571be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell } 572be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell return result; 573be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell } 574be4d68e7b238b8ee879de0481e39c40d3f1683b6Adam Powell 5757bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 5767bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell return false; 5777bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell } 5787bc3ca0dc52be52ecad1c0de8c62a6a4bf8141caAdam Powell 579696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public interface ActionMenuChildView { 580696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public boolean needsDividerBefore(); 581696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell public boolean needsDividerAfter(); 5828515ee846bd76aee86ec5ddfcc4dd1e626dd999cAdam Powell } 583640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 584640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell public static class LayoutParams extends LinearLayout.LayoutParams { 585640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell @ViewDebug.ExportedProperty(category = "layout") 586640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell public boolean isOverflowButton; 58735aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell @ViewDebug.ExportedProperty(category = "layout") 58835aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell public int cellsUsed; 58935aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell @ViewDebug.ExportedProperty(category = "layout") 59035aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell public int extraPixels; 591160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell @ViewDebug.ExportedProperty(category = "layout") 592160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell public boolean expandable; 593be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell @ViewDebug.ExportedProperty(category = "layout") 594be3c329ebec083e5ff933bab6b6c501519ad2bffAdam Powell public boolean preventEdgeOffset; 595160bb7fa60e8ece654e6ce999b6c16af50ee7357Adam Powell 59635aecd5884a5ccfe380903e39f30f468315e8f92Adam Powell public boolean expanded; 597640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 598640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell public LayoutParams(Context c, AttributeSet attrs) { 599640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell super(c, attrs); 600640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 601640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 6028c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell public LayoutParams(ViewGroup.LayoutParams other) { 6038c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell super(other); 6048c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell } 6058c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell 606640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell public LayoutParams(LayoutParams other) { 607640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell super((LinearLayout.LayoutParams) other); 608640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell isOverflowButton = other.isOverflowButton; 609640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 610640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 611640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell public LayoutParams(int width, int height) { 612640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell super(width, height); 613640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell isOverflowButton = false; 614640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 615640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell 616640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell public LayoutParams(int width, int height, boolean isOverflowButton) { 617640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell super(width, height); 618640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell this.isOverflowButton = isOverflowButton; 619640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 620640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell } 62196675b1df3969f2d313b68f60ed9fa36805db8ceAdam Powell} 622