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