Revisiting ActionBar API and layout.

Fix several bugs where ActionBar was ignoring LayoutParams in action
views.

Add convenience methods for toggling display options flags.

Add layout resource version of ActionBar#setCustomView

Fix a bug preventing actionViewClasses from being loaded properly in
menu xml.

Change-Id: I0d9a0b635fd9cfc020bac69369c0c7749c226349
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 67eb02d..8d5a6da 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -154,6 +154,25 @@
     public abstract void setCustomView(View view, LayoutParams layoutParams);
 
     /**
+     * Set the action bar into custom navigation mode, supplying a view
+     * for custom navigation.
+     *
+     * <p>Custom navigation views appear between the application icon and
+     * any action buttons and may use any space available there. Common
+     * use cases for custom navigation views might include an auto-suggesting
+     * address bar for a browser or other navigation mechanisms that do not
+     * translate well to provided navigation modes.</p>
+     *
+     * <p>The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for
+     * the custom view to be displayed.</p>
+     *
+     * @param resId Resource ID of a layout to inflate into the ActionBar.
+     *
+     * @see #setDisplayOptions(int, int)
+     */
+    public abstract void setCustomView(int resId);
+
+    /**
      * @param view
      * @deprecated Use {@link #setCustomView(View)} and {@link #setDisplayOptions(int)} instead.
      */
@@ -319,7 +338,72 @@
      * @param mask A bit mask declaring which display options should be changed.
      */
     public abstract void setDisplayOptions(int options, int mask);
-    
+
+    /**
+     * Set whether to display the activity logo rather than the activity icon.
+     * A logo is often a wider, more detailed image.
+     *
+     * <p>To set several display options at once, see the setDisplayOptions methods.
+     *
+     * @param useLogo true to use the activity logo, false to use the activity icon.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public abstract void setDisplayUseLogoEnabled(boolean useLogo);
+
+    /**
+     * Set whether to include the application home affordance in the action bar.
+     * Home is presented as either an activity icon or logo.
+     *
+     * <p>To set several display options at once, see the setDisplayOptions methods.
+     *
+     * @param showHome true to show home, false otherwise.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public abstract void setDisplayShowHomeEnabled(boolean showHome);
+
+    /**
+     * Set whether home should be displayed as an "up" affordance.
+     * Set this to true if selecting "home" returns up by a single level in your UI
+     * rather than back to the top level or front page.
+     *
+     * <p>To set several display options at once, see the setDisplayOptions methods.
+     *
+     * @param showHomeAsUp true to show the user that selecting home will return one
+     *                     level up rather than to the top level of the app.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public abstract void setDisplayHomeAsUpEnabled(boolean showHomeAsUp);
+
+    /**
+     * Set whether an activity title/subtitle should be displayed.
+     *
+     * <p>To set several display options at once, see the setDisplayOptions methods.
+     *
+     * @param showTitle true to display a title/subtitle if present.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public abstract void setDisplayShowTitleEnabled(boolean showTitle);
+
+    /**
+     * Set whether a custom view should be displayed, if set.
+     *
+     * <p>To set several display options at once, see the setDisplayOptions methods.
+     *
+     * @param showCustom true if the currently set custom view should be displayed, false otherwise.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public abstract void setDisplayShowCustomEnabled(boolean showCustom);
+
     /**
      * Set the ActionBar's background.
      * 
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index 7d5dcd8..ab515c9 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -379,15 +379,15 @@
 
             if (itemActionViewClassName != null) {
                 try {
-                    final Class<?> clazz = Class.forName(itemActionViewClassName);
+                    final Class<?> clazz = Class.forName(itemActionViewClassName, true,
+                            mContext.getClassLoader());
                     Constructor<?> c = clazz.getConstructor(ACTION_VIEW_CONSTRUCTOR_SIGNATURE);
                     item.setActionView((View) c.newInstance(mContext));
                 } catch (Exception e) {
                     throw new InflateException(e);
                 }
             } else if (itemActionViewLayout > 0) {
-                final LayoutInflater inflater = LayoutInflater.from(mContext);
-                item.setActionView(inflater.inflate(itemActionViewLayout, null));
+                item.setActionView(itemActionViewLayout);
             }
         }
         
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 602c765..780c52e 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -433,6 +433,18 @@
     public MenuItem setActionView(View view);
 
     /**
+     * Set an action view for this menu item. An action view will be displayed in place
+     * of an automatically generated menu item element in the UI when this item is shown
+     * as an action within a parent.
+     *
+     * @param resId Layout resource to use for presenting this item to the user.
+     * @return This Item so additional setters can be called.
+     *
+     * @see #setShowAsAction(int)
+     */
+    public MenuItem setActionView(int resId);
+
+    /**
      * Returns the currently set action view for this menu item.
      *
      * @return This item's action view
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 633bdd3..f5c0124 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -238,6 +238,36 @@
     }
 
     @Override
+    public void setCustomView(int resId) {
+        setCustomView(LayoutInflater.from(mContext).inflate(resId, mActionView, false));
+    }
+
+    @Override
+    public void setDisplayUseLogoEnabled(boolean useLogo) {
+        setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
+    }
+
+    @Override
+    public void setDisplayShowHomeEnabled(boolean showHome) {
+        setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
+    }
+
+    @Override
+    public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
+        setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
+    }
+
+    @Override
+    public void setDisplayShowTitleEnabled(boolean showTitle) {
+        setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
+    }
+
+    @Override
+    public void setDisplayShowCustomEnabled(boolean showCustom) {
+        setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
+    }
+
+    @Override
     public void setTitle(int resId) {
         setTitle(mContext.getString(resId));
     }
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index d2851a9..0ef4861 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -231,4 +231,9 @@
     public View getActionView() {
         return null;
     }
+
+    @Override
+    public MenuItem setActionView(int resId) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 871973d..96c1ed3 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -22,6 +22,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
@@ -156,6 +157,13 @@
     
     @Override
     protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        if (p instanceof LayoutParams) {
+            LayoutParams result = new LayoutParams((LayoutParams) p);
+            if (result.gravity <= Gravity.NO_GRAVITY) {
+                result.gravity = Gravity.CENTER_VERTICAL;
+            }
+            return result;
+        }
         return generateDefaultLayoutParams();
     }
 
@@ -186,13 +194,25 @@
                 addView(makeDividerView(), makeDividerLayoutParams());
             }
             final MenuItemImpl itemData = itemsToShow.get(i);
-            final View actionView = itemData.getActionView();
+            View actionView = itemData.getActionView();
+
+            if (actionView == null) {
+                // Check for a layout ID instead
+                final int layoutId = itemData.getActionViewId();
+                if (layoutId != 0) {
+                    LayoutInflater inflater = LayoutInflater.from(getContext());
+                    actionView = inflater.inflate(layoutId, this, false);
+                    itemData.setActionView(0);
+                    itemData.setActionView(actionView);
+                }
+            }
+
             if (actionView != null) {
                 final ViewParent parent = actionView.getParent();
                 if (parent instanceof ViewGroup) {
                     ((ViewGroup) parent).removeView(actionView);
                 }
-                addView(actionView, makeActionViewLayoutParams());
+                addView(actionView, makeActionViewLayoutParams(actionView));
             } else {
                 needsDivider = addItemView(i == 0 || !needsDivider,
                         (ActionMenuItemView) itemData.getItemView(
@@ -274,8 +294,8 @@
         return params;
     }
 
-    private LayoutParams makeActionViewLayoutParams() {
-        LayoutParams params = generateDefaultLayoutParams();
+    private LayoutParams makeActionViewLayoutParams(View view) {
+        LayoutParams params = generateLayoutParams(view.getLayoutParams());
         params.leftMargin = (int) mButtonPaddingLeft;
         params.rightMargin = (int) mButtonPaddingRight;
         return params;
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 8eee360..9faffe5 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -83,6 +83,7 @@
     private int mShowAsAction = SHOW_AS_ACTION_NEVER;
 
     private View mActionView;
+    private int mActionViewId;
 
     /** Used for the icon resource ID if this item does not have an icon */
     static final int NO_ICON = 0;
@@ -694,7 +695,16 @@
         return this;
     }
 
+    public MenuItem setActionView(int resId) {
+        mActionViewId = resId;
+        return this;
+    }
+
     public View getActionView() {
         return mActionView;
     }
+
+    public int getActionViewId() {
+        return mActionViewId;
+    }
 }