ActionMenuItemView.java revision 24340afbab8ad4c191784fda8023407205bc0a75
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 android.content.Context; 20import android.content.res.Resources; 21import android.content.res.TypedArray; 22import android.graphics.Rect; 23import android.graphics.drawable.Drawable; 24import android.text.TextUtils; 25import android.util.AttributeSet; 26import android.view.Gravity; 27import android.view.MotionEvent; 28import android.view.View; 29import android.view.accessibility.AccessibilityEvent; 30import android.widget.Button; 31import android.widget.ImageButton; 32import android.widget.LinearLayout; 33import android.widget.Toast; 34 35/** 36 * @hide 37 */ 38public class ActionMenuItemView extends LinearLayout 39 implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener, 40 ActionMenuView.ActionMenuChildView { 41 private static final String TAG = "ActionMenuItemView"; 42 43 private MenuItemImpl mItemData; 44 private CharSequence mTitle; 45 private MenuBuilder.ItemInvoker mItemInvoker; 46 47 private ImageButton mImageButton; 48 private Button mTextButton; 49 private boolean mAllowTextWithIcon; 50 private boolean mExpandedFormat; 51 private int mMinWidth; 52 53 public ActionMenuItemView(Context context) { 54 this(context, null); 55 } 56 57 public ActionMenuItemView(Context context, AttributeSet attrs) { 58 this(context, attrs, 0); 59 } 60 61 public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) { 62 super(context, attrs, defStyle); 63 final Resources res = context.getResources(); 64 mAllowTextWithIcon = res.getBoolean( 65 com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon); 66 TypedArray a = context.obtainStyledAttributes(attrs, 67 com.android.internal.R.styleable.ActionMenuItemView, 0, 0); 68 mMinWidth = a.getDimensionPixelSize( 69 com.android.internal.R.styleable.ActionMenuItemView_minWidth, 0); 70 a.recycle(); 71 } 72 73 @Override 74 public void onFinishInflate() { 75 mImageButton = (ImageButton) findViewById(com.android.internal.R.id.imageButton); 76 mTextButton = (Button) findViewById(com.android.internal.R.id.textButton); 77 mImageButton.setOnClickListener(this); 78 mTextButton.setOnClickListener(this); 79 mImageButton.setOnLongClickListener(this); 80 setOnClickListener(this); 81 setOnLongClickListener(this); 82 } 83 84 public MenuItemImpl getItemData() { 85 return mItemData; 86 } 87 88 public void initialize(MenuItemImpl itemData, int menuType) { 89 mItemData = itemData; 90 91 setIcon(itemData.getIcon()); 92 setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon 93 setId(itemData.getItemId()); 94 95 setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); 96 setEnabled(itemData.isEnabled()); 97 } 98 99 @Override 100 public void setEnabled(boolean enabled) { 101 super.setEnabled(enabled); 102 mImageButton.setEnabled(enabled); 103 mTextButton.setEnabled(enabled); 104 } 105 106 public void onClick(View v) { 107 if (mItemInvoker != null) { 108 mItemInvoker.invokeItem(mItemData); 109 } 110 } 111 112 public void setItemInvoker(MenuBuilder.ItemInvoker invoker) { 113 mItemInvoker = invoker; 114 } 115 116 public boolean prefersCondensedTitle() { 117 return true; 118 } 119 120 public void setCheckable(boolean checkable) { 121 // TODO Support checkable action items 122 } 123 124 public void setChecked(boolean checked) { 125 // TODO Support checkable action items 126 } 127 128 public void setExpandedFormat(boolean expandedFormat) { 129 if (mExpandedFormat != expandedFormat) { 130 mExpandedFormat = expandedFormat; 131 if (mItemData != null) { 132 mItemData.actionFormatChanged(); 133 } 134 } 135 } 136 137 private void updateTextButtonVisibility() { 138 boolean visible = !TextUtils.isEmpty(mTextButton.getText()); 139 visible &= mImageButton.getDrawable() == null || 140 (mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat)); 141 142 mTextButton.setVisibility(visible ? VISIBLE : GONE); 143 } 144 145 public void setIcon(Drawable icon) { 146 mImageButton.setImageDrawable(icon); 147 if (icon != null) { 148 mImageButton.setVisibility(VISIBLE); 149 } else { 150 mImageButton.setVisibility(GONE); 151 } 152 153 updateTextButtonVisibility(); 154 } 155 156 public boolean hasText() { 157 return mTextButton.getVisibility() != GONE; 158 } 159 160 public void setShortcut(boolean showShortcut, char shortcutKey) { 161 // Action buttons don't show text for shortcut keys. 162 } 163 164 public void setTitle(CharSequence title) { 165 mTitle = title; 166 167 mTextButton.setText(mTitle); 168 169 setContentDescription(mTitle); 170 updateTextButtonVisibility(); 171 } 172 173 @Override 174 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 175 onPopulateAccessibilityEvent(event); 176 return true; 177 } 178 179 @Override 180 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 181 super.onPopulateAccessibilityEvent(event); 182 final CharSequence cdesc = getContentDescription(); 183 if (!TextUtils.isEmpty(cdesc)) { 184 event.getText().add(cdesc); 185 } 186 } 187 188 @Override 189 public boolean dispatchHoverEvent(MotionEvent event) { 190 // Don't allow children to hover; we want this to be treated as a single component. 191 return onHoverEvent(event); 192 } 193 194 public boolean showsIcon() { 195 return true; 196 } 197 198 public boolean needsDividerBefore() { 199 return hasText() && mItemData.getIcon() == null; 200 } 201 202 public boolean needsDividerAfter() { 203 return hasText(); 204 } 205 206 @Override 207 public boolean onLongClick(View v) { 208 if (hasText()) { 209 // Don't show the cheat sheet for items that already show text. 210 return false; 211 } 212 213 final int[] screenPos = new int[2]; 214 final Rect displayFrame = new Rect(); 215 getLocationOnScreen(screenPos); 216 getWindowVisibleDisplayFrame(displayFrame); 217 218 final Context context = getContext(); 219 final int width = getWidth(); 220 final int height = getHeight(); 221 final int midy = screenPos[1] + height / 2; 222 final int screenWidth = context.getResources().getDisplayMetrics().widthPixels; 223 224 Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT); 225 if (midy < displayFrame.height()) { 226 // Show along the top; follow action buttons 227 cheatSheet.setGravity(Gravity.TOP | Gravity.RIGHT, 228 screenWidth - screenPos[0] - width / 2, height); 229 } else { 230 // Show along the bottom center 231 cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height); 232 } 233 cheatSheet.show(); 234 return true; 235 } 236 237 @Override 238 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 239 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 240 241 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 242 final int specSize = MeasureSpec.getSize(widthMeasureSpec); 243 final int oldMeasuredWidth = getMeasuredWidth(); 244 final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(specSize, mMinWidth) 245 : mMinWidth; 246 247 if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) { 248 // Remeasure at exactly the minimum width. 249 super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY), 250 heightMeasureSpec); 251 } 252 } 253} 254