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.

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

mercurial