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