Merge "Add Cascading submenus implementation."

This commit is contained in:
Oren Blasberg
2015-09-10 16:58:01 +00:00
committed by Android (Google) Code Review
9 changed files with 564 additions and 141 deletions

View File

@@ -85,6 +85,8 @@ public class ActionMenuPresenter extends BaseMenuPresenter
private OpenOverflowRunnable mPostedOpenRunnable;
private ActionMenuPopupCallback mPopupCallback;
private final boolean mShowCascadingMenus;
final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
int mOpenSubMenuId;
@@ -126,6 +128,9 @@ public class ActionMenuPresenter extends BaseMenuPresenter
public ActionMenuPresenter(Context context) {
super(context, com.android.internal.R.layout.action_menu_layout,
com.android.internal.R.layout.action_menu_item_layout);
mShowCascadingMenus = context.getResources().getBoolean(
com.android.internal.R.bool.config_enableCascadingSubmenus);
}
@Override
@@ -500,14 +505,29 @@ public class ActionMenuPresenter extends BaseMenuPresenter
}
View anchor = findViewForItem(topSubMenu.getItem());
if (anchor == null) {
if (mOverflowButton == null) return false;
anchor = mOverflowButton;
// This means the submenu was opened from an overflow menu item, indicating the
// MenuPopupHelper will handle opening the submenu via its MenuPopup. Return false to
// ensure that the MenuPopup acts as presenter for the submenu, and acts on its
// responsibility to display the new submenu.
return false;
}
mOpenSubMenuId = subMenu.getItem().getItemId();
mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu);
mActionButtonPopup.setAnchorView(anchor);
boolean preserveIconSpacing = false;
final int count = subMenu.size();
for (int i = 0; i < count; i++) {
MenuItem childItem = subMenu.getItem(i);
if (childItem.isVisible() && childItem.getIcon() != null) {
preserveIconSpacing = true;
break;
}
}
mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu, anchor);
mActionButtonPopup.setForceShowIcon(preserveIconSpacing);
mActionButtonPopup.show();
super.onSubMenuSelected(subMenu);
return true;
}
@@ -926,12 +946,9 @@ public class ActionMenuPresenter extends BaseMenuPresenter
}
private class ActionButtonSubmenu extends MenuPopupHelper {
private SubMenuBuilder mSubMenu;
public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
super(context, subMenu, null, false,
public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu, View anchorView) {
super(context, subMenu, anchorView, false,
com.android.internal.R.attr.actionOverflowMenuStyle);
mSubMenu = subMenu;
MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
if (!item.isActionButton()) {
@@ -940,17 +957,6 @@ public class ActionMenuPresenter extends BaseMenuPresenter
}
setCallback(mPopupPresenterCallback);
boolean preserveIconSpacing = false;
final int count = subMenu.size();
for (int i = 0; i < count; i++) {
MenuItem childItem = subMenu.getItem(i);
if (childItem.isVisible() && childItem.getIcon() != null) {
preserveIconSpacing = true;
break;
}
}
setForceShowIcon(preserveIconSpacing);
}
@Override

View File

@@ -25,10 +25,8 @@ import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.IntProperty;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.TextView;
import android.widget.ListView;
@@ -128,6 +126,61 @@ public class DropDownListView extends ListView {
setCacheColorHint(0); // Transparent, since the background drawable could be anything.
}
@Override
protected boolean shouldShowSelector() {
View selectedView = getSelectedView();
return selectedView != null && selectedView.isEnabled() || super.shouldShowSelector();
}
protected void clearSelection() {
setSelectedPositionInt(-1);
setNextSelectedPositionInt(-1);
}
@Override
public boolean onHoverEvent(MotionEvent ev) {
final int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_HOVER_ENTER
|| action == MotionEvent.ACTION_HOVER_MOVE) {
final int position = pointToPosition((int) ev.getX(), (int) ev.getY());
if (position != INVALID_POSITION && position != mSelectedPosition) {
final View hoveredItem = getChildAt(position - getFirstVisiblePosition());
if (hoveredItem.isEnabled()) {
// Force a focus so that the proper selector state gets used when we update.
requestFocus();
positionSelector(position, hoveredItem);
setSelectedPositionInt(position);
setNextSelectedPositionInt(position);
}
updateSelectorState();
}
} else {
// Do not cancel the selected position if the selection is visible by other reasons.
if (!super.shouldShowSelector()) {
setSelectedPositionInt(INVALID_POSITION);
}
}
return super.onHoverEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
final int position = pointToPosition(x, y);
if (position == INVALID_POSITION) {
return super.onTouchEvent(event);
}
if (position != mSelectedPosition) {
setSelectedPositionInt(position);
setNextSelectedPositionInt(position);
}
return super.onTouchEvent(event);
}
/**
* Handles forwarded events.
*

View File

@@ -69,7 +69,6 @@ public class ListPopupWindow implements ShowableListMenu {
private static final int EXPAND_LIST_TIMEOUT = 250;
private Context mContext;
private PopupWindow mPopup;
private ListAdapter mAdapter;
private DropDownListView mDropDownList;
@@ -112,6 +111,8 @@ public class ListPopupWindow implements ShowableListMenu {
private int mLayoutDirection;
PopupWindow mPopup;
/**
* The provided prompt view should appear above list content.
*

View File

@@ -17,10 +17,17 @@
package android.widget;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.transition.Transition;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.KeyEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.view.ViewGroup;
import android.view.ViewParent;
import com.android.internal.view.menu.ListMenuItemView;
import com.android.internal.view.menu.MenuAdapter;
/**
* A MenuPopupWindow represents the popup window for menu.
@@ -40,52 +47,58 @@ public class MenuPopupWindow extends ListPopupWindow {
return new MenuDropDownListView(context, hijackFocus);
}
static class MenuDropDownListView extends DropDownListView {
private boolean mHoveredOnDisabledItem = false;
private AccessibilityManager mAccessibilityManager;
MenuDropDownListView(Context context, boolean hijackFocus) {
super(context, hijackFocus);
mAccessibilityManager = (AccessibilityManager) getContext().getSystemService(
Context.ACCESSIBILITY_SERVICE);
}
@Override
protected boolean shouldShowSelector() {
return (isHovered() && !mHoveredOnDisabledItem) || super.shouldShowSelector();
}
@Override
public boolean onHoverEvent(MotionEvent ev) {
mHoveredOnDisabledItem = false;
// Accessibility system should already handle hover events and selections, menu does
// not have to handle it by itself.
if (mAccessibilityManager.isTouchExplorationEnabled()) {
return super.onHoverEvent(ev);
}
final int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_HOVER_ENTER
|| action == MotionEvent.ACTION_HOVER_MOVE) {
final int position = pointToPosition((int) ev.getX(), (int) ev.getY());
if (position != INVALID_POSITION && position != mSelectedPosition) {
final View hoveredItem = getChildAt(position - getFirstVisiblePosition());
if (hoveredItem.isEnabled()) {
positionSelector(position, hoveredItem);
setSelectedPositionInt(position);
} else {
mHoveredOnDisabledItem = true;
}
updateSelectorState();
}
} else {
// Do not cancel the selected position if the selection is visible by other reasons.
if (!super.shouldShowSelector()) {
setSelectedPositionInt(INVALID_POSITION);
}
}
return super.onHoverEvent(ev);
}
public void setEnterTransition(Transition enterTransition) {
mPopup.setEnterTransition(enterTransition);
}
}
/**
* Set whether this window is touch modal or if outside touches will be sent to
* other windows behind it.
*/
public void setTouchModal(boolean touchModal) {
mPopup.setTouchModal(touchModal);
}
private static class MenuDropDownListView extends DropDownListView {
final int mAdvanceKey;
final int mRetreatKey;
public MenuDropDownListView(Context context, boolean hijackFocus) {
super(context, hijackFocus);
final Resources res = context.getResources();
final Configuration config = res.getConfiguration();
if (config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
mAdvanceKey = KeyEvent.KEYCODE_DPAD_LEFT;
mRetreatKey = KeyEvent.KEYCODE_DPAD_RIGHT;
} else {
mAdvanceKey = KeyEvent.KEYCODE_DPAD_RIGHT;
mRetreatKey = KeyEvent.KEYCODE_DPAD_LEFT;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
ListMenuItemView selectedItem = (ListMenuItemView) getSelectedView();
if (selectedItem != null && keyCode == mAdvanceKey) {
if (selectedItem.isEnabled() &&
((ListMenuItemView) selectedItem).getItemData().hasSubMenu()) {
performItemClick(
selectedItem,
getSelectedItemPosition(),
getSelectedItemId());
}
return true;
} else if (selectedItem != null && keyCode == mRetreatKey) {
setSelectedPositionInt(-1);
setNextSelectedPositionInt(-1);
((MenuAdapter) getAdapter()).getAdapterMenu().close();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
}

View File

@@ -43,6 +43,7 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
private final MenuBuilder mMenu;
private final View mAnchor;
private final MenuPopupHelper mPopup;
private final boolean mShowCascadingMenus;
private OnMenuItemClickListener mMenuItemClickListener;
private OnDismissListener mDismissListener;
@@ -107,6 +108,8 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
public PopupMenu(Context context, View anchor, int gravity, int popupStyleAttr,
int popupStyleRes) {
mContext = context;
mShowCascadingMenus = context.getResources().getBoolean(
com.android.internal.R.bool.config_enableCascadingSubmenus);
mMenu = new MenuBuilder(context);
mMenu.setCallback(this);
mAnchor = anchor;
@@ -273,8 +276,12 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
return true;
}
// Current menu will be dismissed by the normal helper, submenu will be shown in its place.
new MenuPopupHelper(mContext, subMenu, mAnchor).show();
if (!mShowCascadingMenus) {
// Current menu will be dismissed by the normal helper, submenu will be shown in its
// place. (If cascading menus are enabled, the cascading implementation will show the
// submenu itself).
new MenuPopupHelper(mContext, subMenu, mAnchor).show();
}
return true;
}

View File

@@ -0,0 +1,394 @@
package com.android.internal.view.menu;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Parcelable;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.AdapterView;
import android.widget.DropDownListView;
import android.widget.ListView;
import android.widget.MenuPopupWindow;
import android.widget.PopupWindow;
import android.widget.PopupWindow.OnDismissListener;
import com.android.internal.util.Preconditions;
/**
* A popup for a menu which will allow multiple submenus to appear in a cascading fashion, side by
* side.
* @hide
*/
final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemClickListener,
MenuPresenter, OnKeyListener, PopupWindow.OnDismissListener {
@Retention(RetentionPolicy.SOURCE)
@IntDef({HORIZ_POSITION_LEFT, HORIZ_POSITION_RIGHT})
public @interface HorizPosition {}
private static final int HORIZ_POSITION_LEFT = 0;
private static final int HORIZ_POSITION_RIGHT = 1;
private final Context mContext;
private final int mMenuMaxWidth;
private final int mPopupStyleAttr;
private final int mPopupStyleRes;
private final boolean mOverflowOnly;
private final int mLayoutDirection;
private int mDropDownGravity = Gravity.NO_GRAVITY;
private View mAnchor;
private List<DropDownListView> mListViews;
private List<MenuPopupWindow> mPopupWindows;
private List<int[]> mOffsets;
private int mPreferredPosition;
private boolean mForceShowIcon;
private Callback mPresenterCallback;
private PopupWindow.OnDismissListener mOnDismissListener;
/**
* Initializes a new cascading-capable menu popup.
*
* @param parent A parent view to get the {@link android.view.View#getWindowToken()} token from.
*/
public CascadingMenuPopup(Context context, View anchor, int popupStyleAttr,
int popupStyleRes, boolean overflowOnly) {
mContext = Preconditions.checkNotNull(context);
mAnchor = Preconditions.checkNotNull(anchor);
mPopupStyleAttr = popupStyleAttr;
mPopupStyleRes = popupStyleRes;
mOverflowOnly = overflowOnly;
mForceShowIcon = false;
final Resources res = context.getResources();
final Configuration config = res.getConfiguration();
mLayoutDirection = config.getLayoutDirection();
mPreferredPosition = mLayoutDirection == View.LAYOUT_DIRECTION_RTL ? HORIZ_POSITION_LEFT :
HORIZ_POSITION_RIGHT;
mMenuMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
mPopupWindows = new ArrayList<MenuPopupWindow>();
mListViews = new ArrayList<DropDownListView>();
mOffsets = new ArrayList<int[]>();
}
@Override
public void setForceShowIcon(boolean forceShow) {
mForceShowIcon = forceShow;
}
private MenuPopupWindow createPopupWindow() {
MenuPopupWindow popupWindow = new MenuPopupWindow(
mContext, null, mPopupStyleAttr, mPopupStyleRes);
popupWindow.setOnItemClickListener(this);
popupWindow.setOnDismissListener(this);
popupWindow.setAnchorView(mAnchor);
popupWindow.setDropDownGravity(mDropDownGravity);
popupWindow.setModal(true);
popupWindow.setTouchModal(false);
return popupWindow;
}
@Override
public void show() {
if (isShowing()) {
return;
}
// Show any menus that have been added via #addMenu(MenuBuilder) but which have not yet been
// shown.
// In a typical use case, #addMenu(MenuBuilder) would be called once, followed by a call to
// this #show() method -- which would actually show the popup on the screen.
for (int i = 0; i < mPopupWindows.size(); i++) {
MenuPopupWindow popupWindow = mPopupWindows.get(i);
popupWindow.show();
mListViews.add((DropDownListView) popupWindow.getListView());
}
}
@Override
public void dismiss() {
// Need to make another list to avoid a concurrent modification exception, as #onDismiss
// may clear mPopupWindows while we are iterating.
List<MenuPopupWindow> popupWindows = new ArrayList<MenuPopupWindow>(mPopupWindows);
for (MenuPopupWindow popupWindow : popupWindows) {
if (popupWindow != null && popupWindow.isShowing()) {
popupWindow.dismiss();
}
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
MenuAdapter adapter = (MenuAdapter) parent.getAdapter();
adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
dismiss();
return true;
}
return false;
}
/**
* Determines whether the next submenu (of the given width) should display on the right or on
* the left of the most recent menu.
*
* @param nextMenuWidth Width of the next submenu to display.
* @return The position to display it.
*/
@HorizPosition
private int getNextMenuPosition(int nextMenuWidth) {
ListView lastListView = mListViews.get(mListViews.size() - 1);
final int[] screenLocation = new int[2];
lastListView.getLocationOnScreen(screenLocation);
final Rect displayFrame = new Rect();
mAnchor.getWindowVisibleDisplayFrame(displayFrame);
if (mPreferredPosition == HORIZ_POSITION_RIGHT) {
final int right = screenLocation[0] + lastListView.getWidth() + nextMenuWidth;
if (right > displayFrame.right) {
return HORIZ_POSITION_LEFT;
}
return HORIZ_POSITION_RIGHT;
} else { // LEFT
final int left = screenLocation[0] - nextMenuWidth;
if (left < 0) {
return HORIZ_POSITION_RIGHT;
}
return HORIZ_POSITION_LEFT;
}
}
@Override
public void addMenu(MenuBuilder menu) {
boolean addSubMenu = mListViews.size() > 0;
menu.addMenuPresenter(this, mContext);
MenuPopupWindow popupWindow = createPopupWindow();
MenuAdapter adapter = new MenuAdapter(menu, LayoutInflater.from(mContext), mOverflowOnly);
adapter.setForceShowIcon(mForceShowIcon);
popupWindow.setAdapter(adapter);
int menuWidth = measureIndividualMenuWidth(adapter, null, mContext, mMenuMaxWidth);
int x = 0;
int y = 0;
if (addSubMenu) {
popupWindow.setEnterTransition(null);
ListView lastListView = mListViews.get(mListViews.size() - 1);
@HorizPosition int nextMenuPosition = getNextMenuPosition(menuWidth);
boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
mPreferredPosition = nextMenuPosition;
int[] lastLocation = new int[2];
lastListView.getLocationOnScreen(lastLocation);
int[] lastOffset = mOffsets.get(mOffsets.size() - 1);
// Note: By now, mDropDownGravity is the absolute gravity, so this should work in both
// LTR and RTL.
if ((mDropDownGravity & Gravity.RIGHT) == Gravity.RIGHT) {
if (showOnRight) {
x = lastOffset[0] + menuWidth;
} else {
x = lastOffset[0] - lastListView.getWidth();
}
} else {
if (showOnRight) {
x = lastOffset[0] + lastListView.getWidth();
} else {
x = lastOffset[0] - menuWidth;
}
}
y = lastOffset[1] + lastListView.getSelectedView().getTop() -
lastListView.getChildAt(0).getTop();
}
popupWindow.setWidth(menuWidth);
popupWindow.setHorizontalOffset(x);
popupWindow.setVerticalOffset(y);
mPopupWindows.add(popupWindow);
// NOTE: This case handles showing submenus once the CascadingMenuPopup has already
// been shown via a call to its #show() method. If it hasn't yet been show()n, then
// we deliberately do not yet show the popupWindow, as #show() will do that later.
if (isShowing()) {
popupWindow.show();
mListViews.add((DropDownListView) popupWindow.getListView());
}
int[] offsets = {x, y};
mOffsets.add(offsets);
}
/**
* @return {@code true} if the popup is currently showing, {@code false} otherwise.
*/
@Override
public boolean isShowing() {
return mPopupWindows.size() > 0 && mPopupWindows.get(0).isShowing();
}
/**
* Called when one or more of the popup windows was dismissed.
*/
@Override
public void onDismiss() {
int dismissedIndex = -1;
for (int i = 0; i < mPopupWindows.size(); i++) {
if (!mPopupWindows.get(i).isShowing()) {
dismissedIndex = i;
break;
}
}
if (dismissedIndex != -1) {
for (int i = dismissedIndex; i < mListViews.size(); i++) {
ListView view = mListViews.get(i);
MenuAdapter adapter = (MenuAdapter) view.getAdapter();
adapter.mAdapterMenu.close();
}
}
}
@Override
public void updateMenuView(boolean cleared) {
for (ListView view : mListViews) {
((MenuAdapter) view.getAdapter()).notifyDataSetChanged();
}
}
@Override
public void setCallback(Callback cb) {
mPresenterCallback = cb;
}
@Override
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
// Don't allow double-opening of the same submenu.
for (ListView view : mListViews) {
if (((MenuAdapter) view.getAdapter()).mAdapterMenu.equals(subMenu)) {
// Just re-focus that one.
view.requestFocus();
return true;
}
}
if (subMenu.hasVisibleItems()) {
this.addMenu(subMenu);
if (mPresenterCallback != null) {
mPresenterCallback.onOpenSubMenu(subMenu);
}
return true;
}
return false;
}
@Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
int menuIndex = -1;
boolean wasSelected = false;
for (int i = 0; i < mListViews.size(); i++) {
ListView view = mListViews.get(i);
MenuAdapter adapter = (MenuAdapter) view.getAdapter();
if (menuIndex == -1 && menu == adapter.mAdapterMenu) {
menuIndex = i;
wasSelected = view.getSelectedItem() != null;
}
// Once the menu has been found, remove it and all submenus beneath it from the
// container view. Also remove the presenter.
if (menuIndex != -1) {
adapter.mAdapterMenu.removeMenuPresenter(this);
}
}
// Then, actually remove the views for these [sub]menu(s) from our list of views.
if (menuIndex != -1) {
for (int i = menuIndex; i < mPopupWindows.size(); i++) {
mPopupWindows.get(i).dismiss();
}
mPopupWindows.subList(menuIndex, mPopupWindows.size()).clear();
mListViews.subList(menuIndex, mListViews.size()).clear();
mOffsets.subList(menuIndex, mOffsets.size()).clear();
// If there's still a menu open, refocus the new leaf [sub]menu.
if (mListViews.size() > 0) {
mListViews.get(mListViews.size() - 1).requestFocus();
}
}
if (mListViews.size() == 0 || wasSelected) {
dismiss();
if (mPresenterCallback != null) {
mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
}
}
if (mPopupWindows.size() == 0) {
// If every [sub]menu was dismissed, that means the whole thing was dismissed, so notify
// the owner.
mOnDismissListener.onDismiss();
}
}
@Override
public boolean flagActionItems() {
return false;
}
@Override
public Parcelable onSaveInstanceState() {
return null;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
}
@Override
public void setGravity(int dropDownGravity) {
mDropDownGravity = Gravity.getAbsoluteGravity(dropDownGravity, mLayoutDirection);
}
@Override
public void setAnchorView(View anchor) {
mAnchor = anchor;
}
@Override
public void setOnDismissListener(OnDismissListener listener) {
mOnDismissListener = listener;
}
@Override
public ListView getListView() {
return mListViews.size() > 0 ? mListViews.get(mListViews.size() - 1) : null;
}
}

View File

@@ -64,6 +64,7 @@ public class MenuBuilder implements Menu {
private final Context mContext;
private final Resources mResources;
private final boolean mShowCascadingMenus;
/**
* Whether the shortcuts should be qwerty-accessible. Use isQwertyMode()
@@ -186,6 +187,8 @@ public class MenuBuilder implements Menu {
public MenuBuilder(Context context) {
mContext = context;
mResources = context.getResources();
mShowCascadingMenus = context.getResources().getBoolean(
com.android.internal.R.bool.config_enableCascadingSubmenus);
mItems = new ArrayList<MenuItemImpl>();
@@ -909,7 +912,9 @@ public class MenuBuilder implements Menu {
invoked |= itemImpl.expandActionView();
if (invoked) close(true);
} else if (itemImpl.hasSubMenu() || providerHasSubMenu) {
close(false);
if (!mShowCascadingMenus) {
close(false);
}
if (!itemImpl.hasSubMenu()) {
itemImpl.setSubMenu(new SubMenuBuilder(getContext(), this, itemImpl));

View File

@@ -35,9 +35,11 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter {
public abstract void setForceShowIcon(boolean forceShow);
/**
* Adds the given menu to the popup. If this is the first menu shown it'll be displayed; if it's
* a submenu it will be displayed adjacent to the most recent menu (if supported by the
* implementation).
* Adds the given menu to the popup, if it is capable of displaying submenus within itself.
* If menu is the first menu shown, it won't be displayed until show() is called.
* If the popup was already showing, adding a submenu via this method will cause that new
* submenu to be shown immediately (that is, if this MenuPopup implementation is capable of
* showing its own submenus).
*
* @param menu
*/

View File

@@ -17,10 +17,8 @@
package com.android.internal.view.menu;
import android.content.Context;
import android.os.Parcelable;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.PopupWindow;
@@ -30,7 +28,7 @@ import android.widget.PopupWindow;
* @hide
*/
public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
PopupWindow.OnDismissListener, View.OnAttachStateChangeListener, MenuPresenter {
PopupWindow.OnDismissListener, View.OnAttachStateChangeListener {
private final Context mContext;
private final MenuBuilder mMenu;
private final boolean mOverflowOnly;
@@ -70,9 +68,8 @@ public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
private MenuPopup createMenuPopup() {
if (mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableCascadingSubmenus)) {
// TODO: Return a Cascading implementation of MenuPopup instead.
return new StandardMenuPopup(
mContext, mMenu, mAnchorView, mPopupStyleAttr, mPopupStyleRes, mOverflowOnly);
return new CascadingMenuPopup(mContext, mAnchorView, mPopupStyleAttr, mPopupStyleRes,
mOverflowOnly);
}
return new StandardMenuPopup(
mContext, mMenu, mAnchorView, mPopupStyleAttr, mPopupStyleRes, mOverflowOnly);
@@ -187,62 +184,7 @@ public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
v.removeOnAttachStateChangeListener(this);
}
@Override
public void initForMenu(Context context, MenuBuilder menu) {
// Don't need to do anything; we added as a presenter in the constructor.
}
@Override
public MenuView getMenuView(ViewGroup root) {
throw new UnsupportedOperationException("MenuPopupHelpers manage their own views");
}
@Override
public void updateMenuView(boolean cleared) {
mPopup.updateMenuView(cleared);
}
@Override
public void setCallback(Callback cb) {
public void setCallback(MenuPresenter.Callback cb) {
mPopup.setCallback(cb);
}
@Override
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
return mPopup.onSubMenuSelected(subMenu);
}
@Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
mPopup.onCloseMenu(menu, allMenusAreClosing);
}
@Override
public boolean flagActionItems() {
return false;
}
@Override
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
return false;
}
@Override
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
return false;
}
@Override
public int getId() {
return 0;
}
@Override
public Parcelable onSaveInstanceState() {
return null;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
}
}