IconMenuItemView.java revision 22f7dfd23490a3de2f21ff96949ba47003aac8f8
1/* 2 * Copyright (C) 2006 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.ItemInvoker; 20 21import android.content.Context; 22import android.content.res.TypedArray; 23import android.graphics.Rect; 24import android.graphics.drawable.Drawable; 25import android.util.AttributeSet; 26import android.view.Gravity; 27import android.view.SoundEffectConstants; 28import android.view.View; 29import android.view.ViewDebug; 30import android.widget.TextView; 31 32/** 33 * The item view for each item in the {@link IconMenuView}. 34 */ 35public final class IconMenuItemView extends TextView implements MenuView.ItemView { 36 37 private static final int NO_ALPHA = 0xFF; 38 39 private IconMenuView mIconMenuView; 40 41 private ItemInvoker mItemInvoker; 42 private MenuItemImpl mItemData; 43 44 private Drawable mIcon; 45 46 private int mTextAppearance; 47 private Context mTextAppearanceContext; 48 49 private float mDisabledAlpha; 50 51 private Rect mPositionIconAvailable = new Rect(); 52 private Rect mPositionIconOutput = new Rect(); 53 54 private boolean mShortcutCaptionMode; 55 private String mShortcutCaption; 56 57 private static String sPrependShortcutLabel; 58 59 public IconMenuItemView(Context context, AttributeSet attrs, int defStyle) { 60 super(context, attrs); 61 62 if (sPrependShortcutLabel == null) { 63 /* 64 * Views should only be constructed from the UI thread, so no 65 * synchronization needed 66 */ 67 sPrependShortcutLabel = getResources().getString( 68 com.android.internal.R.string.prepend_shortcut_label); 69 } 70 71 TypedArray a = 72 context.obtainStyledAttributes( 73 attrs, com.android.internal.R.styleable.MenuView, defStyle, 0); 74 75 mDisabledAlpha = a.getFloat( 76 com.android.internal.R.styleable.MenuView_itemIconDisabledAlpha, 0.8f); 77 mTextAppearance = a.getResourceId(com.android.internal.R.styleable. 78 MenuView_itemTextAppearance, -1); 79 mTextAppearanceContext = context; 80 81 a.recycle(); 82 } 83 84 public IconMenuItemView(Context context, AttributeSet attrs) { 85 this(context, attrs, 0); 86 } 87 88 /** 89 * Initializes with the provided title and icon 90 * @param title The title of this item 91 * @param icon The icon of this item 92 */ 93 void initialize(CharSequence title, Drawable icon) { 94 setClickable(true); 95 setFocusable(true); 96 97 if (mTextAppearance != -1) { 98 setTextAppearance(mTextAppearanceContext, mTextAppearance); 99 } 100 101 setTitle(title); 102 setIcon(icon); 103 } 104 105 public void initialize(MenuItemImpl itemData, int menuType) { 106 mItemData = itemData; 107 108 initialize(itemData.getTitleForItemView(this), itemData.getIcon()); 109 110 setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); 111 setEnabled(itemData.isEnabled()); 112 } 113 114 @Override 115 public boolean performClick() { 116 // Let the view's click listener have top priority (the More button relies on this) 117 if (super.performClick()) { 118 return true; 119 } 120 121 if ((mItemInvoker != null) && (mItemInvoker.invokeItem(mItemData))) { 122 playSoundEffect(SoundEffectConstants.CLICK); 123 return true; 124 } else { 125 return false; 126 } 127 } 128 129 public void setTitle(CharSequence title) { 130 131 if (mShortcutCaptionMode) { 132 /* 133 * Don't set the title directly since it will replace the 134 * shortcut+title being shown. Instead, re-set the shortcut caption 135 * mode so the new title is shown. 136 */ 137 setCaptionMode(true); 138 139 } else if (title != null) { 140 setText(title); 141 } 142 } 143 144 void setCaptionMode(boolean shortcut) { 145 146 mShortcutCaptionMode = shortcut && (mItemData.shouldShowShortcut()); 147 148 /* 149 * If there is no item model, don't do any of the below (for example, 150 * the 'More' item doesn't have a model) 151 */ 152 if (mItemData == null) { 153 return; 154 } 155 156 CharSequence text = mItemData.getTitleForItemView(this); 157 158 if (mShortcutCaptionMode) { 159 160 if (mShortcutCaption == null) { 161 mShortcutCaption = mItemData.getShortcutLabel(); 162 } 163 164 text = mShortcutCaption; 165 } 166 167 setText(text); 168 } 169 170 public void setIcon(Drawable icon) { 171 mIcon = icon; 172 173 if (icon != null) { 174 175 /* Set the bounds of the icon since setCompoundDrawables needs it. */ 176 icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); 177 178 // Set the compound drawables 179 setCompoundDrawables(null, icon, null, null); 180 181 // When there is an icon, make sure the text is at the bottom 182 setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL); 183 184 /* 185 * Request a layout to reposition the icon. The positioning of icon 186 * depends on this TextView's line bounds, which is only available 187 * after a layout. 188 */ 189 requestLayout(); 190 } else { 191 setCompoundDrawables(null, null, null, null); 192 193 // When there is no icon, make sure the text is centered vertically 194 setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL); 195 } 196 } 197 198 public void setItemInvoker(ItemInvoker itemInvoker) { 199 mItemInvoker = itemInvoker; 200 } 201 202 @ViewDebug.CapturedViewProperty(retrieveReturn = true) 203 public MenuItemImpl getItemData() { 204 return mItemData; 205 } 206 207 @Override 208 public void setVisibility(int v) { 209 super.setVisibility(v); 210 211 if (mIconMenuView != null) { 212 // On visibility change, mark the IconMenuView to refresh itself eventually 213 mIconMenuView.markStaleChildren(); 214 } 215 } 216 217 void setIconMenuView(IconMenuView iconMenuView) { 218 mIconMenuView = iconMenuView; 219 } 220 221 @Override 222 protected void drawableStateChanged() { 223 super.drawableStateChanged(); 224 225 if (mItemData != null && mIcon != null) { 226 // When disabled, the not-focused state and the pressed state should 227 // drop alpha on the icon 228 final boolean isInAlphaState = !mItemData.isEnabled() && (isPressed() || !isFocused()); 229 mIcon.setAlpha(isInAlphaState ? (int) (mDisabledAlpha * NO_ALPHA) : NO_ALPHA); 230 } 231 } 232 233 @Override 234 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 235 super.onLayout(changed, left, top, right, bottom); 236 237 positionIcon(); 238 } 239 240 /** 241 * Positions the icon vertically (horizontal centering is taken care of by 242 * the TextView's gravity). 243 */ 244 private void positionIcon() { 245 246 if (mIcon == null) { 247 return; 248 } 249 250 // We reuse the output rectangle as a temp rect 251 Rect tmpRect = mPositionIconOutput; 252 getLineBounds(0, tmpRect); 253 mPositionIconAvailable.set(0, 0, getWidth(), tmpRect.top); 254 Gravity.apply(Gravity.CENTER_VERTICAL | Gravity.LEFT, mIcon.getIntrinsicWidth(), mIcon 255 .getIntrinsicHeight(), mPositionIconAvailable, mPositionIconOutput); 256 mIcon.setBounds(mPositionIconOutput); 257 } 258 259 public void setCheckable(boolean checkable) { 260 } 261 262 public void setChecked(boolean checked) { 263 } 264 265 public void setShortcut(boolean showShortcut, char shortcutKey) { 266 267 if (mShortcutCaptionMode) { 268 /* 269 * Shortcut has changed and we're showing it right now, need to 270 * update (clear the old one first). 271 */ 272 mShortcutCaption = null; 273 setCaptionMode(true); 274 } 275 } 276 277 public boolean prefersCondensedTitle() { 278 return true; 279 } 280 281 public boolean showsIcon() { 282 return true; 283 } 284 285} 286