OSDN Git Service

Show alternate menu panel on devices with menu key
[android-x86/frameworks-base.git] / core / java / com / android / internal / view / menu / ActionMenuPresenter.java
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.internal.view.menu;
18
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.content.res.Resources;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.util.SparseBooleanArray;
25 import android.view.ActionProvider;
26 import android.view.MenuItem;
27 import android.view.MotionEvent;
28 import android.view.SoundEffectConstants;
29 import android.view.View;
30 import android.view.ViewConfiguration;
31 import android.view.View.MeasureSpec;
32 import android.view.accessibility.AccessibilityNodeInfo;
33 import android.view.ViewGroup;
34 import android.widget.ImageButton;
35 import android.widget.ListPopupWindow;
36 import android.widget.ListPopupWindow.ForwardingListener;
37
38 import com.android.internal.view.ActionBarPolicy;
39 import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView;
40
41 import java.util.ArrayList;
42
43 /**
44  * MenuPresenter for building action menus as seen in the action bar and action modes.
45  */
46 public class ActionMenuPresenter extends BaseMenuPresenter
47         implements ActionProvider.SubUiVisibilityListener {
48     private static final String TAG = "ActionMenuPresenter";
49
50     private View mOverflowButton;
51     private boolean mReserveOverflow;
52     private boolean mReserveOverflowSet;
53     private int mWidthLimit;
54     private int mActionItemWidthLimit;
55     private int mMaxItems;
56     private boolean mMaxItemsSet;
57     private boolean mStrictWidthLimit;
58     private boolean mWidthLimitSet;
59     private boolean mExpandedActionViewsExclusive;
60
61     private int mMinCellSize;
62
63     // Group IDs that have been added as actions - used temporarily, allocated here for reuse.
64     private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
65
66     private View mScrapActionButtonView;
67
68     private OverflowPopup mOverflowPopup;
69     private ActionButtonSubmenu mActionButtonPopup;
70
71     private OpenOverflowRunnable mPostedOpenRunnable;
72
73     final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
74     int mOpenSubMenuId;
75
76     public ActionMenuPresenter(Context context) {
77         super(context, com.android.internal.R.layout.action_menu_layout,
78                 com.android.internal.R.layout.action_menu_item_layout);
79     }
80
81     @Override
82     public void initForMenu(Context context, MenuBuilder menu) {
83         super.initForMenu(context, menu);
84
85         final Resources res = context.getResources();
86
87         final ActionBarPolicy abp = ActionBarPolicy.get(context);
88         if (!mReserveOverflowSet) {
89             mReserveOverflow = abp.showsOverflowMenuButton();
90         }
91
92         if (!mWidthLimitSet) {
93             mWidthLimit = abp.getEmbeddedMenuWidthLimit();
94         }
95
96         // Measure for initial configuration
97         if (!mMaxItemsSet) {
98             mMaxItems = abp.getMaxActionButtons();
99         }
100
101         int width = mWidthLimit;
102         if (mReserveOverflow) {
103             if (mOverflowButton == null) {
104                 mOverflowButton = new OverflowMenuButton(mSystemContext);
105                 final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
106                 mOverflowButton.measure(spec, spec);
107             }
108             width -= mOverflowButton.getMeasuredWidth();
109         } else {
110             mOverflowButton = null;
111         }
112
113         mActionItemWidthLimit = width;
114
115         mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density);
116
117         // Drop a scrap view as it may no longer reflect the proper context/config.
118         mScrapActionButtonView = null;
119     }
120
121     public void onConfigurationChanged(Configuration newConfig) {
122         if (!mMaxItemsSet) {
123             mMaxItems = mContext.getResources().getInteger(
124                     com.android.internal.R.integer.max_action_buttons);
125         }
126         if (mMenu != null) {
127             mMenu.onItemsChanged(true);
128         }
129     }
130
131     public void setWidthLimit(int width, boolean strict) {
132         mWidthLimit = width;
133         mStrictWidthLimit = strict;
134         mWidthLimitSet = true;
135     }
136
137     public void setReserveOverflow(boolean reserveOverflow) {
138         mReserveOverflow = reserveOverflow;
139         mReserveOverflowSet = true;
140     }
141
142     public void setItemLimit(int itemCount) {
143         mMaxItems = itemCount;
144         mMaxItemsSet = true;
145     }
146
147     public void setExpandedActionViewsExclusive(boolean isExclusive) {
148         mExpandedActionViewsExclusive = isExclusive;
149     }
150
151     @Override
152     public MenuView getMenuView(ViewGroup root) {
153         MenuView result = super.getMenuView(root);
154         ((ActionMenuView) result).setPresenter(this);
155         return result;
156     }
157
158     @Override
159     public View getItemView(final MenuItemImpl item, View convertView, ViewGroup parent) {
160         View actionView = item.getActionView();
161         if (actionView == null || item.hasCollapsibleActionView()) {
162             if (!(convertView instanceof ActionMenuItemView)) {
163                 convertView = null;
164             }
165             actionView = super.getItemView(item, convertView, parent);
166         }
167         actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
168
169         if (item.hasSubMenu()) {
170             actionView.setOnTouchListener(new ForwardingListener(actionView) {
171                 @Override
172                 public ListPopupWindow getPopup() {
173                     return mActionButtonPopup != null ? mActionButtonPopup.getPopup() : null;
174                 }
175
176                 @Override
177                 protected boolean onForwardingStarted() {
178                     return onSubMenuSelected((SubMenuBuilder) item.getSubMenu());
179                 }
180
181                 @Override
182                 protected boolean onForwardingStopped() {
183                     return dismissPopupMenus();
184                 }
185             });
186         } else {
187             actionView.setOnTouchListener(null);
188         }
189
190         final ActionMenuView menuParent = (ActionMenuView) parent;
191         final ViewGroup.LayoutParams lp = actionView.getLayoutParams();
192         if (!menuParent.checkLayoutParams(lp)) {
193             actionView.setLayoutParams(menuParent.generateLayoutParams(lp));
194         }
195         return actionView;
196     }
197
198     @Override
199     public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) {
200         itemView.initialize(item, 0);
201
202         final ActionMenuView menuView = (ActionMenuView) mMenuView;
203         ActionMenuItemView actionItemView = (ActionMenuItemView) itemView;
204         actionItemView.setItemInvoker(menuView);
205     }
206
207     @Override
208     public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
209         return item.isActionButton();
210     }
211
212     @Override
213     public void updateMenuView(boolean cleared) {
214         super.updateMenuView(cleared);
215
216         if (mMenu != null) {
217             final ArrayList<MenuItemImpl> actionItems = mMenu.getActionItems();
218             final int count = actionItems.size();
219             for (int i = 0; i < count; i++) {
220                 final ActionProvider provider = actionItems.get(i).getActionProvider();
221                 if (provider != null) {
222                     provider.setSubUiVisibilityListener(this);
223                 }
224             }
225         }
226
227         final ArrayList<MenuItemImpl> nonActionItems = mMenu != null ?
228                 mMenu.getNonActionItems() : null;
229
230         boolean hasOverflow = false;
231         if (mReserveOverflow && nonActionItems != null) {
232             final int count = nonActionItems.size();
233             if (count == 1) {
234                 hasOverflow = !nonActionItems.get(0).isActionViewExpanded();
235             } else {
236                 hasOverflow = count > 0;
237             }
238         }
239
240         if (hasOverflow) {
241             if (mOverflowButton == null) {
242                 mOverflowButton = new OverflowMenuButton(mSystemContext);
243             }
244             ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
245             if (parent != mMenuView) {
246                 if (parent != null) {
247                     parent.removeView(mOverflowButton);
248                 }
249                 ActionMenuView menuView = (ActionMenuView) mMenuView;
250                 menuView.addView(mOverflowButton, menuView.generateOverflowButtonLayoutParams());
251             }
252         } else if (mOverflowButton != null && mOverflowButton.getParent() == mMenuView) {
253             ((ViewGroup) mMenuView).removeView(mOverflowButton);
254         }
255
256         ((ActionMenuView) mMenuView).setOverflowReserved(mReserveOverflow);
257     }
258
259     @Override
260     public boolean filterLeftoverView(ViewGroup parent, int childIndex) {
261         if (parent.getChildAt(childIndex) == mOverflowButton) return false;
262         return super.filterLeftoverView(parent, childIndex);
263     }
264
265     public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
266         if (!subMenu.hasVisibleItems()) return false;
267
268         SubMenuBuilder topSubMenu = subMenu;
269         while (topSubMenu.getParentMenu() != mMenu) {
270             topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu();
271         }
272         View anchor = findViewForItem(topSubMenu.getItem());
273         if (anchor == null) {
274             if (mOverflowButton == null) return false;
275             anchor = mOverflowButton;
276         }
277
278         mOpenSubMenuId = subMenu.getItem().getItemId();
279         mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu);
280         mActionButtonPopup.setAnchorView(anchor);
281         mActionButtonPopup.show();
282         super.onSubMenuSelected(subMenu);
283         return true;
284     }
285
286     private View findViewForItem(MenuItem item) {
287         final ViewGroup parent = (ViewGroup) mMenuView;
288         if (parent == null) return null;
289
290         final int count = parent.getChildCount();
291         for (int i = 0; i < count; i++) {
292             final View child = parent.getChildAt(i);
293             if (child instanceof MenuView.ItemView &&
294                     ((MenuView.ItemView) child).getItemData() == item) {
295                 return child;
296             }
297         }
298         return null;
299     }
300
301     /**
302      * Display the overflow menu if one is present.
303      * @return true if the overflow menu was shown, false otherwise.
304      */
305     public boolean showOverflowMenu() {
306         if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
307                 mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) {
308             OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
309             mPostedOpenRunnable = new OpenOverflowRunnable(popup);
310             // Post this for later; we might still need a layout for the anchor to be right.
311             ((View) mMenuView).post(mPostedOpenRunnable);
312
313             // ActionMenuPresenter uses null as a callback argument here
314             // to indicate overflow is opening.
315             super.onSubMenuSelected(null);
316
317             return true;
318         }
319         return false;
320     }
321
322     /**
323      * Hide the overflow menu if it is currently showing.
324      *
325      * @return true if the overflow menu was hidden, false otherwise.
326      */
327     public boolean hideOverflowMenu() {
328         if (mPostedOpenRunnable != null && mMenuView != null) {
329             ((View) mMenuView).removeCallbacks(mPostedOpenRunnable);
330             mPostedOpenRunnable = null;
331             return true;
332         }
333
334         MenuPopupHelper popup = mOverflowPopup;
335         if (popup != null) {
336             popup.dismiss();
337             return true;
338         }
339         return false;
340     }
341
342     /**
343      * Dismiss all popup menus - overflow and submenus.
344      * @return true if popups were dismissed, false otherwise. (This can be because none were open.)
345      */
346     public boolean dismissPopupMenus() {
347         boolean result = hideOverflowMenu();
348         result |= hideSubMenus();
349         return result;
350     }
351
352     /**
353      * Dismiss all submenu popups.
354      *
355      * @return true if popups were dismissed, false otherwise. (This can be because none were open.)
356      */
357     public boolean hideSubMenus() {
358         if (mActionButtonPopup != null) {
359             mActionButtonPopup.dismiss();
360             return true;
361         }
362         return false;
363     }
364
365     /**
366      * @return true if the overflow menu is currently showing
367      */
368     public boolean isOverflowMenuShowing() {
369         return mOverflowPopup != null && mOverflowPopup.isShowing();
370     }
371
372     public boolean isOverflowMenuShowPending() {
373         return mPostedOpenRunnable != null || isOverflowMenuShowing();
374     }
375
376     /**
377      * @return true if space has been reserved in the action menu for an overflow item.
378      */
379     public boolean isOverflowReserved() {
380         return mReserveOverflow;
381     }
382
383     public boolean flagActionItems() {
384         final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
385         final int itemsSize = visibleItems.size();
386         int maxActions = mMaxItems;
387         int widthLimit = mActionItemWidthLimit;
388         final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
389         final ViewGroup parent = (ViewGroup) mMenuView;
390
391         int requiredItems = 0;
392         int requestedItems = 0;
393         int firstActionWidth = 0;
394         boolean hasOverflow = false;
395         for (int i = 0; i < itemsSize; i++) {
396             MenuItemImpl item = visibleItems.get(i);
397             if (item.requiresActionButton()) {
398                 requiredItems++;
399             } else if (item.requestsActionButton()) {
400                 requestedItems++;
401             } else {
402                 hasOverflow = true;
403             }
404             if (mExpandedActionViewsExclusive && item.isActionViewExpanded()) {
405                 // Overflow everything if we have an expanded action view and we're
406                 // space constrained.
407                 maxActions = 0;
408             }
409         }
410
411         // Reserve a spot for the overflow item if needed.
412         if (mReserveOverflow &&
413                 (hasOverflow || requiredItems + requestedItems > maxActions)) {
414             maxActions--;
415         }
416         maxActions -= requiredItems;
417
418         final SparseBooleanArray seenGroups = mActionButtonGroups;
419         seenGroups.clear();
420
421         int cellSize = 0;
422         int cellsRemaining = 0;
423         if (mStrictWidthLimit) {
424             cellsRemaining = widthLimit / mMinCellSize;
425             final int cellSizeRemaining = widthLimit % mMinCellSize;
426             cellSize = mMinCellSize + cellSizeRemaining / cellsRemaining;
427         }
428
429         // Flag as many more requested items as will fit.
430         for (int i = 0; i < itemsSize; i++) {
431             MenuItemImpl item = visibleItems.get(i);
432
433             if (item.requiresActionButton()) {
434                 View v = getItemView(item, mScrapActionButtonView, parent);
435                 if (mScrapActionButtonView == null) {
436                     mScrapActionButtonView = v;
437                 }
438                 if (mStrictWidthLimit) {
439                     cellsRemaining -= ActionMenuView.measureChildForCells(v,
440                             cellSize, cellsRemaining, querySpec, 0);
441                 } else {
442                     v.measure(querySpec, querySpec);
443                 }
444                 final int measuredWidth = v.getMeasuredWidth();
445                 widthLimit -= measuredWidth;
446                 if (firstActionWidth == 0) {
447                     firstActionWidth = measuredWidth;
448                 }
449                 final int groupId = item.getGroupId();
450                 if (groupId != 0) {
451                     seenGroups.put(groupId, true);
452                 }
453                 item.setIsActionButton(true);
454             } else if (item.requestsActionButton()) {
455                 // Items in a group with other items that already have an action slot
456                 // can break the max actions rule, but not the width limit.
457                 final int groupId = item.getGroupId();
458                 final boolean inGroup = seenGroups.get(groupId);
459                 boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0 &&
460                         (!mStrictWidthLimit || cellsRemaining > 0);
461
462                 if (isAction) {
463                     View v = getItemView(item, mScrapActionButtonView, parent);
464                     if (mScrapActionButtonView == null) {
465                         mScrapActionButtonView = v;
466                     }
467                     if (mStrictWidthLimit) {
468                         final int cells = ActionMenuView.measureChildForCells(v,
469                                 cellSize, cellsRemaining, querySpec, 0);
470                         cellsRemaining -= cells;
471                         if (cells == 0) {
472                             isAction = false;
473                         }
474                     } else {
475                         v.measure(querySpec, querySpec);
476                     }
477                     final int measuredWidth = v.getMeasuredWidth();
478                     widthLimit -= measuredWidth;
479                     if (firstActionWidth == 0) {
480                         firstActionWidth = measuredWidth;
481                     }
482
483                     if (mStrictWidthLimit) {
484                         isAction &= widthLimit >= 0;
485                     } else {
486                         // Did this push the entire first item past the limit?
487                         isAction &= widthLimit + firstActionWidth > 0;
488                     }
489                 }
490
491                 if (isAction && groupId != 0) {
492                     seenGroups.put(groupId, true);
493                 } else if (inGroup) {
494                     // We broke the width limit. Demote the whole group, they all overflow now.
495                     seenGroups.put(groupId, false);
496                     for (int j = 0; j < i; j++) {
497                         MenuItemImpl areYouMyGroupie = visibleItems.get(j);
498                         if (areYouMyGroupie.getGroupId() == groupId) {
499                             // Give back the action slot
500                             if (areYouMyGroupie.isActionButton()) maxActions++;
501                             areYouMyGroupie.setIsActionButton(false);
502                         }
503                     }
504                 }
505
506                 if (isAction) maxActions--;
507
508                 item.setIsActionButton(isAction);
509             } else {
510                 // Neither requires nor requests an action button.
511                 item.setIsActionButton(false);
512             }
513         }
514         return true;
515     }
516
517     @Override
518     public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
519         dismissPopupMenus();
520         super.onCloseMenu(menu, allMenusAreClosing);
521     }
522
523     @Override
524     public Parcelable onSaveInstanceState() {
525         SavedState state = new SavedState();
526         state.openSubMenuId = mOpenSubMenuId;
527         return state;
528     }
529
530     @Override
531     public void onRestoreInstanceState(Parcelable state) {
532         SavedState saved = (SavedState) state;
533         if (saved.openSubMenuId > 0) {
534             MenuItem item = mMenu.findItem(saved.openSubMenuId);
535             if (item != null) {
536                 SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
537                 onSubMenuSelected(subMenu);
538             }
539         }
540     }
541
542     @Override
543     public void onSubUiVisibilityChanged(boolean isVisible) {
544         if (isVisible) {
545             // Not a submenu, but treat it like one.
546             super.onSubMenuSelected(null);
547         } else {
548             mMenu.close(false);
549         }
550     }
551
552     private static class SavedState implements Parcelable {
553         public int openSubMenuId;
554
555         SavedState() {
556         }
557
558         SavedState(Parcel in) {
559             openSubMenuId = in.readInt();
560         }
561
562         @Override
563         public int describeContents() {
564             return 0;
565         }
566
567         @Override
568         public void writeToParcel(Parcel dest, int flags) {
569             dest.writeInt(openSubMenuId);
570         }
571
572         public static final Parcelable.Creator<SavedState> CREATOR
573                 = new Parcelable.Creator<SavedState>() {
574             public SavedState createFromParcel(Parcel in) {
575                 return new SavedState(in);
576             }
577
578             public SavedState[] newArray(int size) {
579                 return new SavedState[size];
580             }
581         };
582     }
583
584     private class OverflowMenuButton extends ImageButton implements ActionMenuChildView {
585         public OverflowMenuButton(Context context) {
586             super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle);
587
588             setClickable(true);
589             setFocusable(true);
590             setVisibility(VISIBLE);
591             setEnabled(true);
592
593             setOnTouchListener(new ForwardingListener(this) {
594                 @Override
595                 public ListPopupWindow getPopup() {
596                     if (mOverflowPopup == null) {
597                         return null;
598                     }
599
600                     return mOverflowPopup.getPopup();
601                 }
602
603                 @Override
604                 public boolean onForwardingStarted() {
605                     showOverflowMenu();
606                     return true;
607                 }
608
609                 @Override
610                 public boolean onForwardingStopped() {
611                     // Displaying the popup occurs asynchronously, so wait for
612                     // the runnable to finish before deciding whether to stop
613                     // forwarding.
614                     if (mPostedOpenRunnable != null) {
615                         return false;
616                     }
617
618                     hideOverflowMenu();
619                     return true;
620                 }
621             });
622         }
623
624         @Override
625         public boolean performClick() {
626             if (super.performClick()) {
627                 return true;
628             }
629
630             playSoundEffect(SoundEffectConstants.CLICK);
631             showOverflowMenu();
632             return true;
633         }
634
635         @Override
636         public boolean needsDividerBefore() {
637             return false;
638         }
639
640         @Override
641         public boolean needsDividerAfter() {
642             return false;
643         }
644
645         @Override
646         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
647             if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
648                 // Fill available height
649                 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
650                         MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY);
651             }
652             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
653         }
654
655         @Override
656         public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
657             super.onInitializeAccessibilityNodeInfo(info);
658             info.setCanOpenPopup(true);
659         }
660     }
661
662     private class OverflowPopup extends MenuPopupHelper {
663         public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
664                 boolean overflowOnly) {
665             super(context, menu, anchorView, overflowOnly);
666             setCallback(mPopupPresenterCallback);
667         }
668
669         @Override
670         public void onDismiss() {
671             super.onDismiss();
672             mMenu.close();
673             mOverflowPopup = null;
674         }
675     }
676
677     private class ActionButtonSubmenu extends MenuPopupHelper {
678         private SubMenuBuilder mSubMenu;
679
680         public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
681             super(context, subMenu);
682             mSubMenu = subMenu;
683
684             MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
685             if (!item.isActionButton()) {
686                 // Give a reasonable anchor to nested submenus.
687                 setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton);
688             }
689
690             setCallback(mPopupPresenterCallback);
691
692             boolean preserveIconSpacing = false;
693             final int count = subMenu.size();
694             for (int i = 0; i < count; i++) {
695                 MenuItem childItem = subMenu.getItem(i);
696                 if (childItem.isVisible() && childItem.getIcon() != null) {
697                     preserveIconSpacing = true;
698                     break;
699                 }
700             }
701             setForceShowIcon(preserveIconSpacing);
702         }
703
704         @Override
705         public void onDismiss() {
706             super.onDismiss();
707             mActionButtonPopup = null;
708             mOpenSubMenuId = 0;
709         }
710     }
711
712     private class PopupPresenterCallback implements MenuPresenter.Callback {
713
714         @Override
715         public boolean onOpenSubMenu(MenuBuilder subMenu) {
716             if (subMenu == null) return false;
717
718             mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
719             return false;
720         }
721
722         @Override
723         public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
724             if (menu instanceof SubMenuBuilder) {
725                 ((SubMenuBuilder) menu).getRootMenu().close(false);
726             }
727         }
728     }
729
730     private class OpenOverflowRunnable implements Runnable {
731         private OverflowPopup mPopup;
732
733         public OpenOverflowRunnable(OverflowPopup popup) {
734             mPopup = popup;
735         }
736
737         public void run() {
738             mMenu.changeMenuMode();
739             final View menuView = (View) mMenuView;
740             if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) {
741                 mOverflowPopup = mPopup;
742             }
743             mPostedOpenRunnable = null;
744         }
745     }
746 }