MenuPopupHelper.java revision 6c6f575423d6718c3ff322224c1520901ce881e1
1/* 2 * Copyright (C) 2010 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 17package com.android.internal.view.menu; 18 19import com.android.internal.view.menu.MenuBuilder.MenuAdapter; 20 21import android.content.Context; 22import android.util.DisplayMetrics; 23import android.view.KeyEvent; 24import android.view.MenuItem; 25import android.view.View; 26import android.view.View.MeasureSpec; 27import android.widget.AdapterView; 28import android.widget.ListPopupWindow; 29import android.widget.PopupWindow; 30 31import java.lang.ref.WeakReference; 32 33/** 34 * @hide 35 */ 36public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener { 37 private static final String TAG = "MenuPopupHelper"; 38 39 private Context mContext; 40 private ListPopupWindow mPopup; 41 private MenuBuilder mMenu; 42 private int mPopupMaxWidth; 43 private WeakReference<View> mAnchorView; 44 private boolean mOverflowOnly; 45 46 private PopupWindow.OnDismissListener mDismissListener = new PopupWindow.OnDismissListener() { 47 public void onDismiss() { 48 mPopup = null; 49 } 50 }; 51 52 public MenuPopupHelper(Context context, MenuBuilder menu) { 53 this(context, menu, null, false); 54 } 55 56 public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) { 57 this(context, menu, anchorView, false); 58 } 59 60 public MenuPopupHelper(Context context, MenuBuilder menu, 61 View anchorView, boolean overflowOnly) { 62 mContext = context; 63 mMenu = menu; 64 mOverflowOnly = overflowOnly; 65 66 final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 67 mPopupMaxWidth = metrics.widthPixels / 2; 68 69 if (anchorView != null) { 70 mAnchorView = new WeakReference<View>(anchorView); 71 } 72 } 73 74 public void show() { 75 // TODO Use a style from the theme here 76 mPopup = new ListPopupWindow(mContext, null, 0, 77 com.android.internal.R.style.Widget_Spinner); 78 mPopup.setOnItemClickListener(this); 79 mPopup.setOnDismissListener(mDismissListener); 80 81 final MenuAdapter adapter = mOverflowOnly ? 82 mMenu.getOverflowMenuAdapter(MenuBuilder.TYPE_POPUP) : 83 mMenu.getMenuAdapter(MenuBuilder.TYPE_POPUP); 84 mPopup.setAdapter(adapter); 85 mPopup.setModal(true); 86 87 if (mAnchorView != null) { 88 mPopup.setAnchorView(mAnchorView.get()); 89 } else if (mMenu instanceof SubMenuBuilder) { 90 SubMenuBuilder subMenu = (SubMenuBuilder) mMenu; 91 final MenuItemImpl itemImpl = (MenuItemImpl) subMenu.getItem(); 92 mPopup.setAnchorView(itemImpl.getItemView(MenuBuilder.TYPE_ACTION_BUTTON, null)); 93 } else { 94 throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); 95 } 96 97 mPopup.setContentWidth(Math.min(measureContentWidth(adapter), mPopupMaxWidth)); 98 mPopup.show(); 99 mPopup.getListView().setOnKeyListener(this); 100 } 101 102 public void dismiss() { 103 if (isShowing()) { 104 mPopup.dismiss(); 105 } 106 } 107 108 public boolean isShowing() { 109 return mPopup != null && mPopup.isShowing(); 110 } 111 112 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 113 MenuItem item = null; 114 if (mOverflowOnly) { 115 item = mMenu.getOverflowItem(position); 116 } else { 117 item = mMenu.getItem(position); 118 } 119 mMenu.performItemAction(item, 0); 120 mPopup.dismiss(); 121 } 122 123 public boolean onKey(View v, int keyCode, KeyEvent event) { 124 if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { 125 dismiss(); 126 return true; 127 } 128 return false; 129 } 130 131 private int measureContentWidth(MenuAdapter adapter) { 132 // Menus don't tend to be long, so this is more sane than it looks. 133 int width = 0; 134 View itemView = null; 135 final int widthMeasureSpec = 136 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 137 final int heightMeasureSpec = 138 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 139 final int count = adapter.getCount(); 140 for (int i = 0; i < count; i++) { 141 itemView = adapter.getView(i, itemView, null); 142 itemView.measure(widthMeasureSpec, heightMeasureSpec); 143 width = Math.max(width, itemView.getMeasuredWidth()); 144 } 145 return width; 146 } 147} 148