Bug 878929: Optimize custom menu's list view. [r=mfinkle] [r=wesj]
authorSriram Ramasubramanian <sriram@mozilla.com>
Wed, 05 Jun 2013 15:28:02 -0700
changeset 134568 98539fbbbf390fd3c985abe8f26b6893abee47ce
parent 134567 4a854c013d42478b46362a5b4d110016fe53264f
child 134569 9619f1a5d3c2e7da2c9a5226419dc6768f6c8f38
push id29274
push usersramasubramanian@mozilla.com
push dateMon, 10 Jun 2013 21:53:39 +0000
treeherdermozilla-inbound@9619f1a5d3c2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle, wesj
bugs878929
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 878929: Optimize custom menu's list view. [r=mfinkle] [r=wesj]
mobile/android/base/BrowserToolbar.java
mobile/android/base/GeckoViewsFactory.java
mobile/android/base/Makefile.in
mobile/android/base/menu/GeckoMenu.java
mobile/android/base/menu/GeckoMenuItem.java
mobile/android/base/menu/GeckoSubMenu.java
mobile/android/base/menu/MenuItemActionBar.java
mobile/android/base/menu/MenuItemActionView.java
mobile/android/base/menu/MenuItemDefault.java
mobile/android/base/resources/color/menu_item_title.xml
mobile/android/base/resources/layout/menu_action_bar.xml
mobile/android/base/resources/layout/menu_item_action_view.xml
mobile/android/base/resources/values-v11/themes.xml
mobile/android/base/resources/values/attrs.xml
mobile/android/base/resources/values/styles.xml
mobile/android/base/widget/GeckoActionProvider.java
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -97,18 +97,16 @@ public class BrowserToolbar implements T
 
     final private BrowserApp mActivity;
     private Handler mHandler;
     private boolean mHasSoftMenuButton;
 
     private boolean mShowSiteSecurity;
     private boolean mShowReader;
 
-    private static List<View> sActionItems;
-
     private boolean mAnimatingEntry;
 
     private AlphaAnimation mLockFadeIn;
     private TranslateAnimation mTitleSlideLeft;
     private TranslateAnimation mTitleSlideRight;
 
     private int mAddressBarViewOffset;
     private int mDefaultForwardMargin;
@@ -130,17 +128,16 @@ public class BrowserToolbar implements T
     private boolean mShowUrl;
 
     private Integer mPrefObserverId;
 
     public BrowserToolbar(BrowserApp activity) {
         // BrowserToolbar is attached to BrowserApp only.
         mActivity = activity;
 
-        sActionItems = new ArrayList<View>();
         Tabs.registerOnTabsChangedListener(this);
         mSwitchingTabs = true;
 
         mAnimatingEntry = false;
         mShowUrl = false;
 
         // listen to the title bar pref.
         mPrefObserverId = PrefsHelper.getPref(PREF_TITLEBAR_MODE, new PrefsHelper.PrefHandlerBase() {
@@ -1109,30 +1106,21 @@ public class BrowserToolbar implements T
                       PropertyAnimator.Property.TRANSLATION_X,
                       mAddressBarViewOffset);
         }
     }
 
     @Override
     public void addActionItem(View actionItem) {
         mActionItemBar.addView(actionItem);
-
-        if (!sActionItems.contains(actionItem))
-            sActionItems.add(actionItem);
     }
 
     @Override
-    public void removeActionItem(int index) {
-        mActionItemBar.removeViewAt(index);
-        sActionItems.remove(index);
-    }
-
-    @Override
-    public int getActionItemsCount() {
-        return sActionItems.size();
+    public void removeActionItem(View actionItem) {
+        mActionItemBar.removeView(actionItem);
     }
 
     public void show() {
         mLayout.setVisibility(View.VISIBLE);
     }
 
     public void hide() {
         mLayout.setVisibility(View.GONE);
--- a/mobile/android/base/GeckoViewsFactory.java
+++ b/mobile/android/base/GeckoViewsFactory.java
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.gfx.LayerView;
+import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.MenuItemActionBar;
 import org.mozilla.gecko.menu.MenuItemDefault;
 import org.mozilla.gecko.widget.AboutHomeView;
 import org.mozilla.gecko.widget.AddonsSection;
 import org.mozilla.gecko.widget.FaviconView;
 import org.mozilla.gecko.widget.IconTabWidget;
 import org.mozilla.gecko.widget.LastTabsSection;
 import org.mozilla.gecko.widget.LinkTextView;
@@ -61,16 +62,17 @@ public final class GeckoViewsFactory imp
             mFactoryMap.put("BrowserToolbarBackground", BrowserToolbarBackground.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("CheckableLinearLayout", CheckableLinearLayout.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("FormAssistPopup", FormAssistPopup.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("ForwardButton", ForwardButton.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("GeckoApp$MainLayout", GeckoApp.MainLayout.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("LinkTextView", LinkTextView.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("MenuItemActionBar", MenuItemActionBar.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("MenuItemDefault", MenuItemDefault.class.getConstructor(arg1Class, arg2Class));
+            mFactoryMap.put("GeckoMenu$DefaultActionItemBar", GeckoMenu.DefaultActionItemBar.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("FindInPageBar", FindInPageBar.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("IconTabWidget", IconTabWidget.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("RemoteTabs", RemoteTabs.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("ShapedButton", ShapedButton.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("TabRow", TabRow.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("TabsPanel", TabsPanel.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("TabsPanel$TabsListContainer", TabsPanel.TabsListContainer.class.getConstructor(arg1Class, arg2Class));
             mFactoryMap.put("TabsPanel$TabsPanelToolbar", TabsPanel.TabsPanelToolbar.class.getConstructor(arg1Class, arg2Class));
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -1000,17 +1000,16 @@ RES_DRAWABLE_XLARGE_XHDPI_V11 = \
   $(NULL)
 
 RES_COLOR = \
   res/color/abouthome_section_more_text.xml \
   res/color/abouthome_section_subtitle.xml \
   res/color/abouthome_section_title.xml \
   res/color/awesome_bar_title.xml \
   res/color/awesome_bar_title_hint.xml \
-  res/color/menu_item_title.xml \
   res/color/primary_text.xml \
   res/color/primary_text_inverse.xml \
   res/color/secondary_text.xml \
   res/color/secondary_text_inverse.xml \
   res/color/select_item_multichoice.xml \
   res/color/tertiary_text.xml \
   res/color/tertiary_text_inverse.xml \
   $(NULL)
--- a/mobile/android/base/menu/GeckoMenu.java
+++ b/mobile/android/base/menu/GeckoMenu.java
@@ -1,16 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.menu;
 
 import org.mozilla.gecko.R;
-import org.mozilla.gecko.widget.Divider;
 
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.util.AttributeSet;
 import android.view.ActionProvider;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -20,28 +19,26 @@ import android.view.SubMenu;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class GeckoMenu extends ListView 
                        implements Menu,
-                                  MenuItem.OnMenuItemClickListener,
                                   AdapterView.OnItemClickListener,
-                                  GeckoMenuItem.OnVisibilityChangedListener,
                                   GeckoMenuItem.OnShowAsActionChangedListener {
     private static final String LOGTAG = "GeckoMenu";
 
-    private Context mContext;
-
     /*
      * A callback for a menu item selected event.
      */
     public static interface Callback {
         // Called when a menu item is selected, with the actual menu item as the argument.
         public boolean onMenuItemSelected(MenuItem item);
     }
 
@@ -60,203 +57,192 @@ public class GeckoMenu extends ListView
         // Close the menu.
         public void closeMenu();
     }
 
     /*
      * An interface for a presenter of action-items.
      * Either an Activity or a View can be a presenter, that can watch for events
      * and add/remove action-items. If not ActionItemBarPresenter, the menu uses a 
-     * DefaultActionItemBarPresenter, that shows the action-items as a header over list-view.
+     * DefaultActionItemBar, that shows the action-items as a header over list-view.
      */
     public static interface ActionItemBarPresenter {
         // Add an action-item.
         public void addActionItem(View actionItem);
 
-        // Remove an action-item based on the index. The index used while adding.
-        public void removeActionItem(int index);
-
-        // Get the number of action-items shown by the presenter.
-        public int getActionItemsCount();
+        // Remove an action-item.
+        public void removeActionItem(View actionItem);
     }
 
     protected static final int NO_ID = 0;
 
     // List of all menu items.
     private List<GeckoMenuItem> mItems;
 
-    // List of items in action-bar.
-    private List<GeckoMenuItem> mActionItems;
+    // Map of items in action-bar and their views.
+    private Map<GeckoMenuItem, View> mActionItems;
 
     // Reference to a callback for menu events.
     private Callback mCallback;
 
     // Reference to menu presenter.
     private MenuPresenter mMenuPresenter;
 
     // Reference to action-items bar in action-bar.
     private ActionItemBarPresenter mActionItemBarPresenter;
 
     // Adapter to hold the list of menu items.
     private MenuItemsAdapter mAdapter;
 
-    // ActionBar to show the menu items as icons.
-    private LinearLayout mActionBar;
+    public GeckoMenu(Context context) {
+        this(context, null);
+    }
 
     public GeckoMenu(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mContext = context;
+        this(context, attrs, android.R.attr.listViewStyle);
+    }
+
+    public GeckoMenu(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
 
         setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
                                          LayoutParams.FILL_PARENT));
 
-        // Add a header view that acts as an action-bar.
-        mActionBar = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.menu_action_bar, null);
-
         // Attach an adapter.
         mAdapter = new MenuItemsAdapter(context);
         setAdapter(mAdapter);
         setOnItemClickListener(this);
 
         mItems = new ArrayList<GeckoMenuItem>();
-        mActionItems = new ArrayList<GeckoMenuItem>();
+        mActionItems = new HashMap<GeckoMenuItem, View>();
 
-        mActionItemBarPresenter = new DefaultActionItemBarPresenter(mContext, mActionBar);
+        mActionItemBarPresenter =  (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_action_bar, null);
     }
 
     @Override
     public MenuItem add(CharSequence title) {
-        GeckoMenuItem menuItem = new GeckoMenuItem(mContext, NO_ID);
-        menuItem.setTitle(title);
+        GeckoMenuItem menuItem = new GeckoMenuItem(this, NO_ID, 0, title);
         addItem(menuItem);
         return menuItem;
     }
 
     @Override
     public MenuItem add(int groupId, int itemId, int order, int titleRes) {
-        GeckoMenuItem menuItem = new GeckoMenuItem(mContext, itemId, order);
-        menuItem.setTitle(titleRes);
+        GeckoMenuItem menuItem = new GeckoMenuItem(this, itemId, order, titleRes);
         addItem(menuItem);
         return menuItem;
     }
 
     @Override
     public MenuItem add(int titleRes) {
-        GeckoMenuItem menuItem = new GeckoMenuItem(mContext, NO_ID);
-        menuItem.setTitle(titleRes);
+        GeckoMenuItem menuItem = new GeckoMenuItem(this, NO_ID, 0, titleRes);
         addItem(menuItem);
         return menuItem;
     }
 
     @Override
     public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
-        GeckoMenuItem menuItem = new GeckoMenuItem(mContext, itemId, order);
-        menuItem.setTitle(title);
+        GeckoMenuItem menuItem = new GeckoMenuItem(this, itemId, order, title);
         addItem(menuItem);
         return menuItem;
     }
 
     private void addItem(GeckoMenuItem menuItem) {
-        menuItem.setMenu(this);
         menuItem.setOnShowAsActionChangedListener(this);
-        menuItem.setOnVisibilityChangedListener(this);
-        menuItem.setOnMenuItemClickListener(this);
         mAdapter.addMenuItem(menuItem);
         mItems.add(menuItem);
     }
 
-    private void addActionItem(GeckoMenuItem menuItem) {
-        menuItem.setMenu(this);
+    private void addActionItem(final GeckoMenuItem menuItem) {
         menuItem.setOnShowAsActionChangedListener(this);
-        menuItem.setOnVisibilityChangedListener(null);
-        menuItem.setOnMenuItemClickListener(this);
 
         if (mActionItems.size() == 0 && 
-            mActionItemBarPresenter instanceof DefaultActionItemBarPresenter) {
+            mActionItemBarPresenter instanceof DefaultActionItemBar) {
             // Reset the adapter before adding the header view to a list.
             setAdapter(null);
-            addHeaderView(mActionBar);
+            addHeaderView((DefaultActionItemBar) mActionItemBarPresenter);
             setAdapter(mAdapter);
         }
 
-        mActionItems.add(menuItem);
-        mActionItemBarPresenter.addActionItem(menuItem.getLayout());
+        View actionView = menuItem.getActionView();
+        actionView.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                handleMenuItemClick(menuItem);
+            }
+        });
+
+        mActionItems.put(menuItem, actionView);
+        mActionItemBarPresenter.addActionItem(actionView);
         mItems.add(menuItem);
     }
 
     @Override
     public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
         return 0;
     }
 
     @Override
     public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
         MenuItem menuItem = add(groupId, itemId, order, title);
-        GeckoSubMenu subMenu = new GeckoSubMenu(mContext, null);
-        subMenu.setMenuItem(menuItem);
-        subMenu.setCallback(mCallback);
-        subMenu.setMenuPresenter(mMenuPresenter);
-        ((GeckoMenuItem) menuItem).setSubMenu(subMenu);
-        return subMenu;
+        return addSubMenu(menuItem);
     }
 
     @Override
     public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
         MenuItem menuItem = add(groupId, itemId, order, titleRes);
-        GeckoSubMenu subMenu = new GeckoSubMenu(mContext, null);
-        subMenu.setMenuItem(menuItem);
-        subMenu.setCallback(mCallback);
-        subMenu.setMenuPresenter(mMenuPresenter);
-        ((GeckoMenuItem) menuItem).setSubMenu(subMenu);
-        return subMenu;
+        return addSubMenu(menuItem);
     }
 
     @Override
     public SubMenu addSubMenu(CharSequence title) {
         MenuItem menuItem = add(title);
-        GeckoSubMenu subMenu = new GeckoSubMenu(mContext, null);
-        subMenu.setMenuItem(menuItem);
-        subMenu.setCallback(mCallback);
-        subMenu.setMenuPresenter(mMenuPresenter);
-        ((GeckoMenuItem) menuItem).setSubMenu(subMenu);
-        return subMenu;
+        return addSubMenu(menuItem);
     }
 
     @Override
     public SubMenu addSubMenu(int titleRes) {
         MenuItem menuItem = add(titleRes);
-        GeckoSubMenu subMenu = new GeckoSubMenu(mContext, null);
+        return addSubMenu(menuItem);
+    }
+
+    private SubMenu addSubMenu(MenuItem menuItem) {
+        GeckoSubMenu subMenu = new GeckoSubMenu(getContext());
         subMenu.setMenuItem(menuItem);
         subMenu.setCallback(mCallback);
         subMenu.setMenuPresenter(mMenuPresenter);
         ((GeckoMenuItem) menuItem).setSubMenu(subMenu);
         return subMenu;
     }
 
     @Override
     public void clear() {
         for (GeckoMenuItem menuItem : mItems) {
             if (menuItem.hasSubMenu()) {
-                SubMenu subMenu = menuItem.getSubMenu();
-                subMenu.clear();
+                menuItem.getSubMenu().clear();
             }
         }
 
         mAdapter.clear();
 
         mItems.clear();
         mActionItems.clear();
     }
 
     @Override
     public void close() {
         if (mMenuPresenter != null)
             mMenuPresenter.closeMenu();
     }
 
+    private void showMenu(View viewForMenu) {
+        if (mMenuPresenter != null)
+            mMenuPresenter.showMenu(viewForMenu);
+    }
+
     @Override
     public MenuItem findItem(int id) {
         for (GeckoMenuItem menuItem : mItems) {
             if (menuItem.getItemId() == id) {
                 return menuItem;
             } else if (menuItem.hasSubMenu()) {
                 if (menuItem.getActionProvider() == null) {
                     SubMenu subMenu = menuItem.getSubMenu();
@@ -304,38 +290,39 @@ public class GeckoMenu extends ListView
 
     @Override
     public void removeGroup(int groupId) {
     }
 
     @Override
     public void removeItem(int id) {
         GeckoMenuItem item = (GeckoMenuItem) findItem(id);
-        if (item != null) {
-            if (mActionItems.contains(item)) {
-                if (mActionItemBarPresenter != null)
-                    mActionItemBarPresenter.removeActionItem(mActionItems.indexOf(item));
+        if (item == null)
+            return;
 
-                mActionItems.remove(item);
-                mItems.remove(item);
+        if (mActionItems.containsKey(item)) {
+            if (mActionItemBarPresenter != null)
+                mActionItemBarPresenter.removeActionItem(mActionItems.get(item));
 
-                if (mActionItems.size() == 0 && 
-                    mActionItemBarPresenter instanceof DefaultActionItemBarPresenter) {
-                    // Reset the adapter before removing the header view from a list.
-                    setAdapter(null);
-                    removeHeaderView(mActionBar);
-                    setAdapter(mAdapter);
-                }
+            mActionItems.remove(item);
+            mItems.remove(item);
 
-                return;
+            if (mActionItems.size() == 0 && 
+                mActionItemBarPresenter instanceof DefaultActionItemBar) {
+                // Reset the adapter before removing the header view from a list.
+                setAdapter(null);
+                removeHeaderView((DefaultActionItemBar) mActionItemBarPresenter);
+                setAdapter(mAdapter);
             }
 
-            mAdapter.removeMenuItem(item);
-            mItems.remove(item);
+            return;
         }
+
+        mAdapter.removeMenuItem(item);
+        mItems.remove(item);
     }
 
     @Override
     public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
     }
 
     @Override
     public void setGroupEnabled(int group, boolean enabled) {
@@ -364,63 +351,73 @@ public class GeckoMenu extends ListView
         removeItem(item.getItemId());
 
         if (isActionItem)
             addActionItem(item);
         else
             addItem(item);
     }
 
-    @Override
-    public void onVisibilityChanged(GeckoMenuItem item, boolean isVisible) {
-        if (isVisible)
-            mAdapter.addMenuItem(item);
-        else
-            mAdapter.removeMenuItem(item);
+    public void onItemChanged(GeckoMenuItem item) {
+        if (item.isActionItem()) {
+           final MenuItemActionBar actionView = (MenuItemActionBar) mActionItems.get(item);
+           if (actionView != null) {
+               // The update could be coming from the background thread.
+               // Post a runnable on the UI thread of the view for it to update.
+               final GeckoMenuItem menuItem = item;
+               actionView.post(new Runnable() {
+                   @Override
+                   public void run() {
+                       if (menuItem.isVisible()) {
+                           actionView.setVisibility(View.VISIBLE);
+                           actionView.initialize(menuItem);
+                       } else {
+                           actionView.setVisibility(View.GONE);
+                       }
+                   }
+               });
+           } 
+        } else {
+            mAdapter.notifyDataSetChanged();
+        }
     }
 
     @Override
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        // We might be showing headers. Account them while using the position.
         position -= getHeaderViewsCount();
+
         GeckoMenuItem item = mAdapter.getItem(position);
-        if (item.isEnabled())
-            item.onClick(item.getLayout());
+        handleMenuItemClick(item);
     }
 
-    @Override
-    public boolean onMenuItemClick(MenuItem item) {
-        if (!item.hasSubMenu()) {
-            if (mMenuPresenter != null) 
-                mMenuPresenter.closeMenu();
+    private void handleMenuItemClick(GeckoMenuItem item) {
+        if (!item.isEnabled())
+            return;
 
-            return mCallback.onMenuItemSelected(item);
-        } else {
+        if (item.invoke()) {
+            close();
+        } else if (item.hasSubMenu()) {
             // Refresh the submenu for the provider.
             ActionProvider provider = item.getActionProvider();
             if (provider != null) {
-                GeckoSubMenu subMenu = new GeckoSubMenu(mContext, null);
+                GeckoSubMenu subMenu = new GeckoSubMenu(getContext());
                 provider.onPrepareSubMenu(subMenu);
-                ((GeckoMenuItem) item).setSubMenu(subMenu);
+                item.setSubMenu(subMenu);
             }
 
             // Show the submenu.
-            if (mMenuPresenter != null)
-                mMenuPresenter.showMenu((GeckoSubMenu) item.getSubMenu());
-
-            return true;
+            GeckoSubMenu subMenu = (GeckoSubMenu) item.getSubMenu();
+            showMenu(subMenu);
+        } else {
+            close();
+            mCallback.onMenuItemSelected(item);
         }
     }
 
-    public boolean onCustomMenuItemClick(MenuItem item, MenuItem.OnMenuItemClickListener listener) {
-        if (mMenuPresenter != null)
-            mMenuPresenter.closeMenu();
-
-        return listener.onMenuItemClick(item);
-    }
-
     public Callback getCallback() {
         return mCallback;
     }
 
     public MenuPresenter getMenuPresenter() {
         return mMenuPresenter;
     }
 
@@ -449,97 +446,133 @@ public class GeckoMenu extends ListView
     }
 
     public void setActionItemBarPresenter(ActionItemBarPresenter presenter) {
         mActionItemBarPresenter = presenter;
     }
 
     // Action Items are added to the header view by default.
     // URL bar can register itself as a presenter, in case it has a different place to show them.
-    private class DefaultActionItemBarPresenter implements ActionItemBarPresenter {
-        private Context mContext;
-        private LinearLayout mContainer;
-        private List<View> mItems;
- 
-        public DefaultActionItemBarPresenter(Context context, LinearLayout container) {
-            mContext = context;
-            mContainer = container;
-            mItems = new ArrayList<View>();
+    public static class DefaultActionItemBar extends LinearLayout
+                                             implements ActionItemBarPresenter {
+        public DefaultActionItemBar(Context context) {
+            super(context);
+        }
+
+        public DefaultActionItemBar(Context context, AttributeSet attrs) {
+            super(context, attrs);
         }
 
         @Override
         public void addActionItem(View actionItem) {
             LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(actionItem.getLayoutParams());
             params.weight = 1.0f;
             actionItem.setLayoutParams(params);
-
-            if (mItems.size() > 0) {
-                Divider divider = new Divider(mContext, null);
-                divider.setOrientation(Divider.Orientation.VERTICAL);
-                divider.setBackgroundColor(0xFFD1D5DA);
-                mContainer.addView(divider);
-            }
-
-            mContainer.addView(actionItem);
-            mItems.add(actionItem);
+            addView(actionItem);
         }
 
         @Override
-        public void removeActionItem(int index) {
-            // Remove the icon and the vertical divider.
-            mContainer.removeViewAt(index * 2);
-
-            if (index != 0)
-                mContainer.removeViewAt(index * 2 - 1);
-
-            mItems.remove(index);
-
-            if (mItems.size() == 0)
-                mContainer.setVisibility(View.GONE);
-        }
-
-        @Override
-        public int getActionItemsCount() {
-            return mItems.size();
+        public void removeActionItem(View actionItem) {
+            removeView(actionItem);
         }
     }
 
     // Adapter to bind menu items to the list.
     private class MenuItemsAdapter extends BaseAdapter {
-        private Context mContext;
+        private static final int VIEW_TYPE_DEFAULT = 0;
+        private static final int VIEW_TYPE_ACTION_MODE = 1;
+
         private List<GeckoMenuItem> mItems;
 
         public MenuItemsAdapter(Context context) {
-            mContext = context;
             mItems = new ArrayList<GeckoMenuItem>();
         }
 
         @Override
         public int getCount() {
-            return (mItems == null ? 0 : mItems.size());
+            if (mItems == null)
+                return 0;
+
+            int visibleCount = 0;
+            for (GeckoMenuItem item : mItems) {
+                if (item.isVisible())
+                    visibleCount++;
+            }
+
+            return visibleCount;
         }
 
         @Override
         public GeckoMenuItem getItem(int position) {
-            return mItems.get(position);
+            for (GeckoMenuItem item : mItems) {
+                if (item.isVisible()) {
+                    position--;
+
+                    if (position < 0)
+                        return item;
+                }
+            }
+
+            return null;
         }
 
         @Override
         public long getItemId(int position) {
             return position;
         }
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            return mItems.get(position).getLayout();
+            GeckoMenuItem item = getItem(position);
+            GeckoMenuItem.Layout view = null;
+
+            // Try to re-use the view.
+            if (convertView == null && getItemViewType(position) == VIEW_TYPE_DEFAULT) {
+                view = new MenuItemDefault(parent.getContext(), null);
+            } else {
+                view = (GeckoMenuItem.Layout) convertView;
+            }
+
+            if (view == null || view instanceof MenuItemActionView) {
+                // Always get from the menu item.
+                // This will ensure that the default activity is refreshed.
+                view = (MenuItemActionView) item.getActionView();
+
+                // ListView will not perform an item click if the row has a focusable view in it.
+                // Hence, forward the click event on the menu item in the action-view to the ListView.
+                final View actionView = (View) view;
+                final int pos = position;
+                final long id = getItemId(position);
+                ((MenuItemActionView) view).setMenuItemClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        GeckoMenu listView = GeckoMenu.this;
+                        listView.performItemClick(actionView, pos + listView.getHeaderViewsCount(), id);
+                    }
+                });
+            }
+
+            // Initialize the view.
+            view.initialize(item);
+            return (View) view; 
         }
 
         @Override
-        public int getItemViewType (int position) {
-            return AdapterView.ITEM_VIEW_TYPE_IGNORE;
+        public int getItemViewType(int position) {
+            return getItem(position).getActionProvider() == null ? VIEW_TYPE_DEFAULT : VIEW_TYPE_ACTION_MODE;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 2;
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return false;
         }
 
         @Override
         public boolean areAllItemsEnabled() {
             for (GeckoMenuItem item : mItems) {
                  if (!item.isEnabled())
                      return false;
             }
--- a/mobile/android/base/menu/GeckoMenuItem.java
+++ b/mobile/android/base/menu/GeckoMenuItem.java
@@ -1,91 +1,68 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.menu;
 
 import org.mozilla.gecko.widget.GeckoActionProvider;
 
-import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.view.ActionProvider;
 import android.view.ContextMenu;
-import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.SubMenu;
 import android.view.View;
 
-public class GeckoMenuItem implements MenuItem, View.OnClickListener {
+public class GeckoMenuItem implements MenuItem {
     private static final String LOGTAG = "GeckoMenuItem";
 
+    // A View that can show a MenuItem should be able to initialize from 
+    // the properties of the MenuItem.
     public static interface Layout {
-        public void setId(int id);
-        public void setIcon(Drawable icon);
-        public void setIcon(int iconRes);
-        public void setTitle(CharSequence title);
-        public void setEnabled(boolean enabled);
-        public void setCheckable(boolean checkable);
-        public void setChecked(boolean checked);
-        public void setOnClickListener(View.OnClickListener listener);
-        public void setSubMenuIndicator(boolean hasSubMenu);
-        public void setVisibility(int visible);
-        public View getView();
+        public void initialize(GeckoMenuItem item);
     }
 
     public static interface OnShowAsActionChangedListener {
         public boolean hasActionItemBar();
         public void onShowAsActionChanged(GeckoMenuItem item, boolean isActionItem);
     }
 
-    public static interface OnVisibilityChangedListener {
-        public void onVisibilityChanged(GeckoMenuItem item, boolean isVisible);
-    }
-
-    private Context mContext;
     private int mId;
     private int mOrder;
-    private Layout mLayout;
-    private boolean mActionItem;
+    private View mActionView;
+    private boolean mActionItem = false;
     private CharSequence mTitle;
     private CharSequence mTitleCondensed;
-    private boolean mCheckable;
-    private boolean mChecked;
-    private boolean mVisible;
-    private boolean mEnabled;
+    private boolean mCheckable = false;
+    private boolean mChecked = false;
+    private boolean mVisible = true;
+    private boolean mEnabled = true;
     private Drawable mIcon;
     private int mIconRes;
     private ActionProvider mActionProvider;
     private GeckoMenu mMenu;
     private GeckoSubMenu mSubMenu;
-    private MenuItem.OnMenuItemClickListener mMenuItemClickListener;
-    private OnVisibilityChangedListener mVisibilityChangedListener;
+    private MenuItem.OnMenuItemClickListener mMenuItemClickListener = null;
     private OnShowAsActionChangedListener mShowAsActionChangedListener;
 
-    public GeckoMenuItem(Context context, int id) {
-        mContext = context;
-        mLayout = new MenuItemDefault(context, null);
-        mLayout.setId(id);
-
+    public GeckoMenuItem(GeckoMenu menu, int id, int order, int titleRes) {
+        mMenu = menu;
         mId = id;
-        mOrder = 0;
-        mActionItem = false;
-        mVisible = true;
-        mEnabled = true;
-        mCheckable = true;
-        mChecked = false;
-        mMenuItemClickListener = null;
+        mOrder = order;
+        setTitle(titleRes);
     }
 
-    public GeckoMenuItem(Context context, int id, int order) {
-        this(context, id);
+    public GeckoMenuItem(GeckoMenu menu, int id, int order, CharSequence title) {
+        mMenu = menu;
+        mId = id;
         mOrder = order;
+        setTitle(title);
     }
 
     @Override
     public boolean collapseActionView() {
         return false;
     }
 
     @Override
@@ -96,39 +73,37 @@ public class GeckoMenuItem implements Me
     @Override
     public ActionProvider getActionProvider() {
         return mActionProvider;
     }
 
     @Override
     public View getActionView() {
         if (mActionProvider != null && mActionProvider instanceof GeckoActionProvider) {
-            final View view = ((GeckoActionProvider) mActionProvider).getView(this);
-            view.setOnClickListener(this);
-            return view;
+            return ((GeckoActionProvider) mActionProvider).getView();
         }
 
-        return null;
+        return mActionView;
     }
 
     @Override
     public char getAlphabeticShortcut() {
         return 0;
     }
 
     @Override
     public int getGroupId() {
         return 0;
     }
 
     @Override
     public Drawable getIcon() {
         if (mIcon == null) {
             if (mIconRes != 0)
-                return mContext.getResources().getDrawable(mIconRes);
+                return mMenu.getResources().getDrawable(mIconRes);
             else
                 return null;
         } else {
             return mIcon;
         }
     }
 
     @Override
@@ -136,27 +111,16 @@ public class GeckoMenuItem implements Me
         return null;
     }
 
     @Override
     public int getItemId() {
         return mId;
     }
 
-    public View getLayout() {
-        if (mActionProvider != null)
-            return getActionView();
-
-        return mLayout.getView();
-    }
-
-    public void setMenu(GeckoMenu menu) {
-        mMenu = menu;
-    }
-
     @Override
     public ContextMenu.ContextMenuInfo getMenuInfo() {
         return null;
     }
 
     @Override
     public char getNumericShortcut() {
         return 0;
@@ -185,16 +149,20 @@ public class GeckoMenuItem implements Me
     @Override
     public boolean hasSubMenu() {
         if (mActionProvider != null)
             return mActionProvider.hasSubMenu();
 
         return (mSubMenu != null);
     }
 
+    public boolean isActionItem() {
+        return mActionItem;
+    }
+
     @Override
     public boolean isActionViewExpanded() {
         return false;
     }
 
     @Override
     public boolean isCheckable() {
         return mCheckable;
@@ -244,45 +212,45 @@ public class GeckoMenuItem implements Me
     @Override
     public MenuItem setAlphabeticShortcut(char alphaChar) {
         return this;
     }
 
     @Override
     public MenuItem setCheckable(boolean checkable) {
         mCheckable = checkable;
-        mLayout.setCheckable(checkable);
+        mMenu.onItemChanged(this);
         return this;
     }
 
     @Override
     public MenuItem setChecked(boolean checked) {
         mChecked = checked;
-        mLayout.setChecked(checked);
+        mMenu.onItemChanged(this);
         return this;
     }
 
     @Override
     public MenuItem setEnabled(boolean enabled) {
         mEnabled = enabled;
-        mLayout.setEnabled(enabled);
+        mMenu.onItemChanged(this);
         return this;
     }
 
     @Override
     public MenuItem setIcon(Drawable icon) {
         mIcon = icon;
-        mLayout.setIcon(icon);
+        mMenu.onItemChanged(this);
         return this;
     }
 
     @Override
     public MenuItem setIcon(int iconRes) {
         mIconRes = iconRes;
-        mLayout.setIcon(iconRes);
+        mMenu.onItemChanged(this);
         return this;
     }
 
     @Override
     public MenuItem setIntent(Intent intent) {
         return this;
     }
 
@@ -315,94 +283,66 @@ public class GeckoMenuItem implements Me
         if (mActionItem == (actionEnum > 0))
             return;
 
         if (actionEnum > 0) {
             if (!mShowAsActionChangedListener.hasActionItemBar())
                 return;
 
             // Change the type to just an icon
-            mLayout = new MenuItemActionBar(mContext, null);
-        } else {
-            // Change the type to default
-            mLayout = new MenuItemDefault(mContext, null);
+            MenuItemActionBar actionView = new MenuItemActionBar(mMenu.getContext(), null);
+            actionView.initialize(this);
+            mActionView = actionView;
+
+            mActionItem = (actionEnum > 0);
         }
 
-        mActionItem = (actionEnum > 0);         
-
-        mLayout.setId(mId);
-        mLayout.setOnClickListener(this);
-
-        setTitle(mTitle);        
-        setVisible(mVisible);
-        setEnabled(mEnabled);
-        setCheckable(mCheckable);
-        setChecked(mChecked);
-
-        if (mIcon == null)
-            setIcon(mIconRes);
-        else
-            setIcon(mIcon);
-        
         mShowAsActionChangedListener.onShowAsActionChanged(this, mActionItem);
     }
 
     @Override
     public MenuItem setShowAsActionFlags(int actionEnum) {
         return this;
     }
 
     public MenuItem setSubMenu(GeckoSubMenu subMenu) {
         mSubMenu = subMenu;
-        mLayout.setSubMenuIndicator(mActionProvider == null && subMenu != null);
         return this;
     }
 
     @Override
     public MenuItem setTitle(CharSequence title) {
         mTitle = title;
-        mLayout.setTitle(mTitle);
+        mMenu.onItemChanged(this);
         return this;
     }
 
     @Override
     public MenuItem setTitle(int title) {
-        mTitle = mContext.getResources().getString(title);
-        mLayout.setTitle(mTitle);
+        mTitle = mMenu.getResources().getString(title);
+        mMenu.onItemChanged(this);
         return this;
     }
 
     @Override
     public MenuItem setTitleCondensed(CharSequence title) {
         mTitleCondensed = title;
         return this;
     }
 
     @Override
     public MenuItem setVisible(boolean visible) {
         mVisible = visible;
-        mLayout.setVisibility(visible ? View.VISIBLE : View.GONE);
-
-        if (mVisibilityChangedListener != null)
-            mVisibilityChangedListener.onVisibilityChanged(this, visible);
-
+        mMenu.onItemChanged(this);
         return this;
     }
 
-    @Override
-    public void onClick(View view) {
-        // If there is a custom listener, pass it to parent menu, so that it can do default cleanups.
-        if (mMenuItemClickListener != null) {
-            if (mMenuItemClickListener instanceof GeckoMenu)
-                mMenuItemClickListener.onMenuItemClick(this);
-            else
-                mMenu.onCustomMenuItemClick(this, mMenuItemClickListener);
-        }
+    public boolean invoke() {
+        if (mMenuItemClickListener != null)
+            return mMenuItemClickListener.onMenuItemClick(this);
+        else
+            return false;
     }
 
     public void setOnShowAsActionChangedListener(OnShowAsActionChangedListener listener) {
         mShowAsActionChangedListener = listener;
     }
-
-    public void setOnVisibilityChangedListener(OnVisibilityChangedListener listener) {
-        mVisibilityChangedListener = listener;
-    }
 }
--- a/mobile/android/base/menu/GeckoSubMenu.java
+++ b/mobile/android/base/menu/GeckoSubMenu.java
@@ -10,24 +10,29 @@ import android.util.AttributeSet;
 import android.view.MenuItem;
 import android.view.SubMenu;
 import android.view.View;
 
 public class GeckoSubMenu extends GeckoMenu 
                           implements SubMenu {
     private static final String LOGTAG = "GeckoSubMenu";
 
-    private Context mContext;
-
     // MenuItem associated with this submenu.
     private MenuItem mMenuItem;
 
+    public GeckoSubMenu(Context context) {
+        super(context);
+    }
+
     public GeckoSubMenu(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mContext = context;
+    }
+
+    public GeckoSubMenu(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
     }
 
     @Override
     public void clearHeader() {
     }
 
     public SubMenu setMenuItem(MenuItem item) {
         mMenuItem = item;
--- a/mobile/android/base/menu/MenuItemActionBar.java
+++ b/mobile/android/base/menu/MenuItemActionBar.java
@@ -4,78 +4,69 @@
 
 package org.mozilla.gecko.menu;
 
 import org.mozilla.gecko.R;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageButton;
-import android.widget.ImageView;
 
 public class MenuItemActionBar extends ImageButton
                                implements GeckoMenuItem.Layout {
     private static final String LOGTAG = "GeckoMenuItemActionBar";
 
+    public MenuItemActionBar(Context context) {
+        this(context, null);
+    }
+
     public MenuItemActionBar(Context context, AttributeSet attrs) {
-        super(context, attrs);
+        this(context, attrs, R.attr.menuItemActionBarStyle);
+    }
+
+    public MenuItemActionBar(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
 
         int size = (int) (context.getResources().getDimension(R.dimen.browser_toolbar_height));
         setLayoutParams(new ViewGroup.LayoutParams(size, size));
-
-        int padding = (int) (context.getResources().getDimension(R.dimen.browser_toolbar_button_padding));
-        setPadding(padding, padding, padding, padding);
-        setBackgroundResource(R.drawable.action_bar_button);
-        setScaleType(ImageView.ScaleType.FIT_CENTER);
     }
 
     @Override
-    public View getView() {
-        return this;
+    public void initialize(GeckoMenuItem item) {
+        if (item == null)
+            return;
+
+        setIcon(item.getIcon());
+        setTitle(item.getTitle());
+        setEnabled(item.isEnabled());
     }
 
-    @Override
-    public void setIcon(Drawable icon) {
+    private void setIcon(Drawable icon) {
         if (icon != null) {
             setImageDrawable(icon);
             setVisibility(VISIBLE);
         } else {
             setVisibility(GONE);
         }
     }
 
-    @Override
-    public void setIcon(int icon) {
+    private void setIcon(int icon) {
         if (icon != 0) {
             setImageResource(icon);
             setVisibility(VISIBLE);
         } else {
             setVisibility(GONE);
         }
     }
 
-    @Override
-    public void setTitle(CharSequence title) {
+    private void setTitle(CharSequence title) {
         // set accessibility contentDescription here
         setContentDescription(title);
     }
 
     @Override
     public void setEnabled(boolean enabled) {
         super.setEnabled(enabled);
         setColorFilter(enabled ? 0 : 0xFF999999);
     }
-
-    @Override
-    public void setCheckable(boolean checkable) {
-    }
-
-    @Override
-    public void setChecked(boolean checked) {
-    }
-
-    @Override
-    public void setSubMenuIndicator(boolean hasSubMenu) {
-    }
 }
--- a/mobile/android/base/menu/MenuItemActionView.java
+++ b/mobile/android/base/menu/MenuItemActionView.java
@@ -2,95 +2,91 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.menu;
 
 import org.mozilla.gecko.R;
 
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.ImageButton;
 
 public class MenuItemActionView extends LinearLayout
                                 implements GeckoMenuItem.Layout {
     private static final String LOGTAG = "GeckoMenuItemActionView";
 
     private MenuItemDefault mMenuItem;
     private ImageButton mActionButton;
 
+    public MenuItemActionView(Context context) {
+        this(context, null);
+    }
+
     public MenuItemActionView(Context context, AttributeSet attrs) {
-        super(context, attrs);
+        this(context, attrs, R.attr.menuItemActionViewStyle);
+    }
+
+    @TargetApi(11)
+    public MenuItemActionView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
 
         Resources res = context.getResources();
         int width = res.getDimensionPixelSize(R.dimen.menu_item_row_width);
         int height = res.getDimensionPixelSize(R.dimen.menu_item_row_height);
         setMinimumWidth(width);
         setMinimumHeight(height);
 
-        setShowDividers(SHOW_DIVIDER_MIDDLE);
-        setDividerDrawable(res.getDrawable(R.drawable.divider_vertical));
-        setDividerPadding((int) (8 * res.getDisplayMetrics().density));
-
         LayoutInflater.from(context).inflate(R.layout.menu_item_action_view, this);
         mMenuItem = (MenuItemDefault) findViewById(R.id.menu_item);
         mActionButton = (ImageButton) findViewById(R.id.action_button);
-
-        mMenuItem.setBackgroundResource(R.drawable.action_bar_button);
     }
 
     @Override
-    public View getView() {
-        return this;
+    public void initialize(GeckoMenuItem item) {
+        if (item == null)
+            return;
+
+        setTitle(item.getTitle());
+        setIcon(item.getIcon());
+        setEnabled(item.isEnabled());
     }
 
-    @Override
-    public void setIcon(Drawable icon) {
+    private void setIcon(Drawable icon) {
         mMenuItem.setIcon(icon);
     }
 
-    @Override
-    public void setIcon(int icon) {
+    private void setIcon(int icon) {
         mMenuItem.setIcon(icon);
     }
 
-    @Override
-    public void setTitle(CharSequence title) {
+    private void setTitle(CharSequence title) {
         mMenuItem.setTitle(title);
     }
 
     @Override
     public void setEnabled(boolean enabled) {
         super.setEnabled(enabled);
         mMenuItem.setEnabled(enabled);
 
         if (mActionButton != null) {
             mActionButton.setEnabled(enabled);
             mActionButton.setAlpha(enabled ? 255 : 99);
         }
     }
 
-    @Override
-    public void setCheckable(boolean checkable) {
-    }
-
-    @Override
-    public void setChecked(boolean checked) {
-    }
-
-    @Override
-    public void setSubMenuIndicator(boolean hasSubMenu) {
+    public void setMenuItemClickListener(View.OnClickListener listener) {
+        mMenuItem.setOnClickListener(listener);
     }
 
     public void setActionButtonClickListener(View.OnClickListener listener) {
         mActionButton.setOnClickListener(listener);
     }
 
     public void setActionButton(Drawable drawable) {
         mActionButton.setImageDrawable(drawable);
--- a/mobile/android/base/menu/MenuItemDefault.java
+++ b/mobile/android/base/menu/MenuItemDefault.java
@@ -6,19 +6,16 @@ package org.mozilla.gecko.menu;
 
 import org.mozilla.gecko.R;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
 import android.widget.TextView;
 
 public class MenuItemDefault extends TextView
                              implements GeckoMenuItem.Layout {
     private static final int[] STATE_MORE = new int[] { R.attr.state_more };
     private static final int[] STATE_CHECKED = new int[] { android.R.attr.state_checkable, android.R.attr.state_checked };
     private static final int[] STATE_UNCHECKED = new int[] { android.R.attr.state_checkable };
 
@@ -30,35 +27,27 @@ public class MenuItemDefault extends Tex
     private boolean mChecked = false;
     private boolean mHasSubMenu = false;
 
     public MenuItemDefault(Context context) {
         this(context, null);
     }
 
     public MenuItemDefault(Context context, AttributeSet attrs) {
-        this(context, attrs, R.style.MenuItemDefault);
+        this(context, attrs, R.attr.menuItemDefaultStyle);
     }
 
     public MenuItemDefault(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        Resources res = context.getResources();
+        Resources res = getResources();
         int width = res.getDimensionPixelSize(R.dimen.menu_item_row_width);
         int height = res.getDimensionPixelSize(R.dimen.menu_item_row_height);
         setMinimumWidth(width);
         setMinimumHeight(height);
-        setGravity(Gravity.CENTER_VERTICAL);
-
-        float density = res.getDisplayMetrics().density;
-        int padding = (int) (10 * density);
-        setPadding(padding, 0, padding, 0);
-
-        int drawablePadding = (int) (6 * density);
-        setCompoundDrawablePadding(drawablePadding);
 
         int stateIconSize = res.getDimensionPixelSize(R.dimen.menu_item_state_icon);
         Rect stateIconBounds = new Rect(0, 0, stateIconSize, stateIconSize);
 
         mState = res.getDrawable(R.drawable.menu_item_state);
         mState.setBounds(stateIconBounds);
 
         if (sIconBounds == null) {
@@ -79,72 +68,76 @@ public class MenuItemDefault extends Tex
             mergeDrawableStates(drawableState, STATE_CHECKED);
         else if (mCheckable && !mChecked)
             mergeDrawableStates(drawableState, STATE_UNCHECKED);
 
         return drawableState;
     }
 
     @Override
-    public View getView() {
-        return this;
+    public void initialize(GeckoMenuItem item) {
+        if (item == null)
+            return;
+
+        setTitle(item.getTitle());        
+        setIcon(item.getIcon());
+        setEnabled(item.isEnabled());
+        setCheckable(item.isCheckable());
+        setChecked(item.isChecked());
+        setSubMenuIndicator(item.hasSubMenu());
     }
 
-    @Override
-    public void setIcon(Drawable icon) {
+    void setIcon(Drawable icon) {
         mIcon = icon;
 
-        if (mIcon != null)
+        if (mIcon != null) {
             mIcon.setBounds(sIconBounds);
+            mIcon.setAlpha(isEnabled() ? 255 : 99);
+        }
 
         setCompoundDrawables(mIcon, null, mState, null);
     }
 
-    @Override
-    public void setIcon(int icon) {
+    void setIcon(int icon) {
         Drawable drawable = null;
 
         if (icon != 0)
-            drawable = getContext().getResources().getDrawable(icon);
+            drawable = getResources().getDrawable(icon);
          
         setIcon(drawable);
     }
 
-    @Override
-    public void setTitle(CharSequence title) {
+    void setTitle(CharSequence title) {
         setText(title);
     }
 
     @Override
     public void setEnabled(boolean enabled) {
         super.setEnabled(enabled);
 
         if (mIcon != null)
             mIcon.setAlpha(enabled ? 255 : 99);
 
         if (mState != null)
             mState.setAlpha(enabled ? 255 : 99);
     }
 
-    @Override
-    public void setCheckable(boolean checkable) {
+    private void setCheckable(boolean checkable) {
         if (mCheckable != checkable) {
             mCheckable = checkable;
             refreshDrawableState();
         }
     }
 
-    @Override
-    public void setChecked(boolean checked) {
+    private void setChecked(boolean checked) {
         if (mChecked != checked) {
             mChecked = checked;
             refreshDrawableState();
         }
     }
 
-    @Override
-    public void setSubMenuIndicator(boolean hasSubMenu) {
+    private void setSubMenuIndicator(boolean hasSubMenu) {
         if (mHasSubMenu != hasSubMenu) {
             mHasSubMenu = hasSubMenu;
             refreshDrawableState();
         }
     }
 }
deleted file mode 100644
--- a/mobile/android/base/resources/color/menu_item_title.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_enabled="false" android:color="#999999" />
-    <item android:color="#222222"/>
-
-</selector>
--- a/mobile/android/base/resources/layout/menu_action_bar.xml
+++ b/mobile/android/base/resources/layout/menu_action_bar.xml
@@ -1,5 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="@dimen/menu_item_row_width"
-              android:layout_height="@dimen/browser_toolbar_height"
-              android:orientation="horizontal"/>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!--
+     Note: This layout is intended to be used only above 11+.
+     android:showDividers are available only 11+
+-->
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+      class="org.mozilla.gecko.menu.GeckoMenu$DefaultActionItemBar"
+      android:layout_width="@dimen/menu_item_row_width"
+      android:layout_height="@dimen/browser_toolbar_height"
+      android:orientation="horizontal"
+      android:divider="@drawable/divider_vertical"
+      android:showDividers="middle"
+      android:dividerPadding="0dip"/>
--- a/mobile/android/base/resources/layout/menu_item_action_view.xml
+++ b/mobile/android/base/resources/layout/menu_item_action_view.xml
@@ -4,17 +4,20 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <org.mozilla.gecko.menu.MenuItemDefault
             android:id="@+id/menu_item"
             android:layout_width="0dip"
             android:layout_height="fill_parent"
-            android:layout_weight="1.0"/>
+            android:layout_weight="1.0"
+            android:background="@drawable/action_bar_button"
+            android:clickable="true"
+            android:focusable="true"/>
 
     <ImageButton android:id="@+id/action_button"
                  android:layout_width="@dimen/menu_item_action_icon"
                  android:layout_height="@dimen/menu_item_row_height"
                  android:paddingTop="8dip"
                  android:paddingBottom="8dip"
                  android:scaleType="centerInside"
                  android:background="@drawable/action_bar_button"
--- a/mobile/android/base/resources/values-v11/themes.xml
+++ b/mobile/android/base/resources/values-v11/themes.xml
@@ -39,11 +39,14 @@
         Activity based themes.
     -->
     <style name="Gecko.App">
         <item name="android:windowBackground">@color/background_normal</item>
         <item name="android:panelBackground">@drawable/menu_panel_bg</item>
         <item name="android:listViewStyle">@style/Widget.ListView</item>
         <item name="android:spinnerStyle">@style/Widget.Spinner</item>
         <item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
+        <item name="menuItemActionBarStyle">@style/Widget.MenuItemActionBar</item>
+        <item name="menuItemActionViewStyle">@style/Widget.MenuItemActionView</item>
+        <item name="menuItemDefaultStyle">@style/Widget.MenuItemDefault</item>
     </style>
 
 </resources>
--- a/mobile/android/base/resources/values/attrs.xml
+++ b/mobile/android/base/resources/values/attrs.xml
@@ -1,15 +1,29 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <resources>
 
+    <!-- Theme level attributes -->
+    <declare-styleable name="GeckoTheme">
+
+        <!-- Style for MenuItemActionBar -->
+        <attr name="menuItemActionBarStyle" format="reference"/>
+
+        <!-- Style for MenuItemActionView -->
+        <attr name="menuItemActionViewStyle" format="reference"/>
+
+        <!-- Style for MenuItemDefault -->
+        <attr name="menuItemDefaultStyle" format="reference"/>
+
+    </declare-styleable>
+
     <declare-styleable name="AboutHomeSection">
         <attr name="title" format="string"/>
         <attr name="subtitle" format="string"/>
         <attr name="more_text" format="string"/>
     </declare-styleable>
 
     <!-- DoorHangers -->
     <declare-styleable name="DoorHanger">
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -66,16 +66,38 @@
     </style>
 
     <style name="Widget.Spinner" parent="android:style/Widget.Spinner">
         <item name="android:minWidth">@dimen/doorhanger_input_width</item>
     </style>
 
     <style name="Widget.TextView.SpinnerItem" parent="android:style/Widget.TextView.SpinnerItem"/>
 
+    <style name="Widget.MenuItemActionBar">
+        <item name="android:padding">@dimen/browser_toolbar_button_padding</item>
+        <item name="android:background">@drawable/action_bar_button</item>
+        <item name="android:scaleType">fitCenter</item>
+    </style>
+
+    <style name="Widget.MenuItemActionView">
+        <item name="android:divider">@drawable/divider_vertical</item>
+        <item name="android:showDividers">middle</item>
+        <item name="android:dividerPadding">8dip</item>
+    </style>
+
+    <style name="Widget.MenuItemDefault">
+        <item name="android:paddingLeft">10dip</item>
+        <item name="android:paddingRight">10dip</item>
+        <item name="android:drawablePadding">6dip</item>
+        <item name="android:gravity">center_vertical</item>
+        <item name="android:textAppearance">@style/TextAppearance</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:ellipsize">middle</item>
+    </style>
+
     <!--
         TextAppearance
         Note: Gecko uses light theme as default, while Android uses dark.
         If Android convention has to be followd, the list of colors specified 
         in themes.xml would be inverse, and things would get confusing.
         Hence, Gecko's TextAppearance is based on text over light theme and
         TextAppearance.Inverse is based on text over dark theme.
     -->
@@ -435,16 +457,9 @@
         <item name="android:textAppearance">@style/TextAppearance</item>
     </style>
 
     <style name="PopupAnimation">
         <item name="@android:windowEnterAnimation">@anim/popup_show</item>
         <item name="@android:windowExitAnimation">@anim/popup_hide</item>
     </style>
 
-    <style name="MenuItemDefault">
-          <item name="android:textSize">16sp</item>
-          <item name="android:textColor">@color/menu_item_title</item>
-          <item name="android:singleLine">true</item>
-          <item name="android:ellipsize">middle</item>
-    </style>
-
 </resources>
--- a/mobile/android/base/widget/GeckoActionProvider.java
+++ b/mobile/android/base/widget/GeckoActionProvider.java
@@ -55,29 +55,18 @@ public class GeckoActionProvider extends
 
         PackageManager packageManager = mContext.getPackageManager();
         ResolveInfo defaultActivity = dataModel.getDefaultActivity();
         view.setActionButton(defaultActivity == null ? null : defaultActivity.loadIcon(packageManager));
 
         return view;
     }
 
-    @Override
-    public View onCreateActionView(MenuItem item) {
-        MenuItemActionView view = (MenuItemActionView) onCreateActionView();
-        view.setId(item.getItemId());
-        view.setTitle(item.getTitle());
-        view.setIcon(item.getIcon());
-        view.setVisibility(item.isVisible() ? View.VISIBLE : View.GONE);
-        view.setEnabled(item.isEnabled());
-        return view;
-    }
-
-    public View getView(MenuItem item) {
-        return onCreateActionView(item);
+    public View getView() {
+        return onCreateActionView();
     }
 
     @Override
     public boolean hasSubMenu() {
         return true;
     }
 
     @Override