mobile/android/base/menu/GeckoMenu.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 package org.mozilla.gecko.menu;
     7 import org.mozilla.gecko.AppConstants;
     8 import org.mozilla.gecko.R;
     9 import org.mozilla.gecko.util.ThreadUtils;
    10 import org.mozilla.gecko.util.ThreadUtils.AssertBehavior;
    11 import org.mozilla.gecko.widget.GeckoActionProvider;
    13 import android.content.ComponentName;
    14 import android.content.Context;
    15 import android.content.Intent;
    16 import android.util.AttributeSet;
    17 import android.util.Log;
    18 import android.view.ActionProvider;
    19 import android.view.KeyEvent;
    20 import android.view.LayoutInflater;
    21 import android.view.Menu;
    22 import android.view.MenuItem;
    23 import android.view.SubMenu;
    24 import android.view.View;
    25 import android.view.ViewGroup;
    26 import android.widget.AdapterView;
    27 import android.widget.BaseAdapter;
    28 import android.widget.LinearLayout;
    29 import android.widget.ListView;
    31 import java.util.ArrayList;
    32 import java.util.HashMap;
    33 import java.util.List;
    34 import java.util.Map;
    36 public class GeckoMenu extends ListView 
    37                        implements Menu,
    38                                   AdapterView.OnItemClickListener,
    39                                   GeckoMenuItem.OnShowAsActionChangedListener {
    40     private static final String LOGTAG = "GeckoMenu";
    42     /**
    43      * Controls whether off-UI-thread method calls in this class cause an
    44      * exception or just logging.
    45      */
    46     private static final AssertBehavior THREAD_ASSERT_BEHAVIOR = AppConstants.RELEASE_BUILD ? AssertBehavior.NONE : AssertBehavior.THROW;
    48     /*
    49      * A callback for a menu item selected event.
    50      */
    51     public static interface Callback {
    52         // Called when a menu item is selected, with the actual menu item as the argument.
    53         public boolean onMenuItemSelected(MenuItem item);
    54     }
    56     /*
    57      * An interface for a presenter to show the menu.
    58      * Either an Activity or a View can be a presenter, that can watch for events
    59      * and show/hide menu.
    60      */
    61     public static interface MenuPresenter {
    62         // Open the menu.
    63         public void openMenu();
    65         // Show the actual view containing the menu items. This can either be a parent or sub-menu.
    66         public void showMenu(View menu);
    68         // Close the menu.
    69         public void closeMenu();
    70     }
    72     /*
    73      * An interface for a presenter of action-items.
    74      * Either an Activity or a View can be a presenter, that can watch for events
    75      * and add/remove action-items. If not ActionItemBarPresenter, the menu uses a 
    76      * DefaultActionItemBar, that shows the action-items as a header over list-view.
    77      */
    78     public static interface ActionItemBarPresenter {
    79         // Add an action-item.
    80         public boolean addActionItem(View actionItem);
    82         // Remove an action-item.
    83         public void removeActionItem(View actionItem);
    84     }
    86     protected static final int NO_ID = 0;
    88     // List of all menu items.
    89     private List<GeckoMenuItem> mItems;
    91     // Map of "always" action-items in action-bar and their views.
    92     private Map<GeckoMenuItem, View> mPrimaryActionItems;
    94     // Map of "ifRoom" action-items in action-bar and their views.
    95     private Map<GeckoMenuItem, View> mSecondaryActionItems;
    97     // Reference to a callback for menu events.
    98     private Callback mCallback;
   100     // Reference to menu presenter.
   101     private MenuPresenter mMenuPresenter;
   103     // Reference to "always" action-items bar in action-bar.
   104     private ActionItemBarPresenter mPrimaryActionItemBar;
   106     // Reference to "ifRoom" action-items bar in action-bar.
   107     private final ActionItemBarPresenter mSecondaryActionItemBar;
   109     // Adapter to hold the list of menu items.
   110     private MenuItemsAdapter mAdapter;
   112     // Show/hide icons in the list.
   113     private boolean mShowIcons;
   115     public GeckoMenu(Context context) {
   116         this(context, null);
   117     }
   119     public GeckoMenu(Context context, AttributeSet attrs) {
   120         this(context, attrs, R.attr.geckoMenuListViewStyle);
   121     }
   123     public GeckoMenu(Context context, AttributeSet attrs, int defStyle) {
   124         super(context, attrs, defStyle);
   126         setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
   127                                          LayoutParams.FILL_PARENT));
   129         // Attach an adapter.
   130         mAdapter = new MenuItemsAdapter();
   131         setAdapter(mAdapter);
   132         setOnItemClickListener(this);
   134         mShowIcons = false;
   135         mItems = new ArrayList<GeckoMenuItem>();
   136         mPrimaryActionItems = new HashMap<GeckoMenuItem, View>();
   137         mSecondaryActionItems = new HashMap<GeckoMenuItem, View>();
   139         mPrimaryActionItemBar = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_action_bar, null);
   140         mSecondaryActionItemBar = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_secondary_action_bar, null);
   141     }
   143     private static void assertOnUiThread() {
   144         ThreadUtils.assertOnUiThread(THREAD_ASSERT_BEHAVIOR);
   145     }
   147     @Override
   148     public MenuItem add(CharSequence title) {
   149         GeckoMenuItem menuItem = new GeckoMenuItem(this, NO_ID, 0, title);
   150         addItem(menuItem);
   151         return menuItem;
   152     }
   154     @Override
   155     public MenuItem add(int groupId, int itemId, int order, int titleRes) {
   156         GeckoMenuItem menuItem = new GeckoMenuItem(this, itemId, order, titleRes);
   157         addItem(menuItem);
   158         return menuItem;
   159     }
   161     @Override
   162     public MenuItem add(int titleRes) {
   163         GeckoMenuItem menuItem = new GeckoMenuItem(this, NO_ID, 0, titleRes);
   164         addItem(menuItem);
   165         return menuItem;
   166     }
   168     @Override
   169     public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
   170         GeckoMenuItem menuItem = new GeckoMenuItem(this, itemId, order, title);
   171         addItem(menuItem);
   172         return menuItem;
   173     }
   175     private void addItem(GeckoMenuItem menuItem) {
   176         assertOnUiThread();
   177         menuItem.setOnShowAsActionChangedListener(this);
   178         mAdapter.addMenuItem(menuItem);
   179         mItems.add(menuItem);
   180     }
   182     private boolean addActionItem(final GeckoMenuItem menuItem) {
   183         assertOnUiThread();
   184         menuItem.setOnShowAsActionChangedListener(this);
   186         final View actionView = menuItem.getActionView();
   187         final int actionEnum = menuItem.getActionEnum();
   188         boolean added = false;
   190         if (actionEnum == GeckoMenuItem.SHOW_AS_ACTION_ALWAYS) {
   191             if (mPrimaryActionItems.size() == 0 &&
   192                 mPrimaryActionItemBar instanceof DefaultActionItemBar) {
   193                 // Reset the adapter before adding the header view to a list.
   194                 setAdapter(null);
   195                 addHeaderView((DefaultActionItemBar) mPrimaryActionItemBar);
   196                 setAdapter(mAdapter);
   197             }
   199             if (added = mPrimaryActionItemBar.addActionItem(actionView)) {
   200                 mPrimaryActionItems.put(menuItem, actionView);
   201                 mItems.add(menuItem);
   202             }
   203         } else if (actionEnum == GeckoMenuItem.SHOW_AS_ACTION_IF_ROOM) {
   204             if (mSecondaryActionItems.size() == 0) {
   205                 // Reset the adapter before adding the header view to a list.
   206                 setAdapter(null);
   207                 addHeaderView((DefaultActionItemBar) mSecondaryActionItemBar);
   208                 setAdapter(mAdapter);
   209             }
   211             if (added = mSecondaryActionItemBar.addActionItem(actionView)) {
   212                 mSecondaryActionItems.put(menuItem, actionView);
   213                 mItems.add(menuItem);
   214             }
   215         }
   217         // Set the listeners.
   218         if (actionView instanceof MenuItemActionBar) {
   219             ((MenuItemActionBar) actionView).setOnClickListener(new View.OnClickListener() {
   220                 @Override
   221                 public void onClick(View view) {
   222                     handleMenuItemClick(menuItem);
   223                 }
   224             });
   225         } else if (actionView instanceof MenuItemActionView) {
   226             ((MenuItemActionView) actionView).setMenuItemClickListener(new View.OnClickListener() {
   227                 @Override
   228                 public void onClick(View view) {
   229                     handleMenuItemClick(menuItem);
   230                 }
   231             });
   232         }
   234         return added;
   235     }
   237     @Override
   238     public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
   239         return 0;
   240     }
   242     @Override
   243     public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
   244         MenuItem menuItem = add(groupId, itemId, order, title);
   245         return addSubMenu(menuItem);
   246     }
   248     @Override
   249     public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
   250         MenuItem menuItem = add(groupId, itemId, order, titleRes);
   251         return addSubMenu(menuItem);
   252     }
   254     @Override
   255     public SubMenu addSubMenu(CharSequence title) {
   256         MenuItem menuItem = add(title);
   257         return addSubMenu(menuItem);
   258     }
   260     @Override
   261     public SubMenu addSubMenu(int titleRes) {
   262         MenuItem menuItem = add(titleRes);
   263         return addSubMenu(menuItem);
   264     }
   266     private SubMenu addSubMenu(MenuItem menuItem) {
   267         GeckoSubMenu subMenu = new GeckoSubMenu(getContext());
   268         subMenu.setMenuItem(menuItem);
   269         subMenu.setCallback(mCallback);
   270         subMenu.setMenuPresenter(mMenuPresenter);
   271         ((GeckoMenuItem) menuItem).setSubMenu(subMenu);
   272         return subMenu;
   273     }
   275     private void removePrimaryActionBarView() {
   276         // Reset the adapter before removing the header view from a list.
   277         setAdapter(null);
   278         removeHeaderView((DefaultActionItemBar) mPrimaryActionItemBar);
   279         setAdapter(mAdapter);
   280     }
   282     private void removeSecondaryActionBarView() {
   283         // Reset the adapter before removing the header view from a list.
   284         setAdapter(null);
   285         removeHeaderView((DefaultActionItemBar) mSecondaryActionItemBar);
   286         setAdapter(mAdapter);
   287     }
   289     @Override
   290     public void clear() {
   291         assertOnUiThread();
   292         for (GeckoMenuItem menuItem : mItems) {
   293             if (menuItem.hasSubMenu()) {
   294                 SubMenu sub = menuItem.getSubMenu();
   295                 if (sub == null) {
   296                     continue;
   297                 }
   298                 try {
   299                     sub.clear();
   300                 } catch (Exception ex) {
   301                     Log.e(LOGTAG, "Couldn't clear submenu.", ex);
   302                 }
   303             }
   304         }
   306         mAdapter.clear();
   307         mItems.clear();
   309         /*
   310          * Reinflating the menu will re-add any action items to the toolbar, so
   311          * remove the old ones. This also ensures that any text associated with
   312          * these is switched to the correct locale.
   313          */
   314         if (mPrimaryActionItemBar != null) {
   315             for (View item : mPrimaryActionItems.values()) {
   316                 mPrimaryActionItemBar.removeActionItem(item);
   317             }
   318         }
   319         mPrimaryActionItems.clear();
   321         if (mSecondaryActionItemBar != null) {
   322             for (View item : mSecondaryActionItems.values()) {
   323                 mSecondaryActionItemBar.removeActionItem(item);
   324             }
   325         }
   326         mSecondaryActionItems.clear();
   328         // Remove the view, too -- the first addActionItem will re-add it,
   329         // and this is simpler than changing that logic.
   330         if (mPrimaryActionItemBar instanceof DefaultActionItemBar) {
   331             removePrimaryActionBarView();
   332         }
   334         removeSecondaryActionBarView();
   335     }
   337     @Override
   338     public void close() {
   339         if (mMenuPresenter != null)
   340             mMenuPresenter.closeMenu();
   341     }
   343     private void showMenu(View viewForMenu) {
   344         if (mMenuPresenter != null)
   345             mMenuPresenter.showMenu(viewForMenu);
   346     }
   348     @Override
   349     public MenuItem findItem(int id) {
   350         for (GeckoMenuItem menuItem : mItems) {
   351             if (menuItem.getItemId() == id) {
   352                 return menuItem;
   353             } else if (menuItem.hasSubMenu()) {
   354                 if (!menuItem.hasActionProvider()) {
   355                     SubMenu subMenu = menuItem.getSubMenu();
   356                     MenuItem item = subMenu.findItem(id);
   357                     if (item != null)
   358                         return item;
   359                 }
   360             }
   361         }
   362         return null;
   363     }
   365     @Override
   366     public MenuItem getItem(int index) {
   367         if (index < mItems.size())
   368             return mItems.get(index);
   370         return null;
   371     }
   373     @Override
   374     public boolean hasVisibleItems() {
   375         assertOnUiThread();
   376         for (GeckoMenuItem menuItem : mItems) {
   377             if (menuItem.isVisible() &&
   378                 !mPrimaryActionItems.containsKey(menuItem) &&
   379                 !mSecondaryActionItems.containsKey(menuItem))
   380                 return true;
   381         }
   383         return false;
   384     }
   386     @Override
   387     public boolean isShortcutKey(int keyCode, KeyEvent event) {
   388         return true;
   389     }
   391     @Override
   392     public boolean performIdentifierAction(int id, int flags) {
   393         return false;
   394     }
   396     @Override
   397     public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
   398         return false;
   399     }
   401     @Override
   402     public void removeGroup(int groupId) {
   403     }
   405     @Override
   406     public void removeItem(int id) {
   407         assertOnUiThread();
   408         GeckoMenuItem item = (GeckoMenuItem) findItem(id);
   409         if (item == null)
   410             return;
   412         // Remove it from any sub-menu.
   413         for (GeckoMenuItem menuItem : mItems) {
   414             if (menuItem.hasSubMenu()) {
   415                 SubMenu subMenu = menuItem.getSubMenu();
   416                 if (subMenu != null && subMenu.findItem(id) != null) {
   417                     subMenu.removeItem(id);
   418                     return;
   419                 }
   420             }
   421         }
   423         // Remove it from own menu.
   424         if (mPrimaryActionItems.containsKey(item)) {
   425             if (mPrimaryActionItemBar != null)
   426                 mPrimaryActionItemBar.removeActionItem(mPrimaryActionItems.get(item));
   428             mPrimaryActionItems.remove(item);
   429             mItems.remove(item);
   431             if (mPrimaryActionItems.size() == 0 && 
   432                 mPrimaryActionItemBar instanceof DefaultActionItemBar) {
   433                 removePrimaryActionBarView();
   434             }
   436             return;
   437         }
   439         if (mSecondaryActionItems.containsKey(item)) {
   440             if (mSecondaryActionItemBar != null)
   441                 mSecondaryActionItemBar.removeActionItem(mSecondaryActionItems.get(item));
   443             mSecondaryActionItems.remove(item);
   444             mItems.remove(item);
   446             if (mSecondaryActionItems.size() == 0) {
   447                 removeSecondaryActionBarView();
   448             }
   450             return;
   451         }
   453         mAdapter.removeMenuItem(item);
   454         mItems.remove(item);
   455     }
   457     @Override
   458     public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
   459     }
   461     @Override
   462     public void setGroupEnabled(int group, boolean enabled) {
   463     }
   465     @Override
   466     public void setGroupVisible(int group, boolean visible) {
   467     }
   469     @Override
   470     public void setQwertyMode(boolean isQwerty) {
   471     }
   473     @Override
   474     public int size() {
   475         return mItems.size();
   476     }
   478     @Override
   479     public boolean hasActionItemBar() {
   480          return (mPrimaryActionItemBar != null) && (mSecondaryActionItemBar != null);
   481     }
   483     @Override
   484     public void onShowAsActionChanged(GeckoMenuItem item) {
   485         removeItem(item.getItemId());
   487         if (item.isActionItem() && addActionItem(item)) {
   488             return;
   489         }
   491         addItem(item);
   492     }
   494     public void onItemChanged(GeckoMenuItem item) {
   495         assertOnUiThread();
   496         if (item.isActionItem()) {
   497             final View actionView;
   498             if (item.getActionEnum() == GeckoMenuItem.SHOW_AS_ACTION_ALWAYS) {
   499                 actionView = mPrimaryActionItems.get(item);
   500             } else {
   501                 actionView = mSecondaryActionItems.get(item);
   502             }
   504             if (actionView != null) {
   505                 // The update could be coming from the background thread.
   506                 // Post a runnable on the UI thread of the view for it to update.
   507                 final GeckoMenuItem menuItem = item;
   508                 actionView.post(new Runnable() {
   509                     @Override
   510                     public void run() {
   511                         if (menuItem.isVisible()) {
   512                             actionView.setVisibility(View.VISIBLE);
   513                             if (actionView instanceof MenuItemActionBar) {
   514                                 ((MenuItemActionBar) actionView).initialize(menuItem);
   515                             } else {
   516                                 ((MenuItemActionView) actionView).initialize(menuItem);
   517                             }
   518                         } else {
   519                             actionView.setVisibility(View.GONE);
   520                         }
   521                     }
   522                 });
   523             }
   524         } else {
   525             mAdapter.notifyDataSetChanged();
   526         }
   527     }
   529     @Override
   530     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
   531         // We might be showing headers. Account them while using the position.
   532         position -= getHeaderViewsCount();
   534         GeckoMenuItem item = mAdapter.getItem(position);
   535         handleMenuItemClick(item);
   536     }
   538     private void handleMenuItemClick(GeckoMenuItem item) {
   539         if (!item.isEnabled())
   540             return;
   542         if (item.invoke()) {
   543             close();
   544         } else if (item.hasSubMenu()) {
   545             // Refresh the submenu for the provider.
   546             GeckoActionProvider provider = item.getGeckoActionProvider();
   547             if (provider != null) {
   548                 GeckoSubMenu subMenu = new GeckoSubMenu(getContext());
   549                 subMenu.setShowIcons(true);
   550                 provider.onPrepareSubMenu(subMenu);
   551                 item.setSubMenu(subMenu);
   552             }
   554             // Show the submenu.
   555             GeckoSubMenu subMenu = (GeckoSubMenu) item.getSubMenu();
   556             showMenu(subMenu);
   557         } else {
   558             close();
   559             mCallback.onMenuItemSelected(item);
   560         }
   561     }
   563     public Callback getCallback() {
   564         return mCallback;
   565     }
   567     public MenuPresenter getMenuPresenter() {
   568         return mMenuPresenter;
   569     }
   571     public void setCallback(Callback callback) {
   572         mCallback = callback;
   574         // Update the submenus just in case this changes on the fly.
   575         for (GeckoMenuItem menuItem : mItems) {
   576             if (menuItem.hasSubMenu()) {
   577                 GeckoSubMenu subMenu = (GeckoSubMenu) menuItem.getSubMenu();
   578                 subMenu.setCallback(mCallback);
   579             }
   580         }
   581     }
   583     public void setMenuPresenter(MenuPresenter presenter) {
   584         mMenuPresenter = presenter;
   586         // Update the submenus just in case this changes on the fly.
   587         for (GeckoMenuItem menuItem : mItems) {
   588             if (menuItem.hasSubMenu()) {
   589                 GeckoSubMenu subMenu = (GeckoSubMenu) menuItem.getSubMenu();
   590                 subMenu.setMenuPresenter(mMenuPresenter);
   591             }
   592         }
   593     }
   595     public void setActionItemBarPresenter(ActionItemBarPresenter presenter) {
   596         mPrimaryActionItemBar = presenter;
   597     }
   599     public void setShowIcons(boolean show) {
   600         if (mShowIcons != show) {
   601             mShowIcons = show;
   602             mAdapter.notifyDataSetChanged();
   603         }
   604     }
   606     // Action Items are added to the header view by default.
   607     // URL bar can register itself as a presenter, in case it has a different place to show them.
   608     public static class DefaultActionItemBar extends LinearLayout
   609                                              implements ActionItemBarPresenter {
   610         private final int mRowHeight;
   611         private float mWeightSum;
   613         public DefaultActionItemBar(Context context) {
   614             this(context, null);
   615         }
   617         public DefaultActionItemBar(Context context, AttributeSet attrs) {
   618             super(context, attrs);
   620             mRowHeight = getResources().getDimensionPixelSize(R.dimen.menu_item_row_height);
   621         }
   623         @Override
   624         public boolean addActionItem(View actionItem) {
   625             ViewGroup.LayoutParams actualParams = actionItem.getLayoutParams();
   626             LinearLayout.LayoutParams params;
   628             if (actualParams != null) {
   629                 params = new LinearLayout.LayoutParams(actionItem.getLayoutParams());
   630                 params.width = 0;
   631             } else {
   632                 params = new LinearLayout.LayoutParams(0, mRowHeight);
   633             }
   635             if (actionItem instanceof MenuItemActionView) {
   636                 params.weight = ((MenuItemActionView) actionItem).getChildCount();
   637             } else {
   638                 params.weight = 1.0f;
   639             }
   641             mWeightSum += params.weight;
   643             actionItem.setLayoutParams(params);
   644             addView(actionItem);
   645             setWeightSum(mWeightSum);
   646             return true;
   647         }
   649         @Override
   650         public void removeActionItem(View actionItem) {
   651             if (indexOfChild(actionItem) != -1) {
   652                 LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) actionItem.getLayoutParams();
   653                 mWeightSum -= params.weight;
   654                 removeView(actionItem);
   655             }
   656         }
   657     }
   659     // Adapter to bind menu items to the list.
   660     private class MenuItemsAdapter extends BaseAdapter {
   661         private static final int VIEW_TYPE_DEFAULT = 0;
   662         private static final int VIEW_TYPE_ACTION_MODE = 1;
   664         private List<GeckoMenuItem> mItems;
   666         public MenuItemsAdapter() {
   667             mItems = new ArrayList<GeckoMenuItem>();
   668         }
   670         @Override
   671         public int getCount() {
   672             if (mItems == null)
   673                 return 0;
   675             int visibleCount = 0;
   676             for (GeckoMenuItem item : mItems) {
   677                 if (item.isVisible())
   678                     visibleCount++;
   679             }
   681             return visibleCount;
   682         }
   684         @Override
   685         public GeckoMenuItem getItem(int position) {
   686             for (GeckoMenuItem item : mItems) {
   687                 if (item.isVisible()) {
   688                     position--;
   690                     if (position < 0)
   691                         return item;
   692                 }
   693             }
   695             return null;
   696         }
   698         @Override
   699         public long getItemId(int position) {
   700             return position;
   701         }
   703         @Override
   704         public View getView(int position, View convertView, ViewGroup parent) {
   705             GeckoMenuItem item = getItem(position);
   706             GeckoMenuItem.Layout view = null;
   708             // Try to re-use the view.
   709             if (convertView == null && getItemViewType(position) == VIEW_TYPE_DEFAULT) {
   710                 view = new MenuItemDefault(parent.getContext(), null);
   711             } else {
   712                 view = (GeckoMenuItem.Layout) convertView;
   713             }
   715             if (view == null || view instanceof MenuItemActionView) {
   716                 // Always get from the menu item.
   717                 // This will ensure that the default activity is refreshed.
   718                 view = (MenuItemActionView) item.getActionView();
   720                 // ListView will not perform an item click if the row has a focusable view in it.
   721                 // Hence, forward the click event on the menu item in the action-view to the ListView.
   722                 final View actionView = (View) view;
   723                 final int pos = position;
   724                 final long id = getItemId(position);
   725                 ((MenuItemActionView) view).setMenuItemClickListener(new View.OnClickListener() {
   726                     @Override
   727                     public void onClick(View v) {
   728                         GeckoMenu listView = GeckoMenu.this;
   729                         listView.performItemClick(actionView, pos + listView.getHeaderViewsCount(), id);
   730                     }
   731                 });
   732             }
   734             // Initialize the view.
   735             view.setShowIcon(mShowIcons);
   736             view.initialize(item);
   737             return (View) view; 
   738         }
   740         @Override
   741         public int getItemViewType(int position) {
   742             return getItem(position).getGeckoActionProvider() == null ? VIEW_TYPE_DEFAULT : VIEW_TYPE_ACTION_MODE;
   743         }
   745         @Override
   746         public int getViewTypeCount() {
   747             return 2;
   748         }
   750         @Override
   751         public boolean hasStableIds() {
   752             return false;
   753         }
   755         @Override
   756         public boolean areAllItemsEnabled() {
   757             // Setting this to true is a workaround to fix disappearing
   758             // dividers in the menu (bug 963249).
   759             return true;
   760         }
   762         @Override
   763         public boolean isEnabled(int position) {
   764             return getItem(position).isEnabled();
   765         }
   767         public void addMenuItem(GeckoMenuItem menuItem) {
   768             if (mItems.contains(menuItem))
   769                 return;
   771             // Insert it in proper order.
   772             int index = 0;
   773             for (GeckoMenuItem item : mItems) {
   774                 if (item.getOrder() > menuItem.getOrder()) {
   775                     mItems.add(index, menuItem);
   776                     notifyDataSetChanged();
   777                     return;
   778                 } else {
   779                   index++;
   780                 }
   781             }
   783             // Add the menuItem at the end.
   784             mItems.add(menuItem);
   785             notifyDataSetChanged();
   786         }
   788         public void removeMenuItem(GeckoMenuItem menuItem) {
   789             // Remove it from the list.
   790             mItems.remove(menuItem);
   791             notifyDataSetChanged();
   792         }
   794         public void clear() {
   795             mItems.clear();
   796             notifyDataSetChanged();
   797         }
   799         public GeckoMenuItem getMenuItem(int id) {
   800             for (GeckoMenuItem item : mItems) {
   801                 if (item.getItemId() == id)
   802                     return item;
   803             }
   805             return null;
   806         }
   807     }
   808 }

mercurial