Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 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 | package com.android.internal.view.menu; |
| 17 | |
| 18 | import android.content.Context; |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 19 | import android.content.res.Configuration; |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 20 | import android.content.res.Resources; |
| 21 | import android.content.res.TypedArray; |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 22 | import android.graphics.drawable.Drawable; |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 23 | import android.util.AttributeSet; |
Adam Powell | 6b336f8 | 2010-08-10 20:13:01 -0700 | [diff] [blame] | 24 | import android.view.Gravity; |
Adam Powell | b3312b8 | 2011-01-21 18:12:02 -0800 | [diff] [blame] | 25 | import android.view.SoundEffectConstants; |
Adam Powell | cf78b3e | 2010-09-12 18:25:23 -0700 | [diff] [blame] | 26 | import android.view.View; |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 27 | import android.view.ViewGroup; |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 28 | import android.widget.ImageButton; |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 29 | import android.widget.ImageView; |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 30 | import android.widget.LinearLayout; |
| 31 | |
| 32 | import java.util.ArrayList; |
| 33 | |
| 34 | /** |
| 35 | * @hide |
| 36 | */ |
| 37 | public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvoker, MenuView { |
| 38 | private static final String TAG = "ActionMenuView"; |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 39 | |
| 40 | // TODO Theme/style this. |
| 41 | private static final int DIVIDER_PADDING = 12; // dips |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 42 | |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 43 | private MenuBuilder mMenu; |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 44 | |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 45 | private int mMaxItems; |
Adam Powell | 36fced9 | 2011-01-16 15:48:07 -0800 | [diff] [blame] | 46 | private int mWidthLimit; |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 47 | private boolean mReserveOverflow; |
| 48 | private OverflowMenuButton mOverflowButton; |
Adam Powell | 6c6f575 | 2010-08-20 18:34:46 -0700 | [diff] [blame] | 49 | private MenuPopupHelper mOverflowPopup; |
Adam Powell | 345a9f4 | 2011-01-06 16:03:30 -0800 | [diff] [blame] | 50 | |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 51 | private float mDividerPadding; |
| 52 | |
| 53 | private Drawable mDivider; |
Adam Powell | 6c6f575 | 2010-08-20 18:34:46 -0700 | [diff] [blame] | 54 | |
Adam Powell | 5576744 | 2011-01-24 14:28:37 -0800 | [diff] [blame] | 55 | private final Runnable mShowOverflow = new Runnable() { |
Adam Powell | 6c6f575 | 2010-08-20 18:34:46 -0700 | [diff] [blame] | 56 | public void run() { |
| 57 | showOverflowMenu(); |
| 58 | } |
| 59 | }; |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 60 | |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 61 | private class OpenOverflowRunnable implements Runnable { |
| 62 | private MenuPopupHelper mPopup; |
| 63 | |
| 64 | public OpenOverflowRunnable(MenuPopupHelper popup) { |
| 65 | mPopup = popup; |
| 66 | } |
| 67 | |
| 68 | public void run() { |
Adam Powell | 5e3f284 | 2011-01-07 17:16:56 -0800 | [diff] [blame] | 69 | if (mPopup.tryShow()) { |
| 70 | mOverflowPopup = mPopup; |
| 71 | mPostedOpenRunnable = null; |
| 72 | } |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 73 | } |
| 74 | } |
| 75 | |
| 76 | private OpenOverflowRunnable mPostedOpenRunnable; |
| 77 | |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 78 | public ActionMenuView(Context context) { |
| 79 | this(context, null); |
| 80 | } |
| 81 | |
| 82 | public ActionMenuView(Context context, AttributeSet attrs) { |
| 83 | super(context, attrs); |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 84 | |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 85 | final Resources res = getResources(); |
Adam Powell | 773b1b9 | 2010-08-20 15:45:24 -0700 | [diff] [blame] | 86 | |
| 87 | // Measure for initial configuration |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 88 | mMaxItems = getMaxActionButtons(); |
Adam Powell | 773b1b9 | 2010-08-20 15:45:24 -0700 | [diff] [blame] | 89 | |
| 90 | // TODO There has to be a better way to indicate that we don't have a hard menu key. |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 91 | final int screen = res.getConfiguration().screenLayout; |
Adam Powell | 773b1b9 | 2010-08-20 15:45:24 -0700 | [diff] [blame] | 92 | mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) == |
| 93 | Configuration.SCREENLAYOUT_SIZE_XLARGE; |
Adam Powell | 36fced9 | 2011-01-16 15:48:07 -0800 | [diff] [blame] | 94 | mWidthLimit = res.getDisplayMetrics().widthPixels / 2; |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 95 | |
| 96 | TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme); |
Adam Powell | cf03576 | 2010-12-06 11:49:45 -0800 | [diff] [blame] | 97 | mDivider = a.getDrawable(com.android.internal.R.styleable.Theme_dividerVertical); |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 98 | a.recycle(); |
| 99 | |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 100 | mDividerPadding = DIVIDER_PADDING * res.getDisplayMetrics().density; |
Adam Powell | f16888f | 2010-10-11 17:05:29 -0700 | [diff] [blame] | 101 | |
| 102 | setBaselineAligned(false); |
Adam Powell | 773b1b9 | 2010-08-20 15:45:24 -0700 | [diff] [blame] | 103 | } |
| 104 | |
Adam Powell | 6c6f575 | 2010-08-20 18:34:46 -0700 | [diff] [blame] | 105 | @Override |
Adam Powell | 773b1b9 | 2010-08-20 15:45:24 -0700 | [diff] [blame] | 106 | public void onConfigurationChanged(Configuration newConfig) { |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 107 | super.onConfigurationChanged(newConfig); |
Adam Powell | 773b1b9 | 2010-08-20 15:45:24 -0700 | [diff] [blame] | 108 | final int screen = newConfig.screenLayout; |
| 109 | mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) == |
| 110 | Configuration.SCREENLAYOUT_SIZE_XLARGE; |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 111 | mMaxItems = getMaxActionButtons(); |
Adam Powell | 36fced9 | 2011-01-16 15:48:07 -0800 | [diff] [blame] | 112 | mWidthLimit = getResources().getDisplayMetrics().widthPixels / 2; |
Adam Powell | 773b1b9 | 2010-08-20 15:45:24 -0700 | [diff] [blame] | 113 | if (mMenu != null) { |
| 114 | mMenu.setMaxActionItems(mMaxItems); |
| 115 | updateChildren(false); |
| 116 | } |
Adam Powell | 6c6f575 | 2010-08-20 18:34:46 -0700 | [diff] [blame] | 117 | |
| 118 | if (mOverflowPopup != null && mOverflowPopup.isShowing()) { |
| 119 | mOverflowPopup.dismiss(); |
| 120 | post(mShowOverflow); |
| 121 | } |
Adam Powell | 773b1b9 | 2010-08-20 15:45:24 -0700 | [diff] [blame] | 122 | } |
| 123 | |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 124 | @Override |
| 125 | public void onDetachedFromWindow() { |
| 126 | super.onDetachedFromWindow(); |
| 127 | if (mOverflowPopup != null && mOverflowPopup.isShowing()) { |
| 128 | mOverflowPopup.dismiss(); |
| 129 | } |
Adam Powell | 5576744 | 2011-01-24 14:28:37 -0800 | [diff] [blame] | 130 | removeCallbacks(mShowOverflow); |
| 131 | if (mPostedOpenRunnable != null) { |
| 132 | removeCallbacks(mPostedOpenRunnable); |
| 133 | } |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 134 | } |
| 135 | |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 136 | private int getMaxActionButtons() { |
| 137 | return getResources().getInteger(com.android.internal.R.integer.max_action_buttons); |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 138 | } |
| 139 | |
| 140 | public boolean isOverflowReserved() { |
| 141 | return mReserveOverflow; |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 142 | } |
| 143 | |
Adam Powell | b366bba | 2010-07-20 14:26:38 -0700 | [diff] [blame] | 144 | public void setOverflowReserved(boolean reserveOverflow) { |
| 145 | mReserveOverflow = reserveOverflow; |
| 146 | } |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 147 | |
Adam Powell | f0ad6e6 | 2011-01-10 17:14:06 -0800 | [diff] [blame] | 148 | public View getOverflowButton() { |
| 149 | return mOverflowButton; |
| 150 | } |
| 151 | |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 152 | @Override |
| 153 | protected LayoutParams generateDefaultLayoutParams() { |
| 154 | LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, |
| 155 | LayoutParams.WRAP_CONTENT); |
Adam Powell | 6b336f8 | 2010-08-10 20:13:01 -0700 | [diff] [blame] | 156 | params.gravity = Gravity.CENTER_VERTICAL; |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 157 | return params; |
| 158 | } |
| 159 | |
| 160 | @Override |
| 161 | protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { |
Adam Powell | 3f476b3 | 2011-01-03 19:25:36 -0800 | [diff] [blame] | 162 | if (p instanceof LayoutParams) { |
| 163 | LayoutParams result = new LayoutParams((LayoutParams) p); |
| 164 | if (result.gravity <= Gravity.NO_GRAVITY) { |
| 165 | result.gravity = Gravity.CENTER_VERTICAL; |
| 166 | } |
| 167 | return result; |
| 168 | } |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 169 | return generateDefaultLayoutParams(); |
| 170 | } |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 171 | |
| 172 | public boolean invokeItem(MenuItemImpl item) { |
| 173 | return mMenu.performItemAction(item, 0); |
| 174 | } |
| 175 | |
| 176 | public int getWindowAnimations() { |
| 177 | return 0; |
| 178 | } |
| 179 | |
| 180 | public void initialize(MenuBuilder menu, int menuType) { |
Adam Powell | 36fced9 | 2011-01-16 15:48:07 -0800 | [diff] [blame] | 181 | int width = mWidthLimit; |
| 182 | if (mReserveOverflow) { |
| 183 | if (mOverflowButton == null) { |
| 184 | OverflowMenuButton button = new OverflowMenuButton(mContext); |
| 185 | mOverflowButton = button; |
| 186 | } |
| 187 | final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); |
| 188 | mOverflowButton.measure(spec, spec); |
| 189 | width -= mOverflowButton.getMeasuredWidth(); |
| 190 | } |
| 191 | |
| 192 | menu.setActionWidthLimit(width); |
| 193 | |
Adam Powell | 7ade1be | 2010-06-17 12:51:21 -0700 | [diff] [blame] | 194 | menu.setMaxActionItems(mMaxItems); |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 195 | final boolean cleared = mMenu != menu; |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 196 | mMenu = menu; |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 197 | updateChildren(cleared); |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | public void updateChildren(boolean cleared) { |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 201 | final ArrayList<MenuItemImpl> itemsToShow = mMenu.getActionItems(mReserveOverflow); |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 202 | final int itemCount = itemsToShow.size(); |
| 203 | |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 204 | boolean needsDivider = false; |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 205 | int childIndex = 0; |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 206 | for (int i = 0; i < itemCount; i++) { |
Adam Powell | e7d4684 | 2011-01-13 21:36:09 -0800 | [diff] [blame] | 207 | final MenuItemImpl itemData = itemsToShow.get(i); |
| 208 | boolean hasDivider = false; |
| 209 | |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 210 | if (needsDivider) { |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 211 | if (!isDivider(getChildAt(childIndex))) { |
| 212 | addView(makeDividerView(), childIndex, makeDividerLayoutParams()); |
| 213 | } |
Adam Powell | e7d4684 | 2011-01-13 21:36:09 -0800 | [diff] [blame] | 214 | hasDivider = true; |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 215 | childIndex++; |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 216 | } |
Adam Powell | e7d4684 | 2011-01-13 21:36:09 -0800 | [diff] [blame] | 217 | |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 218 | View childToAdd = itemData.getActionView(); |
| 219 | boolean needsPreDivider = false; |
| 220 | if (childToAdd != null) { |
| 221 | childToAdd.setLayoutParams(makeActionViewLayoutParams(childToAdd)); |
Adam Powell | cf78b3e | 2010-09-12 18:25:23 -0700 | [diff] [blame] | 222 | } else { |
Adam Powell | e7d4684 | 2011-01-13 21:36:09 -0800 | [diff] [blame] | 223 | ActionMenuItemView view = (ActionMenuItemView) itemData.getItemView( |
| 224 | MenuBuilder.TYPE_ACTION_BUTTON, this); |
| 225 | view.setItemInvoker(this); |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 226 | needsPreDivider = i > 0 && !hasDivider && view.hasText() && |
| 227 | itemData.getIcon() == null; |
Adam Powell | e7d4684 | 2011-01-13 21:36:09 -0800 | [diff] [blame] | 228 | needsDivider = view.hasText(); |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 229 | childToAdd = view; |
Adam Powell | cf78b3e | 2010-09-12 18:25:23 -0700 | [diff] [blame] | 230 | } |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 231 | |
| 232 | boolean addPreDivider = removeChildrenUntil(childIndex, childToAdd, needsPreDivider); |
| 233 | |
| 234 | if (addPreDivider) addView(makeDividerView(), childIndex, makeDividerLayoutParams()); |
| 235 | if (needsPreDivider) childIndex++; |
| 236 | |
| 237 | if (getChildAt(childIndex) != childToAdd) { |
| 238 | addView(childToAdd, childIndex); |
| 239 | } |
| 240 | childIndex++; |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 241 | } |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 242 | |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 243 | final boolean hasOverflow = mOverflowButton != null && mOverflowButton.getParent() == this; |
| 244 | final boolean needsOverflow = mReserveOverflow && mMenu.getNonActionItems(true).size() > 0; |
| 245 | |
| 246 | if (hasOverflow != needsOverflow) { |
| 247 | if (needsOverflow) { |
Adam Powell | 36fced9 | 2011-01-16 15:48:07 -0800 | [diff] [blame] | 248 | if (mOverflowButton == null) { |
| 249 | OverflowMenuButton button = new OverflowMenuButton(mContext); |
| 250 | mOverflowButton = button; |
| 251 | } |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 252 | boolean addDivider = removeChildrenUntil(childIndex, mOverflowButton, true); |
| 253 | if (addDivider && itemCount > 0) { |
| 254 | addView(makeDividerView(), childIndex, makeDividerLayoutParams()); |
| 255 | childIndex++; |
| 256 | } |
| 257 | addView(mOverflowButton, childIndex); |
| 258 | childIndex++; |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 259 | } else { |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 260 | removeView(mOverflowButton); |
| 261 | } |
| 262 | } else { |
| 263 | if (needsOverflow) { |
| 264 | boolean overflowDivider = itemCount > 0; |
| 265 | boolean addDivider = removeChildrenUntil(childIndex, mOverflowButton, |
| 266 | overflowDivider); |
| 267 | if (addDivider && itemCount > 0) { |
| 268 | addView(makeDividerView(), childIndex, makeDividerLayoutParams()); |
| 269 | } |
| 270 | if (overflowDivider) { |
| 271 | childIndex += 2; |
| 272 | } else { |
| 273 | childIndex++; |
| 274 | } |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 275 | } |
| 276 | } |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 277 | |
| 278 | while (getChildCount() > childIndex) { |
| 279 | removeViewAt(childIndex); |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | private boolean removeChildrenUntil(int start, View targetChild, boolean needsPreDivider) { |
| 284 | final int childCount = getChildCount(); |
| 285 | boolean found = false; |
| 286 | for (int i = start; i < childCount; i++) { |
| 287 | final View child = getChildAt(i); |
| 288 | if (child == targetChild) { |
| 289 | found = true; |
| 290 | break; |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | if (!found) { |
| 295 | return needsPreDivider; |
| 296 | } |
| 297 | |
| 298 | for (int i = start; i < getChildCount(); ) { |
| 299 | final View child = getChildAt(i); |
| 300 | if (needsPreDivider && isDivider(child)) { |
| 301 | needsPreDivider = false; |
| 302 | i++; |
| 303 | continue; |
| 304 | } |
| 305 | if (child == targetChild) break; |
| 306 | removeViewAt(i); |
| 307 | } |
| 308 | |
| 309 | return needsPreDivider; |
| 310 | } |
| 311 | |
| 312 | private static boolean isDivider(View v) { |
| 313 | return v != null && v.getId() == com.android.internal.R.id.action_menu_divider; |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 314 | } |
| 315 | |
| 316 | public boolean showOverflowMenu() { |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 317 | if (mOverflowButton != null && !isOverflowMenuShowing()) { |
| 318 | mMenu.getCallback().onMenuModeChange(mMenu); |
Adam Powell | f75eeb2 | 2010-08-10 15:59:40 -0700 | [diff] [blame] | 319 | return true; |
| 320 | } |
| 321 | return false; |
| 322 | } |
| 323 | |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 324 | public void openOverflowMenu() { |
| 325 | OverflowPopup popup = new OverflowPopup(getContext(), mMenu, mOverflowButton, true); |
| 326 | mPostedOpenRunnable = new OpenOverflowRunnable(popup); |
| 327 | // Post this for later; we might still need a layout for the anchor to be right. |
| 328 | post(mPostedOpenRunnable); |
| 329 | } |
| 330 | |
Adam Powell | f6148c5 | 2010-08-11 21:10:16 -0700 | [diff] [blame] | 331 | public boolean isOverflowMenuShowing() { |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 332 | return mOverflowPopup != null && mOverflowPopup.isShowing(); |
| 333 | } |
| 334 | |
| 335 | public boolean isOverflowMenuOpen() { |
| 336 | return mOverflowPopup != null; |
Adam Powell | f6148c5 | 2010-08-11 21:10:16 -0700 | [diff] [blame] | 337 | } |
| 338 | |
Adam Powell | f75eeb2 | 2010-08-10 15:59:40 -0700 | [diff] [blame] | 339 | public boolean hideOverflowMenu() { |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 340 | if (mPostedOpenRunnable != null) { |
| 341 | removeCallbacks(mPostedOpenRunnable); |
| 342 | return true; |
| 343 | } |
| 344 | |
Adam Powell | 6c6f575 | 2010-08-20 18:34:46 -0700 | [diff] [blame] | 345 | MenuPopupHelper popup = mOverflowPopup; |
Adam Powell | f75eeb2 | 2010-08-10 15:59:40 -0700 | [diff] [blame] | 346 | if (popup != null) { |
| 347 | popup.dismiss(); |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 348 | return true; |
| 349 | } |
| 350 | return false; |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 351 | } |
| 352 | |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 353 | private boolean addItemView(boolean needsDivider, ActionMenuItemView view) { |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 354 | view.setItemInvoker(this); |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 355 | boolean hasText = view.hasText(); |
| 356 | |
| 357 | if (hasText && needsDivider) { |
| 358 | addView(makeDividerView(), makeDividerLayoutParams()); |
| 359 | } |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 360 | addView(view); |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 361 | return hasText; |
| 362 | } |
| 363 | |
| 364 | private ImageView makeDividerView() { |
| 365 | ImageView result = new ImageView(mContext); |
| 366 | result.setImageDrawable(mDivider); |
| 367 | result.setScaleType(ImageView.ScaleType.FIT_XY); |
Adam Powell | f2d7a5d | 2011-02-07 18:05:24 -0800 | [diff] [blame] | 368 | result.setId(com.android.internal.R.id.action_menu_divider); |
Adam Powell | be4d68e | 2010-10-08 18:16:34 -0700 | [diff] [blame] | 369 | return result; |
| 370 | } |
| 371 | |
| 372 | private LayoutParams makeDividerLayoutParams() { |
| 373 | LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, |
| 374 | LayoutParams.MATCH_PARENT); |
| 375 | params.topMargin = (int) mDividerPadding; |
| 376 | params.bottomMargin = (int) mDividerPadding; |
| 377 | return params; |
| 378 | } |
| 379 | |
Adam Powell | 3f476b3 | 2011-01-03 19:25:36 -0800 | [diff] [blame] | 380 | private LayoutParams makeActionViewLayoutParams(View view) { |
Adam Powell | 345a9f4 | 2011-01-06 16:03:30 -0800 | [diff] [blame] | 381 | return generateLayoutParams(view.getLayoutParams()); |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 382 | } |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 383 | |
| 384 | private class OverflowMenuButton extends ImageButton { |
| 385 | public OverflowMenuButton(Context context) { |
Adam Powell | 079fd1c | 2010-09-08 19:31:29 -0700 | [diff] [blame] | 386 | super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle); |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 387 | |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 388 | setClickable(true); |
| 389 | setFocusable(true); |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 390 | setVisibility(VISIBLE); |
| 391 | setEnabled(true); |
| 392 | } |
| 393 | |
| 394 | @Override |
| 395 | public boolean performClick() { |
| 396 | if (super.performClick()) { |
| 397 | return true; |
| 398 | } |
| 399 | |
Adam Powell | b3312b8 | 2011-01-21 18:12:02 -0800 | [diff] [blame] | 400 | playSoundEffect(SoundEffectConstants.CLICK); |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 401 | showOverflowMenu(); |
Adam Powell | 8028dd3 | 2010-07-15 10:16:33 -0700 | [diff] [blame] | 402 | return true; |
| 403 | } |
| 404 | } |
Adam Powell | 8515ee8 | 2010-11-30 14:09:55 -0800 | [diff] [blame] | 405 | |
| 406 | private class OverflowPopup extends MenuPopupHelper { |
| 407 | public OverflowPopup(Context context, MenuBuilder menu, View anchorView, |
| 408 | boolean overflowOnly) { |
| 409 | super(context, menu, anchorView, overflowOnly); |
| 410 | } |
| 411 | |
| 412 | @Override |
| 413 | public void onDismiss() { |
| 414 | super.onDismiss(); |
| 415 | mMenu.getCallback().onCloseMenu(mMenu, true); |
| 416 | mOverflowPopup = null; |
| 417 | } |
| 418 | } |
Adam Powell | 96675b1 | 2010-06-10 18:58:59 -0700 | [diff] [blame] | 419 | } |