ActionMenuView.java revision be4d68e7b238b8ee879de0481e39c40d3f1683b6
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 */ 16package com.android.internal.view.menu; 17 18import android.content.Context; 19import android.content.res.Configuration; 20import android.content.res.Resources; 21import android.content.res.TypedArray; 22import android.graphics.drawable.Drawable; 23import android.util.AttributeSet; 24import android.view.Gravity; 25import android.view.View; 26import android.view.ViewGroup; 27import android.widget.ImageButton; 28import android.widget.ImageView; 29import android.widget.LinearLayout; 30import android.widget.LinearLayout.LayoutParams; 31 32import java.util.ArrayList; 33 34/** 35 * @hide 36 */ 37public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvoker, MenuView { 38 private static final String TAG = "ActionMenuView"; 39 40 // TODO Theme/style this. 41 private static final int DIVIDER_PADDING = 12; // dips 42 43 private MenuBuilder mMenu; 44 45 private int mMaxItems; 46 private boolean mReserveOverflow; 47 private OverflowMenuButton mOverflowButton; 48 private MenuPopupHelper mOverflowPopup; 49 50 private float mButtonPaddingLeft; 51 private float mButtonPaddingRight; 52 private float mDividerPadding; 53 54 private Drawable mDivider; 55 56 private Runnable mShowOverflow = new Runnable() { 57 public void run() { 58 showOverflowMenu(); 59 } 60 }; 61 62 public ActionMenuView(Context context) { 63 this(context, null); 64 } 65 66 public ActionMenuView(Context context, AttributeSet attrs) { 67 super(context, attrs); 68 69 final Resources res = getResources(); 70 71 // Measure for initial configuration 72 mMaxItems = getMaxActionButtons(); 73 74 // TODO There has to be a better way to indicate that we don't have a hard menu key. 75 final int screen = res.getConfiguration().screenLayout; 76 mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) == 77 Configuration.SCREENLAYOUT_SIZE_XLARGE; 78 79 TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme); 80 final int buttonStyle = a.getResourceId( 81 com.android.internal.R.styleable.Theme_actionButtonStyle, 0); 82 final int groupStyle = a.getResourceId( 83 com.android.internal.R.styleable.Theme_buttonGroupStyle, 0); 84 a.recycle(); 85 86 a = context.obtainStyledAttributes(buttonStyle, com.android.internal.R.styleable.View); 87 mButtonPaddingLeft = a.getDimension(com.android.internal.R.styleable.View_paddingLeft, 0); 88 mButtonPaddingRight = a.getDimension(com.android.internal.R.styleable.View_paddingRight, 0); 89 a.recycle(); 90 91 a = context.obtainStyledAttributes(groupStyle, 92 com.android.internal.R.styleable.ButtonGroup); 93 mDivider = a.getDrawable(com.android.internal.R.styleable.ButtonGroup_divider); 94 a.recycle(); 95 96 mDividerPadding = DIVIDER_PADDING * res.getDisplayMetrics().density; 97 } 98 99 @Override 100 public void onConfigurationChanged(Configuration newConfig) { 101 final int screen = newConfig.screenLayout; 102 mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) == 103 Configuration.SCREENLAYOUT_SIZE_XLARGE; 104 mMaxItems = getMaxActionButtons(); 105 if (mMenu != null) { 106 mMenu.setMaxActionItems(mMaxItems); 107 updateChildren(false); 108 } 109 110 if (mOverflowPopup != null && mOverflowPopup.isShowing()) { 111 mOverflowPopup.dismiss(); 112 post(mShowOverflow); 113 } 114 } 115 116 private int getMaxActionButtons() { 117 return getResources().getInteger(com.android.internal.R.integer.max_action_buttons); 118 } 119 120 public boolean isOverflowReserved() { 121 return mReserveOverflow; 122 } 123 124 public void setOverflowReserved(boolean reserveOverflow) { 125 mReserveOverflow = reserveOverflow; 126 } 127 128 @Override 129 protected LayoutParams generateDefaultLayoutParams() { 130 LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, 131 LayoutParams.WRAP_CONTENT); 132 params.gravity = Gravity.CENTER_VERTICAL; 133 return params; 134 } 135 136 @Override 137 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 138 return generateDefaultLayoutParams(); 139 } 140 141 public boolean invokeItem(MenuItemImpl item) { 142 return mMenu.performItemAction(item, 0); 143 } 144 145 public int getWindowAnimations() { 146 return 0; 147 } 148 149 public void initialize(MenuBuilder menu, int menuType) { 150 menu.setMaxActionItems(mMaxItems); 151 mMenu = menu; 152 updateChildren(true); 153 } 154 155 public void updateChildren(boolean cleared) { 156 final boolean reserveOverflow = mReserveOverflow; 157 removeAllViews(); 158 159 final ArrayList<MenuItemImpl> itemsToShow = mMenu.getActionItems(reserveOverflow); 160 final int itemCount = itemsToShow.size(); 161 162 boolean needsDivider = false; 163 for (int i = 0; i < itemCount; i++) { 164 if (needsDivider) { 165 addView(makeDividerView(), makeDividerLayoutParams()); 166 } 167 final MenuItemImpl itemData = itemsToShow.get(i); 168 final View actionView = itemData.getActionView(); 169 if (actionView != null) { 170 addView(actionView, makeActionViewLayoutParams()); 171 } else { 172 needsDivider = addItemView(i == 0 || !needsDivider, 173 (ActionMenuItemView) itemData.getItemView( 174 MenuBuilder.TYPE_ACTION_BUTTON, this)); 175 } 176 } 177 178 if (reserveOverflow) { 179 if (mMenu.getNonActionItems(true).size() > 0) { 180 OverflowMenuButton button = new OverflowMenuButton(mContext); 181 addView(button); 182 mOverflowButton = button; 183 } else { 184 mOverflowButton = null; 185 } 186 } 187 } 188 189 public boolean showOverflowMenu() { 190 if (mOverflowButton != null) { 191 final MenuPopupHelper popup = 192 new MenuPopupHelper(getContext(), mMenu, mOverflowButton, true); 193 // Post this for later; we might still need a layout for the anchor to be right. 194 post(new Runnable() { 195 public void run() { 196 popup.show(); 197 } 198 }); 199 mOverflowPopup = popup; 200 return true; 201 } 202 return false; 203 } 204 205 public boolean isOverflowMenuShowing() { 206 MenuPopupHelper popup = mOverflowPopup; 207 if (popup != null) { 208 return popup.isShowing(); 209 } 210 return false; 211 } 212 213 public boolean hideOverflowMenu() { 214 MenuPopupHelper popup = mOverflowPopup; 215 if (popup != null) { 216 popup.dismiss(); 217 return true; 218 } 219 return false; 220 } 221 222 private boolean addItemView(boolean needsDivider, ActionMenuItemView view) { 223 view.setItemInvoker(this); 224 boolean hasText = view.hasText(); 225 226 if (hasText && needsDivider) { 227 addView(makeDividerView(), makeDividerLayoutParams()); 228 } 229 addView(view); 230 return hasText; 231 } 232 233 private ImageView makeDividerView() { 234 ImageView result = new ImageView(mContext); 235 result.setImageDrawable(mDivider); 236 result.setScaleType(ImageView.ScaleType.FIT_XY); 237 return result; 238 } 239 240 private LayoutParams makeDividerLayoutParams() { 241 LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, 242 LayoutParams.MATCH_PARENT); 243 params.topMargin = (int) mDividerPadding; 244 params.bottomMargin = (int) mDividerPadding; 245 return params; 246 } 247 248 private LayoutParams makeActionViewLayoutParams() { 249 LayoutParams params = generateDefaultLayoutParams(); 250 params.leftMargin = (int) mButtonPaddingLeft; 251 params.rightMargin = (int) mButtonPaddingRight; 252 return params; 253 } 254 255 private class OverflowMenuButton extends ImageButton { 256 public OverflowMenuButton(Context context) { 257 super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle); 258 259 setClickable(true); 260 setFocusable(true); 261 setVisibility(VISIBLE); 262 setEnabled(true); 263 } 264 265 @Override 266 public boolean performClick() { 267 if (super.performClick()) { 268 return true; 269 } 270 271 // Change to overflow mode 272 mMenu.getCallback().onMenuModeChange(mMenu); 273 return true; 274 } 275 } 276} 277