Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70359ce2 authored by Adam Powell's avatar Adam Powell Committed by Android (Google) Code Review
Browse files

Merge "Fix bug 3050138 - Action bar does not display correctly when many...

Merge "Fix bug 3050138 - Action bar does not display correctly when many action items are added" into honeycomb
parents 8a852406 36fced9b
Loading
Loading
Loading
Loading
+21 −4
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
@@ -44,6 +43,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
    private MenuBuilder mMenu;

    private int mMaxItems;
    private int mWidthLimit;
    private boolean mReserveOverflow;
    private OverflowMenuButton mOverflowButton;
    private MenuPopupHelper mOverflowPopup;
@@ -91,6 +91,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
        final int screen = res.getConfiguration().screenLayout;
        mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
                Configuration.SCREENLAYOUT_SIZE_XLARGE;
        mWidthLimit = res.getDisplayMetrics().widthPixels / 2;
        
        TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
        mDivider = a.getDrawable(com.android.internal.R.styleable.Theme_dividerVertical);
@@ -108,6 +109,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
        mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
                Configuration.SCREENLAYOUT_SIZE_XLARGE;
        mMaxItems = getMaxActionButtons();
        mWidthLimit = getResources().getDisplayMetrics().widthPixels / 2;
        if (mMenu != null) {
            mMenu.setMaxActionItems(mMaxItems);
            updateChildren(false);
@@ -172,6 +174,19 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
    }

    public void initialize(MenuBuilder menu, int menuType) {
        int width = mWidthLimit;
        if (mReserveOverflow) {
            if (mOverflowButton == null) {
                OverflowMenuButton button = new OverflowMenuButton(mContext);
                mOverflowButton = button;
            }
            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
            mOverflowButton.measure(spec, spec);
            width -= mOverflowButton.getMeasuredWidth();
        }

        menu.setActionWidthLimit(width);

        menu.setMaxActionItems(mMaxItems);
        mMenu = menu;
        updateChildren(true);
@@ -219,9 +234,11 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
                if (itemCount > 0) {
                    addView(makeDividerView(), makeDividerLayoutParams());
                }
                if (mOverflowButton == null) {
                    OverflowMenuButton button = new OverflowMenuButton(mContext);
                addView(button);
                    mOverflowButton = button;
                }
                addView(mOverflowButton);
            } else {
                mOverflowButton = null;
            }
+117 −4
Original line number Diff line number Diff line
@@ -27,9 +27,10 @@ import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TypedValue;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextThemeWrapper;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -38,8 +39,8 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.BaseAdapter;

@@ -163,6 +164,10 @@ public class MenuBuilder implements Menu {
     * The number of visible action buttons permitted in this menu
     */
    private int mMaxActionItems;
    /**
     * The total width limit in pixels for all action items within a menu
     */
    private int mActionWidthLimit;
    /**
     * Whether or not the items (or any one item's action state) has changed since it was
     * last fetched.
@@ -208,6 +213,11 @@ public class MenuBuilder implements Menu {
    
    private boolean mOptionalIconsVisible = false;

    private ViewGroup mMeasureActionButtonParent;

    // Group IDs that have been added as actions - used temporarily, allocated here for reuse.
    private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();

    private static int getAlertDialogTheme(Context context) {
        TypedValue outValue = new TypedValue();
        context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
@@ -1035,6 +1045,44 @@ public class MenuBuilder implements Menu {
        return mVisibleItems;
    }
    
    /**
     * @return A fake action button parent view for obtaining child views.
     */
    private ViewGroup getMeasureActionButtonParent() {
        if (mMeasureActionButtonParent == null) {
            mMeasureActionButtonParent = (ViewGroup) mMenuTypes[TYPE_ACTION_BUTTON].getInflater()
                    .inflate(LAYOUT_RES_FOR_TYPE[TYPE_ACTION_BUTTON], null, false);
        }
        return mMeasureActionButtonParent;
    }

    /**
     * This method determines which menu items get to be 'action items' that will appear
     * in an action bar and which items should be 'overflow items' in a secondary menu.
     * The rules are as follows:
     *
     * <p>Items are considered for inclusion in the order specified within the menu.
     * There is a limit of mMaxActionItems as a total count, optionally including the overflow
     * menu button itself. This is a soft limit; if an item shares a group ID with an item
     * previously included as an action item, the new item will stay with its group and become
     * an action item itself even if it breaks the max item count limit. This is done to
     * limit the conceptual complexity of the items presented within an action bar. Only a few
     * unrelated concepts should be presented to the user in this space, and groups are treated
     * as a single concept.
     *
     * <p>There is also a hard limit of consumed measurable space: mActionWidthLimit. This
     * limit may be broken by a single item that exceeds the remaining space, but no further
     * items may be added. If an item that is part of a group cannot fit within the remaining
     * measured width, the entire group will be demoted to overflow. This is done to ensure room
     * for navigation and other affordances in the action bar as well as reduce general UI clutter.
     *
     * <p>The space freed by demoting a full group cannot be consumed by future menu items.
     * Once items begin to overflow, all future items become overflow items as well. This is
     * to avoid inadvertent reordering that may break the app's intended design.
     *
     * @param reserveActionOverflow true if an overflow button should consume one space
     *                              in the available item count
     */
    private void flagActionItems(boolean reserveActionOverflow) {
        if (reserveActionOverflow != mReserveActionOverflow) {
            mReserveActionOverflow = reserveActionOverflow;
@@ -1048,9 +1096,13 @@ public class MenuBuilder implements Menu {
        final ArrayList<MenuItemImpl> visibleItems = getVisibleItems();
        final int itemsSize = visibleItems.size();
        int maxActions = mMaxActionItems;
        int widthLimit = mActionWidthLimit;
        final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        final ViewGroup parent = getMeasureActionButtonParent();

        int requiredItems = 0;
        int requestedItems = 0;
        int firstActionWidth = 0;
        boolean hasOverflow = false;
        for (int i = 0; i < itemsSize; i++) {
            MenuItemImpl item = visibleItems.get(i);
@@ -1070,12 +1122,68 @@ public class MenuBuilder implements Menu {
        }
        maxActions -= requiredItems;

        final SparseBooleanArray seenGroups = mActionButtonGroups;
        seenGroups.clear();

        // Flag as many more requested items as will fit.
        for (int i = 0; i < itemsSize; i++) {
            MenuItemImpl item = visibleItems.get(i);
            if (item.requestsActionButton()) {
                item.setIsActionButton(maxActions > 0);

            if (item.requiresActionButton()) {
                View v = item.getActionView();
                if (v == null) {
                    v = item.getItemView(TYPE_ACTION_BUTTON, parent);
                }
                v.measure(querySpec, querySpec);
                final int measuredWidth = v.getMeasuredWidth();
                widthLimit -= measuredWidth;
                if (firstActionWidth == 0) {
                    firstActionWidth = measuredWidth;
                }
                final int groupId = item.getGroupId();
                if (groupId != 0) {
                    seenGroups.put(groupId, true);
                }
            } else if (item.requestsActionButton()) {
                // Items in a group with other items that already have an action slot
                // can break the max actions rule, but not the width limit.
                final int groupId = item.getGroupId();
                final boolean inGroup = seenGroups.get(groupId);
                boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0;
                maxActions--;

                if (isAction) {
                    View v = item.getActionView();
                    if (v == null) {
                        v = item.getItemView(TYPE_ACTION_BUTTON, parent);
                    }
                    v.measure(querySpec, querySpec);
                    final int measuredWidth = v.getMeasuredWidth();
                    widthLimit -= measuredWidth;
                    if (firstActionWidth == 0) {
                        firstActionWidth = measuredWidth;
                    }

                    // Did this push the entire first item past halfway?
                    if (widthLimit + firstActionWidth <= 0) {
                        isAction = false;
                    }
                }

                if (isAction && groupId != 0) {
                    seenGroups.put(groupId, true);
                } else if (inGroup) {
                    // We broke the width limit. Demote the whole group, they all overflow now.
                    seenGroups.put(groupId, false);
                    for (int j = 0; j < i; j++) {
                        MenuItemImpl areYouMyGroupie = visibleItems.get(j);
                        if (areYouMyGroupie.getGroupId() == groupId) {
                            areYouMyGroupie.setIsActionButton(false);
                        }
                    }
                }

                item.setIsActionButton(isAction);
            }
        }

@@ -1108,6 +1216,11 @@ public class MenuBuilder implements Menu {
        mIsActionItemsStale = true;
    }

    void setActionWidthLimit(int widthLimit) {
        mActionWidthLimit = widthLimit;
        mIsActionItemsStale = true;
    }

    public void clearHeader() {
        mHeaderIcon = null;
        mHeaderTitle = null;