Introducing the split action bar.

Apply (or extend) the theme Theme.Holo.SplitActionBarWhenNarrow or
Theme.Holo.Light.SplitActionBarWhenNarrow to enable splitting the
action bar across both the top and bottom of the screen. This places
the action menu along the bottom, leaving more room at the top for
titles, navigation, and custom views and more room at the bottom for
menu items.

TODO: Refine layout of the action menu when placed at the bottom of
the screen. Make action modes split as well.

Change-Id: I92c91f99c533f26aecf6b828ed041386c4f16922
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f5849c2..02b6619 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2482,6 +2482,7 @@
                 break;
 
             case Window.FEATURE_ACTION_BAR:
+                initActionBar();
                 mActionBar.dispatchMenuVisibilityChanged(false);
                 break;
         }
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index dccfa6c..57df259 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -71,7 +71,7 @@
     private ActionBarContainer mContainerView;
     private ActionBarView mActionView;
     private ActionBarContextView mUpperContextView;
-    private LinearLayout mLowerContextView;
+    private LinearLayout mLowerView;
     private View mContentView;
     private ViewGroup mExternalTabView;
 
@@ -106,8 +106,8 @@
             new AnimatorListenerAdapter() { // NORMAL_VIEW
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    if (mLowerContextView != null) {
-                        mLowerContextView.removeAllViews();
+                    if (mLowerView != null) {
+                        mLowerView.removeAllViews();
                     }
                     mCurrentModeAnim = null;
                     hideAllExcept(NORMAL_VIEW);
@@ -162,7 +162,7 @@
         mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
         mUpperContextView = (ActionBarContextView) decor.findViewById(
                 com.android.internal.R.id.action_context_bar);
-        mLowerContextView = (LinearLayout) decor.findViewById(
+        mLowerView = (LinearLayout) decor.findViewById(
                 com.android.internal.R.id.lower_action_context_bar);
         mContainerView = (ActionBarContainer) decor.findViewById(
                 com.android.internal.R.id.action_bar_container);
@@ -173,8 +173,8 @@
         }
 
         mActionView.setContextView(mUpperContextView);
-        mContextDisplayMode = mLowerContextView == null ?
-                CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT;
+        mContextDisplayMode = mActionView.isSplitActionBar() ?
+                CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
 
         if (!mActionView.hasEmbeddedTabs()) {
             HorizontalScrollView tabScroller = new HorizontalScrollView(mContext);
@@ -348,9 +348,9 @@
             mode.invalidate();
             mUpperContextView.initForMode(mode);
             animateTo(CONTEXT_VIEW);
-            if (mLowerContextView != null) {
+            if (mLowerView != null) {
                 // TODO animate this
-                mLowerContextView.setVisibility(View.VISIBLE);
+                mLowerView.setVisibility(View.VISIBLE);
             }
             mActionMode = mode;
             return mode;
@@ -616,9 +616,9 @@
 
             // Clear out the context mode views after the animation finishes
             mUpperContextView.closeMode();
-            if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) {
+            if (mLowerView != null && mLowerView.getVisibility() != View.GONE) {
                 // TODO Animate this
-                mLowerContextView.setVisibility(View.GONE);
+                mLowerView.setVisibility(View.GONE);
             }
             mActionMode = null;
 
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index a05fa53..e210b78 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -73,10 +73,11 @@
 
         int width = mWidthLimit;
         if (mReserveOverflow) {
-            OverflowMenuButton button = new OverflowMenuButton(mContext);
-            mOverflowButton = button;
-            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-            mOverflowButton.measure(spec, spec);
+            if (mOverflowButton == null) {
+                mOverflowButton = new OverflowMenuButton(mContext);
+                final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+                mOverflowButton.measure(spec, spec);
+            }
             width -= mOverflowButton.getMeasuredWidth();
         } else {
             mOverflowButton = null;
@@ -88,6 +89,17 @@
         mScrapActionButtonView = null;
     }
 
+    public void setWidthLimit(int width) {
+        if (mReserveOverflow) {
+            width -= mOverflowButton.getMeasuredWidth();
+        }
+        mActionItemWidthLimit = width;
+    }
+
+    public void setItemLimit(int itemCount) {
+        mMaxItems = itemCount;
+    }
+
     @Override
     public MenuView getMenuView(ViewGroup root) {
         MenuView result = super.getMenuView(root);
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index a572e11..0c13f7b 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -110,7 +110,7 @@
     private int mProgressStyle;
     private int mIndeterminateProgressStyle;
 
-    private boolean mShowMenu;
+    private boolean mSplitActionBar;
     private boolean mUserTitle;
     private boolean mIncludeTabs;
 
@@ -119,6 +119,7 @@
     private ActionMenuPresenter mActionMenuPresenter;
     
     private ActionBarContextView mContextView;
+    private ViewGroup mSplitView;
 
     private ActionMenuItem mLogoNavItem;
 
@@ -245,6 +246,26 @@
         addView(mIndeterminateProgressView);
     }
 
+    public void setSplitActionBar(boolean splitActionBar) {
+        if (mSplitActionBar != splitActionBar) {
+            if (mMenuView != null) {
+                if (splitActionBar) {
+                    removeView(mMenuView);
+                    if (mSplitView != null) {
+                        mSplitView.addView(mMenuView);
+                    }
+                } else {
+                    addView(mMenuView);
+                }
+            }
+            mSplitActionBar = splitActionBar;
+        }
+    }
+
+    public boolean isSplitActionBar() {
+        return mSplitActionBar;
+    }
+
     public boolean hasEmbeddedTabs() {
         return mIncludeTabs;
     }
@@ -284,10 +305,29 @@
         final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
                 LayoutParams.MATCH_PARENT);
         menuView.setLayoutParams(layoutParams);
-        addView(menuView);
+        if (!mSplitActionBar) {
+            addView(menuView);
+        } else {
+            // Allow full screen width in split mode.
+            mActionMenuPresenter.setWidthLimit(
+                    getContext().getResources().getDisplayMetrics().widthPixels);
+            // No limit to the item count; use whatever will fit.
+            mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+            if (mSplitView != null) {
+                mSplitView.addView(menuView);
+            } // We'll add this later if we missed it this time.
+        }
         mMenuView = menuView;
     }
 
+    public void setSplitView(ViewGroup splitView) {
+        mSplitView = splitView;
+        splitView.setVisibility(VISIBLE);
+        if (mMenuView != null) {
+            splitView.addView(mMenuView);
+        }
+    }
+
     public boolean showOverflowMenu() {
         if (mActionMenuPresenter != null) {
             return mActionMenuPresenter.showOverflowMenu();
@@ -718,7 +758,7 @@
             leftOfCenter -= homeWidth;
         }
         
-        if (mMenuView != null) {
+        if (mMenuView != null && mMenuView.getParent() == this) {
             availableWidth = measureChildView(mMenuView, availableWidth,
                     childSpecHeight, 0);
             rightOfCenter -= mMenuView.getMeasuredWidth();
@@ -880,7 +920,7 @@
         }
 
         int menuLeft = r - l - getPaddingRight();
-        if (mMenuView != null) {
+        if (mMenuView != null && mMenuView.getParent() == this) {
             positionChildInverse(mMenuView, menuLeft, y, contentHeight);
             menuLeft -= mMenuView.getMeasuredWidth();
         }
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index 70af265..14af446 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -47,5 +47,6 @@
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   style="?android:attr/actionBarStyle"
-                  android:visibility="gone" />
+                  android:visibility="gone"
+                  android:gravity="center"/>
 </LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar_overlay.xml b/core/res/res/layout/screen_action_bar_overlay.xml
index cfa335e..aebbe41 100644
--- a/core/res/res/layout/screen_action_bar_overlay.xml
+++ b/core/res/res/layout/screen_action_bar_overlay.xml
@@ -51,5 +51,6 @@
                   android:layout_height="wrap_content"
                   android:layout_alignParentBottom="true"
                   style="?android:attr/actionBarStyle"
-                  android:visibility="gone" />
+                  android:visibility="gone"
+                  android:gravity="center"/>
 </RelativeLayout>
diff --git a/core/res/res/values-w480dp/bools.xml b/core/res/res/values-w480dp/bools.xml
index c202d90..8206e79 100644
--- a/core/res/res/values-w480dp/bools.xml
+++ b/core/res/res/values-w480dp/bools.xml
@@ -19,4 +19,5 @@
 <resources>
     <bool name="allow_action_menu_item_text_with_icon">true</bool>
     <bool name="action_bar_embed_tabs">true</bool>
+    <bool name="split_action_bar_is_narrow">false</bool>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3a44e4f..dac3bd2 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -299,6 +299,10 @@
              when there is not reserved space for their UI (such as an Action Bar). -->
         <attr name="windowActionModeOverlay" format="boolean" />
 
+        <!-- Flag indicating that the action bar should be split to provide more
+             room for elements. -->
+        <attr name="windowSplitActionBar" format="boolean" />
+
         <!-- Defines the default soft input state that this window would
              like when it is displayed. -->
         <attr name="windowSoftInputMode">
@@ -1429,6 +1433,7 @@
         <attr name="windowActionBar" />
         <attr name="windowActionModeOverlay" />
         <attr name="windowActionBarOverlay" />
+        <attr name="windowSplitActionBar" />
         <attr name="windowEnableSplitTouch" />
         <attr name="windowCloseOnTouchOutside" />
         <!-- The minimum width the window is allowed to be, along the major
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 6eb006f..8e27be4 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -19,4 +19,5 @@
 <resources>
     <bool name="allow_action_menu_item_text_with_icon">false</bool>
     <bool name="action_bar_embed_tabs">false</bool>
+    <bool name="split_action_bar_is_narrow">true</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 501d478..7ca5e98 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1660,6 +1660,8 @@
 
   <public type="style" name="Theme.Holo.Light.NoActionBar" />
   <public type="style" name="TextAppearance.SuggestionHighlight" />
+  <public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
+  <public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
 
   <public type="attr" name="textSuggestionsWindowStyle" />
   <public type="attr" name="textEditSuggestionsBottomWindowLayout" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index be7b42f..cdfdd11 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -1538,4 +1538,17 @@
         <item name="android:windowNoTitle">true</item>
     </style>
 
+    <!-- Variant of the holographic (dark) theme with an action bar that
+         splits across the top and bottom of the activity when constrained
+         for horizontal space. -->
+    <style name="Theme.Holo.SplitActionBarWhenNarrow">
+        <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
+    </style>
+
+    <!-- Variant of the holographic (light) theme with an action bar that
+         splits across the top and bottom of the activity when constrained
+         for horizontal space. -->
+    <style name="Theme.Holo.Light.SplitActionBarWhenNarrow">
+        <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
+    </style>
 </resources>