Fix bug 5191728 - Specialized formatting in the split action bar

Visually center a single text menu item in the split action bar even
when an overflow button is present.

Fix a bug in allocating space in the split action bar.

Change-Id: I54eff86bf35197030c9c1656ebd71297e3c8b62b
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index d613921..b355c41 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -31,6 +31,7 @@
     private static final String TAG = "ActionMenuView";
     
     static final int MIN_CELL_SIZE = 56; // dips
+    static final int GENERATED_ITEM_PADDING = 4; // dips
 
     private MenuBuilder mMenu;
 
@@ -39,6 +40,7 @@
     private boolean mFormatItems;
     private int mFormatItemsWidth;
     private int mMinCellSize;
+    private int mGeneratedItemPadding;
     private int mMeasuredExtraWidth;
 
     public ActionMenuView(Context context) {
@@ -48,7 +50,9 @@
     public ActionMenuView(Context context, AttributeSet attrs) {
         super(context, attrs);
         setBaselineAligned(false);
-        mMinCellSize = (int) (MIN_CELL_SIZE * context.getResources().getDisplayMetrics().density);
+        final float density = context.getResources().getDisplayMetrics().density;
+        mMinCellSize = (int) (MIN_CELL_SIZE * density);
+        mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density);
     }
 
     public void setPresenter(ActionMenuPresenter presenter) {
@@ -133,8 +137,15 @@
             final View child = getChildAt(i);
             if (child.getVisibility() == GONE) continue;
 
+            final boolean isGeneratedItem = child instanceof ActionMenuItemView;
             visibleItemCount++;
 
+            if (isGeneratedItem) {
+                // Reset padding for generated menu item views; it may change below
+                // and views are recycled.
+                child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0);
+            }
+
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             lp.expanded = false;
             lp.extraPixels = 0;
@@ -142,6 +153,7 @@
             lp.expandable = false;
             lp.leftMargin = 0;
             lp.rightMargin = 0;
+            lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText();
 
             // Overflow always gets 1 cell. No more, no less.
             final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining;
@@ -158,6 +170,10 @@
             if (cellsUsed == 1) smallestItemsAt |= (1 << i);
         }
 
+        // When we have overflow and a single expanded (text) item, we want to try centering it
+        // visually in the available space even though overflow consumes some of it.
+        final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2;
+
         // Divide space for remaining cells if we have items that can expand.
         // Try distributing whole leftover cells to smaller items first.
 
@@ -184,16 +200,27 @@
                 }
             }
 
-            if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop.
-
             // Items that get expanded will always be in the set of smallest items when we're done.
             smallestItemsAt |= minCellsAt;
 
-            for (int i = 0; i < childCount; i++) {
-                if ((minCellsAt & (1 << i)) == 0) continue;
+            if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop.
 
+            // We have enough cells, all minimum size items will be incremented.
+            minCells++;
+
+            for (int i = 0; i < childCount; i++) {
                 final View child = getChildAt(i);
                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if ((minCellsAt & (1 << i)) == 0) {
+                    // If this item is already at our small item count, mark it for later.
+                    if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i;
+                    continue;
+                }
+
+                if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) {
+                    // Add padding to this item such that it centers.
+                    child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0);
+                }
                 lp.cellsUsed++;
                 lp.expanded = true;
                 cellsRemaining--;
@@ -207,16 +234,18 @@
 
         final boolean singleItem = !hasOverflow && visibleItemCount == 1;
         if (cellsRemaining > 0 && smallestItemsAt != 0 &&
-                (cellsRemaining < visibleItemCount - 1 || singleItem)) {
+                (cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) {
             float expandCount = Long.bitCount(smallestItemsAt);
 
             if (!singleItem) {
                 // The items at the far edges may only expand by half in order to pin to either side.
                 if ((smallestItemsAt & 1) != 0) {
-                    expandCount -= 0.5f;
+                    LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams();
+                    if (!lp.preventEdgeOffset) expandCount -= 0.5f;
                 }
                 if ((smallestItemsAt & (1 << (childCount - 1))) != 0) {
-                    expandCount -= 0.5f;
+                    LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams());
+                    if (!lp.preventEdgeOffset) expandCount -= 0.5f;
                 }
             }
 
@@ -232,7 +261,7 @@
                     // If this is one of our views, expand and measure at the larger size.
                     lp.extraPixels = extraPixels;
                     lp.expanded = true;
-                    if (i == 0) {
+                    if (i == 0 && !lp.preventEdgeOffset) {
                         // First item gets part of its new padding pushed out of sight.
                         // The last item will get this implicitly from layout.
                         lp.leftMargin = -extraPixels / 2;
@@ -496,6 +525,8 @@
         public int extraPixels;
         @ViewDebug.ExportedProperty(category = "layout")
         public boolean expandable;
+        @ViewDebug.ExportedProperty(category = "layout")
+        public boolean preventEdgeOffset;
 
         public boolean expanded;