mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 23:38:38 +09:00
pt 1 in reviving the android build (copied from pm 28a1, wish me luck)
This commit is contained in:
parent
efa9662725
commit
d7788a6d6d
4249 changed files with 468189 additions and 0 deletions
928
mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenu.java
Normal file
928
mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenu.java
Normal file
|
|
@ -0,0 +1,928 @@
|
|||
/* 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.AppConstants;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils.AssertBehavior;
|
||||
import org.mozilla.gecko.widget.GeckoActionProvider;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
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,
|
||||
AdapterView.OnItemClickListener,
|
||||
GeckoMenuItem.OnShowAsActionChangedListener {
|
||||
private static final String LOGTAG = "GeckoMenu";
|
||||
|
||||
/**
|
||||
* Controls whether off-UI-thread method calls in this class cause an
|
||||
* exception or just logging.
|
||||
*/
|
||||
private static final AssertBehavior THREAD_ASSERT_BEHAVIOR = AppConstants.RELEASE_OR_BETA ? AssertBehavior.NONE : AssertBehavior.THROW;
|
||||
|
||||
/*
|
||||
* A callback for a menu item click/long click event.
|
||||
*/
|
||||
public static interface Callback {
|
||||
// Called when a menu item is clicked, with the actual menu item as the argument.
|
||||
public boolean onMenuItemClick(MenuItem item);
|
||||
|
||||
// Called when a menu item is long-clicked, with the actual menu item as the argument.
|
||||
public boolean onMenuItemLongClick(MenuItem item);
|
||||
}
|
||||
|
||||
/*
|
||||
* An interface for a presenter to show the menu.
|
||||
* Either an Activity or a View can be a presenter, that can watch for events
|
||||
* and show/hide menu.
|
||||
*/
|
||||
public static interface MenuPresenter {
|
||||
// Open the menu.
|
||||
public void openMenu();
|
||||
|
||||
// Show the actual view containing the menu items. This can either be a parent or sub-menu.
|
||||
public void showMenu(View menu);
|
||||
|
||||
// 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
|
||||
* DefaultActionItemBar, that shows the action-items as a header over list-view.
|
||||
*/
|
||||
public static interface ActionItemBarPresenter {
|
||||
// Add an action-item.
|
||||
public boolean addActionItem(View actionItem);
|
||||
|
||||
// Remove an action-item.
|
||||
public void removeActionItem(View actionItem);
|
||||
}
|
||||
|
||||
protected static final int NO_ID = 0;
|
||||
|
||||
// List of all menu items.
|
||||
private final List<GeckoMenuItem> mItems;
|
||||
|
||||
// Quick lookup array used to make a fast path in findItem.
|
||||
private final SparseArray<MenuItem> mItemsById;
|
||||
|
||||
// Map of "always" action-items in action-bar and their views.
|
||||
private final Map<GeckoMenuItem, View> mPrimaryActionItems;
|
||||
|
||||
// Map of "ifRoom" action-items in action-bar and their views.
|
||||
private final Map<GeckoMenuItem, View> mSecondaryActionItems;
|
||||
|
||||
// Map of "collapseActionView" action-items in action-bar and their views.
|
||||
private final Map<GeckoMenuItem, View> mQuickShareActionItems;
|
||||
|
||||
// Reference to a callback for menu events.
|
||||
private Callback mCallback;
|
||||
|
||||
// Reference to menu presenter.
|
||||
private MenuPresenter mMenuPresenter;
|
||||
|
||||
// Reference to "always" action-items bar in action-bar.
|
||||
private ActionItemBarPresenter mPrimaryActionItemBar;
|
||||
|
||||
// Reference to "ifRoom" action-items bar in action-bar.
|
||||
private final ActionItemBarPresenter mSecondaryActionItemBar;
|
||||
|
||||
// Reference to "collapseActionView" action-items bar in action-bar.
|
||||
private final ActionItemBarPresenter mQuickShareActionItemBar;
|
||||
|
||||
// Adapter to hold the list of menu items.
|
||||
private final MenuItemsAdapter mAdapter;
|
||||
|
||||
// Show/hide icons in the list.
|
||||
boolean mShowIcons;
|
||||
|
||||
public GeckoMenu(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public GeckoMenu(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.geckoMenuListViewStyle);
|
||||
}
|
||||
|
||||
public GeckoMenu(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.MATCH_PARENT));
|
||||
|
||||
// Attach an adapter.
|
||||
mAdapter = new MenuItemsAdapter();
|
||||
setAdapter(mAdapter);
|
||||
setOnItemClickListener(this);
|
||||
|
||||
mItems = new ArrayList<GeckoMenuItem>();
|
||||
mItemsById = new SparseArray<MenuItem>();
|
||||
mPrimaryActionItems = new HashMap<GeckoMenuItem, View>();
|
||||
mSecondaryActionItems = new HashMap<GeckoMenuItem, View>();
|
||||
mQuickShareActionItems = new HashMap<GeckoMenuItem, View>();
|
||||
|
||||
mPrimaryActionItemBar = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_action_bar, null);
|
||||
mSecondaryActionItemBar = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_secondary_action_bar, null);
|
||||
mQuickShareActionItemBar = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_secondary_action_bar, null);
|
||||
}
|
||||
|
||||
private static void assertOnUiThread() {
|
||||
ThreadUtils.assertOnUiThread(THREAD_ASSERT_BEHAVIOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(CharSequence 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(this, itemId, order, titleRes);
|
||||
addItem(menuItem);
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int 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(this, itemId, order, title);
|
||||
addItem(menuItem);
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
private void addItem(GeckoMenuItem menuItem) {
|
||||
assertOnUiThread();
|
||||
menuItem.setOnShowAsActionChangedListener(this);
|
||||
mAdapter.addMenuItem(menuItem);
|
||||
mItems.add(menuItem);
|
||||
}
|
||||
|
||||
private boolean addActionItem(final GeckoMenuItem menuItem) {
|
||||
assertOnUiThread();
|
||||
menuItem.setOnShowAsActionChangedListener(this);
|
||||
|
||||
final View actionView = menuItem.getActionView();
|
||||
final int actionEnum = menuItem.getActionEnum();
|
||||
boolean added = false;
|
||||
|
||||
if (actionEnum == GeckoMenuItem.SHOW_AS_ACTION_ALWAYS) {
|
||||
if (mPrimaryActionItems.size() == 0 &&
|
||||
mPrimaryActionItemBar instanceof DefaultActionItemBar) {
|
||||
// Reset the adapter before adding the header view to a list.
|
||||
setAdapter(null);
|
||||
addHeaderView((DefaultActionItemBar) mPrimaryActionItemBar);
|
||||
setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
if (added = mPrimaryActionItemBar.addActionItem(actionView)) {
|
||||
mPrimaryActionItems.put(menuItem, actionView);
|
||||
mItems.add(menuItem);
|
||||
}
|
||||
} else if (actionEnum == GeckoMenuItem.SHOW_AS_ACTION_IF_ROOM) {
|
||||
if (mSecondaryActionItems.size() == 0) {
|
||||
// Reset the adapter before adding the header view to a list.
|
||||
setAdapter(null);
|
||||
addHeaderView((DefaultActionItemBar) mSecondaryActionItemBar);
|
||||
setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
if (added = mSecondaryActionItemBar.addActionItem(actionView)) {
|
||||
mSecondaryActionItems.put(menuItem, actionView);
|
||||
mItems.add(menuItem);
|
||||
}
|
||||
} else if (actionEnum == GeckoMenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) {
|
||||
if (actionView instanceof MenuItemSwitcherLayout) {
|
||||
final MenuItemSwitcherLayout quickShareView = (MenuItemSwitcherLayout) actionView;
|
||||
|
||||
// We don't want to add the quick share bar if we don't have any quick share items.
|
||||
if (quickShareView.getActionButtonCount() > 0 &&
|
||||
(added = mQuickShareActionItemBar.addActionItem(quickShareView))) {
|
||||
if (mQuickShareActionItems.size() == 0) {
|
||||
// Reset the adapter before adding the header view to a list.
|
||||
setAdapter(null);
|
||||
addHeaderView((DefaultActionItemBar) mQuickShareActionItemBar);
|
||||
setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
mQuickShareActionItems.put(menuItem, quickShareView);
|
||||
mItems.add(menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the listeners.
|
||||
if (actionView instanceof MenuItemActionBar) {
|
||||
((MenuItemActionBar) actionView).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
handleMenuItemClick(menuItem);
|
||||
}
|
||||
});
|
||||
((MenuItemActionBar) actionView).setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
if (handleMenuItemLongClick(menuItem)) {
|
||||
GeckoAppShell.vibrateOnHapticFeedbackEnabled(getResources().getIntArray(R.array.long_press_vibrate_msec));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} else if (actionView instanceof MenuItemSwitcherLayout) {
|
||||
((MenuItemSwitcherLayout) actionView).setMenuItemClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
handleMenuItemClick(menuItem);
|
||||
}
|
||||
});
|
||||
((MenuItemSwitcherLayout) actionView).setMenuItemLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
if (handleMenuItemLongClick(menuItem)) {
|
||||
GeckoAppShell.vibrateOnHapticFeedbackEnabled(getResources().getIntArray(R.array.long_press_vibrate_msec));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
@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);
|
||||
return addSubMenu(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
|
||||
MenuItem menuItem = add(groupId, itemId, order, titleRes);
|
||||
return addSubMenu(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(CharSequence title) {
|
||||
MenuItem menuItem = add(title);
|
||||
return addSubMenu(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int titleRes) {
|
||||
MenuItem menuItem = add(titleRes);
|
||||
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;
|
||||
}
|
||||
|
||||
private void removePrimaryActionBarView() {
|
||||
// Reset the adapter before removing the header view from a list.
|
||||
setAdapter(null);
|
||||
removeHeaderView((DefaultActionItemBar) mPrimaryActionItemBar);
|
||||
setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
private void removeSecondaryActionBarView() {
|
||||
// Reset the adapter before removing the header view from a list.
|
||||
setAdapter(null);
|
||||
removeHeaderView((DefaultActionItemBar) mSecondaryActionItemBar);
|
||||
setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
private void removeQuickShareActionBarView() {
|
||||
// Reset the adapter before removing the header view from a list.
|
||||
setAdapter(null);
|
||||
removeHeaderView((DefaultActionItemBar) mQuickShareActionItemBar);
|
||||
setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
assertOnUiThread();
|
||||
for (GeckoMenuItem menuItem : mItems) {
|
||||
if (menuItem.hasSubMenu()) {
|
||||
SubMenu sub = menuItem.getSubMenu();
|
||||
if (sub == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
sub.clear();
|
||||
} catch (Exception ex) {
|
||||
Log.e(LOGTAG, "Couldn't clear submenu.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mAdapter.clear();
|
||||
mItems.clear();
|
||||
|
||||
/*
|
||||
* Reinflating the menu will re-add any action items to the toolbar, so
|
||||
* remove the old ones. This also ensures that any text associated with
|
||||
* these is switched to the correct locale.
|
||||
*/
|
||||
if (mPrimaryActionItemBar != null) {
|
||||
for (View item : mPrimaryActionItems.values()) {
|
||||
mPrimaryActionItemBar.removeActionItem(item);
|
||||
}
|
||||
}
|
||||
mPrimaryActionItems.clear();
|
||||
|
||||
if (mSecondaryActionItemBar != null) {
|
||||
for (View item : mSecondaryActionItems.values()) {
|
||||
mSecondaryActionItemBar.removeActionItem(item);
|
||||
}
|
||||
}
|
||||
mSecondaryActionItems.clear();
|
||||
|
||||
if (mQuickShareActionItemBar != null) {
|
||||
for (View item : mQuickShareActionItems.values()) {
|
||||
mQuickShareActionItemBar.removeActionItem(item);
|
||||
}
|
||||
}
|
||||
mQuickShareActionItems.clear();
|
||||
|
||||
// Remove the view, too -- the first addActionItem will re-add it,
|
||||
// and this is simpler than changing that logic.
|
||||
if (mPrimaryActionItemBar instanceof DefaultActionItemBar) {
|
||||
removePrimaryActionBarView();
|
||||
}
|
||||
|
||||
removeSecondaryActionBarView();
|
||||
removeQuickShareActionBarView();
|
||||
}
|
||||
|
||||
@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) {
|
||||
assertOnUiThread();
|
||||
MenuItem quickItem = mItemsById.get(id);
|
||||
if (quickItem != null) {
|
||||
return quickItem;
|
||||
}
|
||||
|
||||
for (GeckoMenuItem menuItem : mItems) {
|
||||
if (menuItem.getItemId() == id) {
|
||||
mItemsById.put(id, menuItem);
|
||||
return menuItem;
|
||||
} else if (menuItem.hasSubMenu()) {
|
||||
if (!menuItem.hasActionProvider()) {
|
||||
SubMenu subMenu = menuItem.getSubMenu();
|
||||
MenuItem item = subMenu.findItem(id);
|
||||
if (item != null) {
|
||||
mItemsById.put(id, item);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem getItem(int index) {
|
||||
if (index < mItems.size())
|
||||
return mItems.get(index);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasVisibleItems() {
|
||||
assertOnUiThread();
|
||||
for (GeckoMenuItem menuItem : mItems) {
|
||||
if (menuItem.isVisible() &&
|
||||
!mPrimaryActionItems.containsKey(menuItem) &&
|
||||
!mSecondaryActionItems.containsKey(menuItem) &&
|
||||
!mQuickShareActionItems.containsKey(menuItem))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
// Close the menu if it is open and the hardware menu key is pressed.
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU && isShown()) {
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShortcutKey(int keyCode, KeyEvent event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performIdentifierAction(int id, int flags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(int groupId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(int id) {
|
||||
assertOnUiThread();
|
||||
GeckoMenuItem item = (GeckoMenuItem) findItem(id);
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
// Remove it from the cache.
|
||||
mItemsById.remove(id);
|
||||
|
||||
// Remove it from any sub-menu.
|
||||
for (GeckoMenuItem menuItem : mItems) {
|
||||
if (menuItem.hasSubMenu()) {
|
||||
SubMenu subMenu = menuItem.getSubMenu();
|
||||
if (subMenu != null && subMenu.findItem(id) != null) {
|
||||
subMenu.removeItem(id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove it from own menu.
|
||||
if (mPrimaryActionItems.containsKey(item)) {
|
||||
if (mPrimaryActionItemBar != null)
|
||||
mPrimaryActionItemBar.removeActionItem(mPrimaryActionItems.get(item));
|
||||
|
||||
mPrimaryActionItems.remove(item);
|
||||
mItems.remove(item);
|
||||
|
||||
if (mPrimaryActionItems.size() == 0 &&
|
||||
mPrimaryActionItemBar instanceof DefaultActionItemBar) {
|
||||
removePrimaryActionBarView();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSecondaryActionItems.containsKey(item)) {
|
||||
if (mSecondaryActionItemBar != null)
|
||||
mSecondaryActionItemBar.removeActionItem(mSecondaryActionItems.get(item));
|
||||
|
||||
mSecondaryActionItems.remove(item);
|
||||
mItems.remove(item);
|
||||
|
||||
if (mSecondaryActionItems.size() == 0) {
|
||||
removeSecondaryActionBarView();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (mQuickShareActionItems.containsKey(item)) {
|
||||
if (mQuickShareActionItemBar != null)
|
||||
mQuickShareActionItemBar.removeActionItem(mQuickShareActionItems.get(item));
|
||||
|
||||
mQuickShareActionItems.remove(item);
|
||||
mItems.remove(item);
|
||||
|
||||
if (mQuickShareActionItems.size() == 0) {
|
||||
removeQuickShareActionBarView();
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupVisible(int group, boolean visible) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQwertyMode(boolean isQwerty) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionItemBar() {
|
||||
return (mPrimaryActionItemBar != null) &&
|
||||
(mSecondaryActionItemBar != null) &&
|
||||
(mQuickShareActionItemBar != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowAsActionChanged(GeckoMenuItem item) {
|
||||
removeItem(item.getItemId());
|
||||
|
||||
if (item.isActionItem() && addActionItem(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
addItem(item);
|
||||
}
|
||||
|
||||
public void onItemChanged(GeckoMenuItem item) {
|
||||
assertOnUiThread();
|
||||
if (item.isActionItem()) {
|
||||
final View actionView;
|
||||
final int actionEnum = item.getActionEnum();
|
||||
if (actionEnum == GeckoMenuItem.SHOW_AS_ACTION_ALWAYS) {
|
||||
actionView = mPrimaryActionItems.get(item);
|
||||
} else if (actionEnum == GeckoMenuItem.SHOW_AS_ACTION_IF_ROOM) {
|
||||
actionView = mSecondaryActionItems.get(item);
|
||||
} else {
|
||||
actionView = mQuickShareActionItems.get(item);
|
||||
}
|
||||
|
||||
if (actionView != null) {
|
||||
if (item.isVisible()) {
|
||||
actionView.setVisibility(View.VISIBLE);
|
||||
if (actionView instanceof MenuItemActionBar) {
|
||||
((MenuItemActionBar) actionView).initialize(item);
|
||||
} else {
|
||||
((MenuItemSwitcherLayout) actionView).initialize(item);
|
||||
}
|
||||
} 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);
|
||||
handleMenuItemClick(item);
|
||||
}
|
||||
|
||||
void handleMenuItemClick(GeckoMenuItem item) {
|
||||
if (!item.isEnabled())
|
||||
return;
|
||||
|
||||
if (item.invoke()) {
|
||||
close();
|
||||
} else if (item.hasSubMenu()) {
|
||||
// Refresh the submenu for the provider.
|
||||
GeckoActionProvider provider = item.getGeckoActionProvider();
|
||||
if (provider != null) {
|
||||
GeckoSubMenu subMenu = new GeckoSubMenu(getContext());
|
||||
subMenu.setShowIcons(true);
|
||||
provider.onPrepareSubMenu(subMenu);
|
||||
item.setSubMenu(subMenu);
|
||||
}
|
||||
|
||||
// Show the submenu.
|
||||
GeckoSubMenu subMenu = (GeckoSubMenu) item.getSubMenu();
|
||||
showMenu(subMenu);
|
||||
} else {
|
||||
close();
|
||||
mCallback.onMenuItemClick(item);
|
||||
}
|
||||
}
|
||||
|
||||
boolean handleMenuItemLongClick(GeckoMenuItem item) {
|
||||
if (!item.isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mCallback != null) {
|
||||
if (mCallback.onMenuItemLongClick(item)) {
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Callback getCallback() {
|
||||
return mCallback;
|
||||
}
|
||||
|
||||
public MenuPresenter getMenuPresenter() {
|
||||
return mMenuPresenter;
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
mCallback = callback;
|
||||
|
||||
// Update the submenus just in case this changes on the fly.
|
||||
for (GeckoMenuItem menuItem : mItems) {
|
||||
if (menuItem.hasSubMenu()) {
|
||||
GeckoSubMenu subMenu = (GeckoSubMenu) menuItem.getSubMenu();
|
||||
subMenu.setCallback(mCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setMenuPresenter(MenuPresenter presenter) {
|
||||
mMenuPresenter = presenter;
|
||||
|
||||
// Update the submenus just in case this changes on the fly.
|
||||
for (GeckoMenuItem menuItem : mItems) {
|
||||
if (menuItem.hasSubMenu()) {
|
||||
GeckoSubMenu subMenu = (GeckoSubMenu) menuItem.getSubMenu();
|
||||
subMenu.setMenuPresenter(mMenuPresenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setActionItemBarPresenter(ActionItemBarPresenter presenter) {
|
||||
mPrimaryActionItemBar = presenter;
|
||||
}
|
||||
|
||||
public void setShowIcons(boolean show) {
|
||||
if (mShowIcons != show) {
|
||||
mShowIcons = show;
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
public static class DefaultActionItemBar extends LinearLayout
|
||||
implements ActionItemBarPresenter {
|
||||
private final int mRowHeight;
|
||||
private float mWeightSum;
|
||||
|
||||
public DefaultActionItemBar(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public DefaultActionItemBar(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
mRowHeight = getResources().getDimensionPixelSize(R.dimen.menu_item_row_height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addActionItem(View actionItem) {
|
||||
ViewGroup.LayoutParams actualParams = actionItem.getLayoutParams();
|
||||
LinearLayout.LayoutParams params;
|
||||
|
||||
if (actualParams != null) {
|
||||
params = new LinearLayout.LayoutParams(actionItem.getLayoutParams());
|
||||
params.width = 0;
|
||||
} else {
|
||||
params = new LinearLayout.LayoutParams(0, mRowHeight);
|
||||
}
|
||||
|
||||
if (actionItem instanceof MenuItemSwitcherLayout) {
|
||||
params.weight = ((MenuItemSwitcherLayout) actionItem).getChildCount();
|
||||
} else {
|
||||
params.weight = 1.0f;
|
||||
}
|
||||
|
||||
mWeightSum += params.weight;
|
||||
|
||||
actionItem.setLayoutParams(params);
|
||||
addView(actionItem);
|
||||
setWeightSum(mWeightSum);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeActionItem(View actionItem) {
|
||||
if (indexOfChild(actionItem) != -1) {
|
||||
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) actionItem.getLayoutParams();
|
||||
mWeightSum -= params.weight;
|
||||
removeView(actionItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adapter to bind menu items to the list.
|
||||
private class MenuItemsAdapter extends BaseAdapter {
|
||||
private static final int VIEW_TYPE_DEFAULT = 0;
|
||||
private static final int VIEW_TYPE_ACTION_MODE = 1;
|
||||
|
||||
private final List<GeckoMenuItem> mItems;
|
||||
|
||||
public MenuItemsAdapter() {
|
||||
mItems = new ArrayList<GeckoMenuItem>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
if (mItems == null)
|
||||
return 0;
|
||||
|
||||
int visibleCount = 0;
|
||||
for (GeckoMenuItem item : mItems) {
|
||||
if (item.isVisible())
|
||||
visibleCount++;
|
||||
}
|
||||
|
||||
return visibleCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeckoMenuItem getItem(int 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) {
|
||||
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 MenuItemSwitcherLayout) {
|
||||
// Always get from the menu item.
|
||||
// This will ensure that the default activity is refreshed.
|
||||
view = (MenuItemSwitcherLayout) 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);
|
||||
((MenuItemSwitcherLayout) 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.setShowIcon(mShowIcons);
|
||||
view.initialize(item);
|
||||
return (View) view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return getItem(position).getGeckoActionProvider() == null ? VIEW_TYPE_DEFAULT : VIEW_TYPE_ACTION_MODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areAllItemsEnabled() {
|
||||
// Setting this to true is a workaround to fix disappearing
|
||||
// dividers in the menu (bug 963249).
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
// Setting this to true is a workaround to fix disappearing
|
||||
// dividers in the menu in L (bug 1050780).
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addMenuItem(GeckoMenuItem menuItem) {
|
||||
if (mItems.contains(menuItem))
|
||||
return;
|
||||
|
||||
// Insert it in proper order.
|
||||
int index = 0;
|
||||
for (GeckoMenuItem item : mItems) {
|
||||
if (item.getOrder() > menuItem.getOrder()) {
|
||||
mItems.add(index, menuItem);
|
||||
notifyDataSetChanged();
|
||||
return;
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the menuItem at the end.
|
||||
mItems.add(menuItem);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void removeMenuItem(GeckoMenuItem menuItem) {
|
||||
// Remove it from the list.
|
||||
mItems.remove(menuItem);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mItemsById.clear();
|
||||
mItems.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public GeckoMenuItem getMenuItem(int id) {
|
||||
for (GeckoMenuItem item : mItems) {
|
||||
if (item.getItemId() == id)
|
||||
return item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
/* 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 java.io.IOException;
|
||||
|
||||
import org.mozilla.gecko.AppConstants.Versions;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Xml;
|
||||
import android.view.InflateException;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
|
||||
public class GeckoMenuInflater extends MenuInflater {
|
||||
private static final String TAG_MENU = "menu";
|
||||
private static final String TAG_ITEM = "item";
|
||||
private static final int NO_ID = 0;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
// Private class to hold the parsed menu item.
|
||||
private class ParsedItem {
|
||||
public int id;
|
||||
public int order;
|
||||
public CharSequence title;
|
||||
public int iconRes;
|
||||
public boolean checkable;
|
||||
public boolean checked;
|
||||
public boolean visible;
|
||||
public boolean enabled;
|
||||
public int showAsAction;
|
||||
public boolean hasSubMenu;
|
||||
}
|
||||
|
||||
public GeckoMenuInflater(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inflate(int menuRes, Menu menu) {
|
||||
|
||||
// This does not check for a well-formed XML.
|
||||
|
||||
XmlResourceParser parser = null;
|
||||
try {
|
||||
parser = mContext.getResources().getXml(menuRes);
|
||||
AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
|
||||
parseMenu(parser, attrs, menu);
|
||||
|
||||
} catch (XmlPullParserException | IOException e) {
|
||||
throw new InflateException("Error inflating menu XML", e);
|
||||
} finally {
|
||||
if (parser != null)
|
||||
parser.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void parseMenu(XmlResourceParser parser, AttributeSet attrs, Menu menu)
|
||||
throws XmlPullParserException, IOException {
|
||||
ParsedItem item = null;
|
||||
|
||||
String tag;
|
||||
int eventType = parser.getEventType();
|
||||
|
||||
do {
|
||||
tag = parser.getName();
|
||||
|
||||
switch (eventType) {
|
||||
case XmlPullParser.START_TAG:
|
||||
if (tag.equals(TAG_ITEM)) {
|
||||
// Parse the menu item.
|
||||
item = new ParsedItem();
|
||||
parseItem(item, attrs);
|
||||
} else if (tag.equals(TAG_MENU)) {
|
||||
if (item != null) {
|
||||
// Add the submenu item.
|
||||
SubMenu subMenu = menu.addSubMenu(NO_ID, item.id, item.order, item.title);
|
||||
item.hasSubMenu = true;
|
||||
|
||||
// Set the menu item in main menu.
|
||||
MenuItem menuItem = subMenu.getItem();
|
||||
setValues(item, menuItem);
|
||||
|
||||
// Start parsing the sub menu.
|
||||
parseMenu(parser, attrs, subMenu);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case XmlPullParser.END_TAG:
|
||||
if (parser.getName().equals(TAG_ITEM)) {
|
||||
if (!item.hasSubMenu) {
|
||||
// Add the item.
|
||||
MenuItem menuItem = menu.add(NO_ID, item.id, item.order, item.title);
|
||||
setValues(item, menuItem);
|
||||
}
|
||||
} else if (tag.equals(TAG_MENU)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
eventType = parser.next();
|
||||
|
||||
} while (eventType != XmlPullParser.END_DOCUMENT);
|
||||
}
|
||||
|
||||
public void parseItem(ParsedItem item, AttributeSet attrs) {
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.MenuItem);
|
||||
|
||||
item.id = a.getResourceId(R.styleable.MenuItem_android_id, NO_ID);
|
||||
item.order = a.getInt(R.styleable.MenuItem_android_orderInCategory, 0);
|
||||
item.title = a.getText(R.styleable.MenuItem_android_title);
|
||||
item.checkable = a.getBoolean(R.styleable.MenuItem_android_checkable, false);
|
||||
item.checked = a.getBoolean(R.styleable.MenuItem_android_checked, false);
|
||||
item.visible = a.getBoolean(R.styleable.MenuItem_android_visible, true);
|
||||
item.enabled = a.getBoolean(R.styleable.MenuItem_android_enabled, true);
|
||||
item.hasSubMenu = false;
|
||||
item.iconRes = a.getResourceId(R.styleable.MenuItem_android_icon, 0);
|
||||
item.showAsAction = a.getInt(R.styleable.MenuItem_android_showAsAction, 0);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public void setValues(ParsedItem item, MenuItem menuItem) {
|
||||
// We are blocking any presenter updates during inflation.
|
||||
GeckoMenuItem geckoItem = null;
|
||||
if (menuItem instanceof GeckoMenuItem) {
|
||||
geckoItem = (GeckoMenuItem) menuItem;
|
||||
}
|
||||
|
||||
if (geckoItem != null) {
|
||||
geckoItem.stopDispatchingChanges();
|
||||
}
|
||||
|
||||
menuItem.setChecked(item.checked)
|
||||
.setVisible(item.visible)
|
||||
.setEnabled(item.enabled)
|
||||
.setCheckable(item.checkable)
|
||||
.setIcon(item.iconRes);
|
||||
|
||||
menuItem.setShowAsAction(item.showAsAction);
|
||||
|
||||
if (geckoItem != null) {
|
||||
// We don't need to allow presenter updates during inflation,
|
||||
// so we use the weak form of re-enabling changes.
|
||||
geckoItem.resumeDispatchingChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,472 @@
|
|||
/* 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.util.ResourceDrawableUtils;
|
||||
import org.mozilla.gecko.widget.GeckoActionProvider;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.ActionProvider;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
|
||||
public class GeckoMenuItem implements MenuItem {
|
||||
private static final int SHARE_BAR_HISTORY_SIZE = 2;
|
||||
|
||||
// These values mirror MenuItem values that are only available on API >= 11.
|
||||
public static final int SHOW_AS_ACTION_NEVER = 0;
|
||||
public static final int SHOW_AS_ACTION_IF_ROOM = 1;
|
||||
public static final int SHOW_AS_ACTION_ALWAYS = 2;
|
||||
public static final int SHOW_AS_ACTION_WITH_TEXT = 4;
|
||||
public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8;
|
||||
|
||||
// A View that can show a MenuItem should be able to initialize from
|
||||
// the properties of the MenuItem.
|
||||
public static interface Layout {
|
||||
public void initialize(GeckoMenuItem item);
|
||||
public void setShowIcon(boolean show);
|
||||
}
|
||||
|
||||
public static interface OnShowAsActionChangedListener {
|
||||
public boolean hasActionItemBar();
|
||||
public void onShowAsActionChanged(GeckoMenuItem item);
|
||||
}
|
||||
|
||||
private final int mId;
|
||||
private final int mOrder;
|
||||
private View mActionView;
|
||||
private int mActionEnum;
|
||||
private CharSequence mTitle;
|
||||
private CharSequence mTitleCondensed;
|
||||
private boolean mCheckable;
|
||||
private boolean mChecked;
|
||||
private boolean mVisible = true;
|
||||
private boolean mEnabled = true;
|
||||
private Drawable mIcon;
|
||||
private int mIconRes;
|
||||
private GeckoActionProvider mActionProvider;
|
||||
private GeckoSubMenu mSubMenu;
|
||||
private MenuItem.OnMenuItemClickListener mMenuItemClickListener;
|
||||
final GeckoMenu mMenu;
|
||||
OnShowAsActionChangedListener mShowAsActionChangedListener;
|
||||
|
||||
private volatile boolean mShouldDispatchChanges = true;
|
||||
private volatile boolean mDidChange;
|
||||
|
||||
public GeckoMenuItem(GeckoMenu menu, int id, int order, int titleRes) {
|
||||
mMenu = menu;
|
||||
mId = id;
|
||||
mOrder = order;
|
||||
mTitle = mMenu.getResources().getString(titleRes);
|
||||
}
|
||||
|
||||
public GeckoMenuItem(GeckoMenu menu, int id, int order, CharSequence title) {
|
||||
mMenu = menu;
|
||||
mId = id;
|
||||
mOrder = order;
|
||||
mTitle = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop dispatching item changed events to presenters until
|
||||
* [start|resume]DispatchingItemsChanged() is called. Useful when
|
||||
* many menu operations are going to be performed as a batch.
|
||||
*/
|
||||
public void stopDispatchingChanges() {
|
||||
mDidChange = false;
|
||||
mShouldDispatchChanges = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume dispatching item changed events to presenters. This method
|
||||
* will NOT call onItemChanged if any menu operations were queued.
|
||||
* Only future menu operations will call onItemChanged. Useful for
|
||||
* sequelching presenter updates.
|
||||
*/
|
||||
public void resumeDispatchingChanges() {
|
||||
mShouldDispatchChanges = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start dispatching item changed events to presenters. This method
|
||||
* will call onItemChanged if any menu operations were queued.
|
||||
*/
|
||||
public void startDispatchingChanges() {
|
||||
if (mDidChange) {
|
||||
mMenu.onItemChanged(this);
|
||||
}
|
||||
mShouldDispatchChanges = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasActionProvider() {
|
||||
return (mActionProvider != null);
|
||||
}
|
||||
|
||||
public int getActionEnum() {
|
||||
return mActionEnum;
|
||||
}
|
||||
|
||||
public GeckoActionProvider getGeckoActionProvider() {
|
||||
return mActionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProvider getActionProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getActionView() {
|
||||
if (mActionProvider != null) {
|
||||
return mActionProvider.onCreateActionView(SHARE_BAR_HISTORY_SIZE,
|
||||
GeckoActionProvider.ActionViewType.DEFAULT);
|
||||
}
|
||||
|
||||
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 ResourceDrawableUtils.getDrawable(mMenu.getContext(), mIconRes);
|
||||
else
|
||||
return null;
|
||||
} else {
|
||||
return mIcon;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextMenu.ContextMenuInfo getMenuInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getNumericShortcut() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return mOrder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu getSubMenu() {
|
||||
return mSubMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitleCondensed() {
|
||||
return mTitleCondensed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
if (mActionProvider != null)
|
||||
return mActionProvider.hasSubMenu();
|
||||
|
||||
return (mSubMenu != null);
|
||||
}
|
||||
|
||||
public boolean isActionItem() {
|
||||
return (mActionEnum > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionViewExpanded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckable() {
|
||||
return mCheckable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return mChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return mVisible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setActionProvider(GeckoActionProvider actionProvider) {
|
||||
mActionProvider = actionProvider;
|
||||
if (mActionProvider != null) {
|
||||
actionProvider.setOnTargetSelectedListener(new GeckoActionProvider.OnTargetSelectedListener() {
|
||||
@Override
|
||||
public void onTargetSelected() {
|
||||
mMenu.close();
|
||||
|
||||
// Refresh the menu item to show the high frequency apps.
|
||||
mShowAsActionChangedListener.onShowAsActionChanged(GeckoMenuItem.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mShowAsActionChangedListener.onShowAsActionChanged(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(int resId) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(View view) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setCheckable(boolean checkable) {
|
||||
if (mCheckable != checkable) {
|
||||
mCheckable = checkable;
|
||||
if (mShouldDispatchChanges) {
|
||||
mMenu.onItemChanged(this);
|
||||
} else {
|
||||
mDidChange = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setChecked(boolean checked) {
|
||||
if (mChecked != checked) {
|
||||
mChecked = checked;
|
||||
if (mShouldDispatchChanges) {
|
||||
mMenu.onItemChanged(this);
|
||||
} else {
|
||||
mDidChange = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setEnabled(boolean enabled) {
|
||||
if (mEnabled != enabled) {
|
||||
mEnabled = enabled;
|
||||
if (mShouldDispatchChanges) {
|
||||
mMenu.onItemChanged(this);
|
||||
} else {
|
||||
mDidChange = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIcon(Drawable icon) {
|
||||
if (mIcon != icon) {
|
||||
mIcon = icon;
|
||||
if (mShouldDispatchChanges) {
|
||||
mMenu.onItemChanged(this);
|
||||
} else {
|
||||
mDidChange = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIcon(int iconRes) {
|
||||
if (mIconRes != iconRes) {
|
||||
mIconRes = iconRes;
|
||||
if (mShouldDispatchChanges) {
|
||||
mMenu.onItemChanged(this);
|
||||
} else {
|
||||
mDidChange = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIntent(Intent intent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setNumericShortcut(char numericChar) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(MenuItem.OnActionExpandListener listener) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener menuItemClickListener) {
|
||||
mMenuItemClickListener = menuItemClickListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowAsAction(int actionEnum) {
|
||||
setShowAsAction(actionEnum, 0);
|
||||
}
|
||||
|
||||
public void setShowAsAction(int actionEnum, int style) {
|
||||
if (mShowAsActionChangedListener == null)
|
||||
return;
|
||||
|
||||
if (mActionEnum == actionEnum)
|
||||
return;
|
||||
|
||||
if (actionEnum > 0) {
|
||||
if (!mShowAsActionChangedListener.hasActionItemBar())
|
||||
return;
|
||||
|
||||
if (!hasActionProvider()) {
|
||||
// Change the type to just an icon
|
||||
MenuItemActionBar actionView;
|
||||
if (style != 0) {
|
||||
actionView = new MenuItemActionBar(mMenu.getContext(), null, style);
|
||||
} else {
|
||||
if (actionEnum == SHOW_AS_ACTION_ALWAYS) {
|
||||
actionView = new MenuItemActionBar(mMenu.getContext());
|
||||
} else {
|
||||
actionView = new MenuItemActionBar(mMenu.getContext(), null, R.attr.menuItemSecondaryActionBarStyle);
|
||||
}
|
||||
}
|
||||
|
||||
actionView.initialize(this);
|
||||
mActionView = actionView;
|
||||
}
|
||||
|
||||
mActionEnum = actionEnum;
|
||||
}
|
||||
|
||||
mShowAsActionChangedListener.onShowAsActionChanged(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int actionEnum) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setSubMenu(GeckoSubMenu subMenu) {
|
||||
mSubMenu = subMenu;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitle(CharSequence title) {
|
||||
if (!TextUtils.equals(mTitle, title)) {
|
||||
mTitle = title;
|
||||
if (mShouldDispatchChanges) {
|
||||
mMenu.onItemChanged(this);
|
||||
} else {
|
||||
mDidChange = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitle(int title) {
|
||||
CharSequence newTitle = mMenu.getResources().getString(title);
|
||||
return setTitle(newTitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitleCondensed(CharSequence title) {
|
||||
mTitleCondensed = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setVisible(boolean visible) {
|
||||
// Action views are not normal menu items and visibility can get out
|
||||
// of sync unless we dispatch whenever required.
|
||||
if (isActionItem() || mVisible != visible) {
|
||||
mVisible = visible;
|
||||
if (mShouldDispatchChanges) {
|
||||
mMenu.onItemChanged(this);
|
||||
} else {
|
||||
mDidChange = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean invoke() {
|
||||
if (mMenuItemClickListener != null)
|
||||
return mMenuItemClickListener.onMenuItemClick(this);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setOnShowAsActionChangedListener(OnShowAsActionChangedListener listener) {
|
||||
mShowAsActionChangedListener = listener;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/* 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 android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
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";
|
||||
|
||||
// MenuItem associated with this submenu.
|
||||
private MenuItem mMenuItem;
|
||||
|
||||
public GeckoSubMenu(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public GeckoSubMenu(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public GeckoSubMenu(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearHeader() {
|
||||
}
|
||||
|
||||
public SubMenu setMenuItem(MenuItem item) {
|
||||
mMenuItem = item;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem getItem() {
|
||||
return mMenuItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderIcon(Drawable icon) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderIcon(int iconRes) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderTitle(CharSequence title) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderTitle(int titleRes) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderView(View view) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setIcon(Drawable icon) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setIcon(int iconRes) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/* 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.util.ResourceDrawableUtils;
|
||||
import org.mozilla.gecko.widget.themed.ThemedImageButton;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
public class MenuItemActionBar extends ThemedImageButton
|
||||
implements GeckoMenuItem.Layout {
|
||||
private static final String LOGTAG = "GeckoMenuItemActionBar";
|
||||
|
||||
public MenuItemActionBar(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public MenuItemActionBar(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.menuItemActionBarStyle);
|
||||
}
|
||||
|
||||
public MenuItemActionBar(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(GeckoMenuItem item) {
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
setIcon(item.getIcon());
|
||||
setTitle(item.getTitle());
|
||||
setEnabled(item.isEnabled());
|
||||
setId(item.getItemId());
|
||||
}
|
||||
|
||||
void setIcon(Drawable icon) {
|
||||
if (icon == null) {
|
||||
setVisibility(GONE);
|
||||
} else {
|
||||
setVisibility(VISIBLE);
|
||||
setImageDrawable(icon);
|
||||
}
|
||||
}
|
||||
|
||||
void setIcon(int icon) {
|
||||
setIcon((icon == 0) ? null : ResourceDrawableUtils.getDrawable(getContext(), icon));
|
||||
}
|
||||
|
||||
void setTitle(CharSequence title) {
|
||||
// set accessibility contentDescription here
|
||||
setContentDescription(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowIcon(boolean show) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
/* 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.util.ResourceDrawableUtils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
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 };
|
||||
|
||||
private Drawable mIcon;
|
||||
private final Drawable mState;
|
||||
private static Rect sIconBounds;
|
||||
|
||||
private boolean mCheckable;
|
||||
private boolean mChecked;
|
||||
private boolean mHasSubMenu;
|
||||
private boolean mShowIcon;
|
||||
|
||||
public MenuItemDefault(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public MenuItemDefault(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.menuItemDefaultStyle);
|
||||
}
|
||||
|
||||
public MenuItemDefault(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
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);
|
||||
|
||||
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).mutate();
|
||||
mState.setBounds(stateIconBounds);
|
||||
|
||||
if (sIconBounds == null) {
|
||||
int iconSize = res.getDimensionPixelSize(R.dimen.menu_item_icon);
|
||||
sIconBounds = new Rect(0, 0, iconSize, iconSize);
|
||||
}
|
||||
|
||||
setCompoundDrawables(mIcon, null, mState, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] onCreateDrawableState(int extraSpace) {
|
||||
final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
|
||||
|
||||
if (mHasSubMenu)
|
||||
mergeDrawableStates(drawableState, STATE_MORE);
|
||||
else if (mCheckable && mChecked)
|
||||
mergeDrawableStates(drawableState, STATE_CHECKED);
|
||||
else if (mCheckable && !mChecked)
|
||||
mergeDrawableStates(drawableState, STATE_UNCHECKED);
|
||||
|
||||
return drawableState;
|
||||
}
|
||||
|
||||
@Override
|
||||
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());
|
||||
}
|
||||
|
||||
private void refreshIcon() {
|
||||
setCompoundDrawables(mShowIcon ? mIcon : null, null, mState, null);
|
||||
}
|
||||
|
||||
void setIcon(Drawable icon) {
|
||||
mIcon = icon;
|
||||
|
||||
if (mIcon != null) {
|
||||
mIcon.setBounds(sIconBounds);
|
||||
mIcon.setAlpha(isEnabled() ? 255 : 99);
|
||||
}
|
||||
|
||||
refreshIcon();
|
||||
}
|
||||
|
||||
void setIcon(int icon) {
|
||||
setIcon((icon == 0) ? null : ResourceDrawableUtils.getDrawable(getContext(), icon));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void setCheckable(boolean checkable) {
|
||||
if (mCheckable != checkable) {
|
||||
mCheckable = checkable;
|
||||
refreshDrawableState();
|
||||
}
|
||||
}
|
||||
|
||||
private void setChecked(boolean checked) {
|
||||
if (mChecked != checked) {
|
||||
mChecked = checked;
|
||||
refreshDrawableState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowIcon(boolean show) {
|
||||
if (mShowIcon != show) {
|
||||
mShowIcon = show;
|
||||
refreshIcon();
|
||||
}
|
||||
}
|
||||
|
||||
void setSubMenuIndicator(boolean hasSubMenu) {
|
||||
if (mHasSubMenu != hasSubMenu) {
|
||||
mHasSubMenu = hasSubMenu;
|
||||
refreshDrawableState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
/* 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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
/**
|
||||
* This class is a container view for menu items that:
|
||||
* * Shows text if there is enough space and there are
|
||||
* no action buttons ({@link #mActionButtons}).
|
||||
* * Shows an icon if there is not enough space for text,
|
||||
* or there are action buttons.
|
||||
*/
|
||||
public class MenuItemSwitcherLayout extends LinearLayout
|
||||
implements GeckoMenuItem.Layout,
|
||||
View.OnClickListener {
|
||||
private final MenuItemDefault mMenuItem;
|
||||
private final MenuItemActionBar mMenuButton;
|
||||
private final List<ImageButton> mActionButtons;
|
||||
private final List<View.OnClickListener> mActionButtonListeners = new ArrayList<View.OnClickListener>();
|
||||
|
||||
public MenuItemSwitcherLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public MenuItemSwitcherLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.menuItemSwitcherLayoutStyle);
|
||||
}
|
||||
|
||||
@TargetApi(14)
|
||||
public MenuItemSwitcherLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs);
|
||||
|
||||
LayoutInflater.from(context).inflate(R.layout.menu_item_switcher_layout, this);
|
||||
mMenuItem = (MenuItemDefault) findViewById(R.id.menu_item);
|
||||
mMenuButton = (MenuItemActionBar) findViewById(R.id.menu_item_button);
|
||||
mActionButtons = new ArrayList<ImageButton>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
final int width = right - left;
|
||||
|
||||
final View parent = (View) getParent();
|
||||
final int parentPadding = parent.getPaddingLeft() + parent.getPaddingRight();
|
||||
final int horizontalSpaceAvailableInParent = parent.getMeasuredWidth() - parentPadding;
|
||||
|
||||
// Check if there is another View sharing horizontal
|
||||
// space with this View in the parent.
|
||||
if (width < horizontalSpaceAvailableInParent || mActionButtons.size() != 0) {
|
||||
// Use the icon.
|
||||
mMenuItem.setVisibility(View.GONE);
|
||||
mMenuButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
// Use the button.
|
||||
mMenuItem.setVisibility(View.VISIBLE);
|
||||
mMenuButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(GeckoMenuItem item) {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMenuItem.initialize(item);
|
||||
mMenuButton.initialize(item);
|
||||
setEnabled(item.isEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
mMenuItem.setEnabled(enabled);
|
||||
mMenuButton.setEnabled(enabled);
|
||||
|
||||
for (ImageButton button : mActionButtons) {
|
||||
button.setEnabled(enabled);
|
||||
button.setAlpha(enabled ? 255 : 99);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMenuItemClickListener(View.OnClickListener listener) {
|
||||
mMenuItem.setOnClickListener(listener);
|
||||
mMenuButton.setOnClickListener(listener);
|
||||
}
|
||||
|
||||
public void setMenuItemLongClickListener(View.OnLongClickListener listener) {
|
||||
mMenuItem.setOnLongClickListener(listener);
|
||||
mMenuButton.setOnLongClickListener(listener);
|
||||
}
|
||||
|
||||
public void addActionButtonClickListener(View.OnClickListener listener) {
|
||||
mActionButtonListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowIcon(boolean show) {
|
||||
mMenuItem.setShowIcon(show);
|
||||
}
|
||||
|
||||
public void setIcon(Drawable icon) {
|
||||
mMenuItem.setIcon(icon);
|
||||
mMenuButton.setIcon(icon);
|
||||
}
|
||||
|
||||
public void setIcon(int icon) {
|
||||
mMenuItem.setIcon(icon);
|
||||
mMenuButton.setIcon(icon);
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
mMenuItem.setTitle(title);
|
||||
mMenuButton.setContentDescription(title);
|
||||
}
|
||||
|
||||
public void setSubMenuIndicator(boolean hasSubMenu) {
|
||||
mMenuItem.setSubMenuIndicator(hasSubMenu);
|
||||
}
|
||||
|
||||
public void addActionButton(Drawable drawable, CharSequence label) {
|
||||
// If this is the first icon, retain the text.
|
||||
// If not, make the menu item an icon.
|
||||
final int count = mActionButtons.size();
|
||||
mMenuItem.setVisibility(View.GONE);
|
||||
mMenuButton.setVisibility(View.VISIBLE);
|
||||
|
||||
if (drawable != null) {
|
||||
ImageButton button = new ImageButton(getContext(), null, R.attr.menuItemSecondaryActionBarStyle);
|
||||
button.setImageDrawable(drawable);
|
||||
button.setContentDescription(label);
|
||||
button.setOnClickListener(this);
|
||||
button.setTag(count);
|
||||
|
||||
final int height = (int) (getResources().getDimension(R.dimen.menu_item_row_height));
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, height);
|
||||
params.weight = 1.0f;
|
||||
button.setLayoutParams(params);
|
||||
|
||||
// Place action buttons to the right of the actual menu item
|
||||
mActionButtons.add(button);
|
||||
addView(button, count + 1);
|
||||
}
|
||||
}
|
||||
|
||||
protected int getActionButtonCount() {
|
||||
return mActionButtons.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
for (View.OnClickListener listener : mActionButtonListeners) {
|
||||
listener.onClick(view);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the styles if this view is being used in the context menus.
|
||||
*
|
||||
* Ideally, we just use different layout files and styles to set this, but
|
||||
* MenuItemSwitcherLayout is too integrated into GeckoActionProvider to provide
|
||||
* an easy separation so instead I provide this hack. I'm sorry.
|
||||
*/
|
||||
public void initContextMenuStyles() {
|
||||
final int defaultContextMenuPadding = getContext().getResources().getDimensionPixelOffset(
|
||||
R.dimen.context_menu_item_horizontal_padding);
|
||||
mMenuItem.setPadding(defaultContextMenuPadding, getPaddingTop(),
|
||||
defaultContextMenuPadding, getPaddingBottom());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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.AppConstants.Versions;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
/**
|
||||
* The outer container for the custom menu. On phones with h/w menu button,
|
||||
* this is given to Android which inflates it to the right panel. On phones
|
||||
* with s/w menu button, this is added to a MenuPopup.
|
||||
*/
|
||||
public class MenuPanel extends LinearLayout {
|
||||
public MenuPanel(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
int width = (int) context.getResources().getDimension(R.dimen.menu_item_row_width);
|
||||
setLayoutParams(new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchPopulateAccessibilityEvent (AccessibilityEvent event) {
|
||||
onPopulateAccessibilityEvent(event);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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.AppConstants;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.support.v7.widget.CardView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.PopupWindow;
|
||||
|
||||
/**
|
||||
* A popup to show the inflated MenuPanel.
|
||||
*/
|
||||
public class MenuPopup extends PopupWindow {
|
||||
private final CardView mPanel;
|
||||
|
||||
private final int mPopupWidth;
|
||||
|
||||
public MenuPopup(Context context) {
|
||||
super(context);
|
||||
|
||||
setFocusable(true);
|
||||
|
||||
mPopupWidth = context.getResources().getDimensionPixelSize(R.dimen.menu_popup_width);
|
||||
|
||||
// Setting a null background makes the popup to not close on touching outside.
|
||||
setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
mPanel = (CardView) inflater.inflate(R.layout.menu_popup, null);
|
||||
setContentView(mPanel);
|
||||
|
||||
setAnimationStyle(R.style.PopupAnimation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the panel with the menu to its content.
|
||||
*
|
||||
* @param view The panel view with the menu to be shown.
|
||||
*/
|
||||
public void setPanelView(View view) {
|
||||
view.setLayoutParams(new FrameLayout.LayoutParams(mPopupWidth,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT));
|
||||
|
||||
mPanel.removeAllViews();
|
||||
mPanel.addView(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* A small little offset.
|
||||
*/
|
||||
@Override
|
||||
public void showAsDropDown(View anchor) {
|
||||
// Set a height, so that the popup will not be displayed below the bottom of the screen.
|
||||
// We use the exact height of the internal content, which is the technique described in
|
||||
// http://stackoverflow.com/a/7698709
|
||||
setHeight(mPanel.getHeight());
|
||||
|
||||
// Attempt to align the center of the popup with the center of the anchor. If the anchor is
|
||||
// near the edge of the screen, the popup will just align with the edge of the screen.
|
||||
final int xOffset = anchor.getWidth() / 2 - mPopupWidth / 2;
|
||||
showAsDropDown(anchor, xOffset, -anchor.getHeight());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue