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 17 package com.android.internal.view.menu; 18 19 import android.content.Context; 20 import android.content.res.TypedArray; 21 import android.graphics.drawable.Drawable; 22 import android.util.AttributeSet; 23 import android.view.LayoutInflater; 24 import android.view.View; 25 import android.view.ViewGroup; 26 import android.view.accessibility.AccessibilityNodeInfo; 27 import android.widget.CheckBox; 28 import android.widget.CompoundButton; 29 import android.widget.ImageView; 30 import android.widget.LinearLayout; 31 import android.widget.RadioButton; 32 import android.widget.TextView; 33 34 /** 35 * The item view for each item in the ListView-based MenuViews. 36 */ 37 public class ListMenuItemView extends LinearLayout implements MenuView.ItemView { 38 private static final String TAG = "ListMenuItemView"; 39 private MenuItemImpl mItemData; 40 41 private ImageView mIconView; 42 private RadioButton mRadioButton; 43 private TextView mTitleView; 44 private CheckBox mCheckBox; 45 private TextView mShortcutView; 46 private ImageView mSubMenuArrowView; 47 48 private Drawable mBackground; 49 private int mTextAppearance; 50 private Context mTextAppearanceContext; 51 private boolean mPreserveIconSpacing; 52 private Drawable mSubMenuArrow; 53 54 private int mMenuType; 55 56 private LayoutInflater mInflater; 57 58 private boolean mForceShowIcon; 59 60 public ListMenuItemView( 61 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 62 super(context, attrs, defStyleAttr, defStyleRes); 63 64 final TypedArray a = context.obtainStyledAttributes( 65 attrs, com.android.internal.R.styleable.MenuView, defStyleAttr, defStyleRes); 66 67 mBackground = a.getDrawable(com.android.internal.R.styleable.MenuView_itemBackground); 68 mTextAppearance = a.getResourceId(com.android.internal.R.styleable. 69 MenuView_itemTextAppearance, -1); 70 mPreserveIconSpacing = a.getBoolean( 71 com.android.internal.R.styleable.MenuView_preserveIconSpacing, false); 72 mTextAppearanceContext = context; 73 mSubMenuArrow = a.getDrawable(com.android.internal.R.styleable.MenuView_subMenuArrow); 74 75 a.recycle(); 76 } 77 78 public ListMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) { 79 this(context, attrs, defStyleAttr, 0); 80 } 81 82 public ListMenuItemView(Context context, AttributeSet attrs) { 83 this(context, attrs, com.android.internal.R.attr.listMenuViewStyle); 84 } 85 86 @Override 87 protected void onFinishInflate() { 88 super.onFinishInflate(); 89 90 setBackgroundDrawable(mBackground); 91 92 mTitleView = findViewById(com.android.internal.R.id.title); 93 if (mTextAppearance != -1) { 94 mTitleView.setTextAppearance(mTextAppearanceContext, 95 mTextAppearance); 96 } 97 98 mShortcutView = findViewById(com.android.internal.R.id.shortcut); 99 mSubMenuArrowView = findViewById(com.android.internal.R.id.submenuarrow); 100 if (mSubMenuArrowView != null) { 101 mSubMenuArrowView.setImageDrawable(mSubMenuArrow); 102 } 103 } 104 105 public void initialize(MenuItemImpl itemData, int menuType) { 106 mItemData = itemData; 107 mMenuType = menuType; 108 109 setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); 110 111 setTitle(itemData.getTitleForItemView(this)); 112 setCheckable(itemData.isCheckable()); 113 setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut()); 114 setIcon(itemData.getIcon()); 115 setEnabled(itemData.isEnabled()); 116 setSubMenuArrowVisible(itemData.hasSubMenu()); 117 setContentDescription(itemData.getContentDescription()); 118 } 119 120 public void setForceShowIcon(boolean forceShow) { 121 mPreserveIconSpacing = mForceShowIcon = forceShow; 122 } 123 124 public void setTitle(CharSequence title) { 125 if (title != null) { 126 mTitleView.setText(title); 127 128 if (mTitleView.getVisibility() != VISIBLE) mTitleView.setVisibility(VISIBLE); 129 } else { 130 if (mTitleView.getVisibility() != GONE) mTitleView.setVisibility(GONE); 131 } 132 } 133 134 public MenuItemImpl getItemData() { 135 return mItemData; 136 } 137 138 public void setCheckable(boolean checkable) { 139 if (!checkable && mRadioButton == null && mCheckBox == null) { 140 return; 141 } 142 143 // Depending on whether its exclusive check or not, the checkbox or 144 // radio button will be the one in use (and the other will be otherCompoundButton) 145 final CompoundButton compoundButton; 146 final CompoundButton otherCompoundButton; 147 148 if (mItemData.isExclusiveCheckable()) { 149 if (mRadioButton == null) { 150 insertRadioButton(); 151 } 152 compoundButton = mRadioButton; 153 otherCompoundButton = mCheckBox; 154 } else { 155 if (mCheckBox == null) { 156 insertCheckBox(); 157 } 158 compoundButton = mCheckBox; 159 otherCompoundButton = mRadioButton; 160 } 161 162 if (checkable) { 163 compoundButton.setChecked(mItemData.isChecked()); 164 165 final int newVisibility = checkable ? VISIBLE : GONE; 166 if (compoundButton.getVisibility() != newVisibility) { 167 compoundButton.setVisibility(newVisibility); 168 } 169 170 // Make sure the other compound button isn't visible 171 if (otherCompoundButton != null && otherCompoundButton.getVisibility() != GONE) { 172 otherCompoundButton.setVisibility(GONE); 173 } 174 } else { 175 if (mCheckBox != null) mCheckBox.setVisibility(GONE); 176 if (mRadioButton != null) mRadioButton.setVisibility(GONE); 177 } 178 } 179 180 public void setChecked(boolean checked) { 181 CompoundButton compoundButton; 182 183 if (mItemData.isExclusiveCheckable()) { 184 if (mRadioButton == null) { 185 insertRadioButton(); 186 } 187 compoundButton = mRadioButton; 188 } else { 189 if (mCheckBox == null) { 190 insertCheckBox(); 191 } 192 compoundButton = mCheckBox; 193 } 194 195 compoundButton.setChecked(checked); 196 } 197 198 private void setSubMenuArrowVisible(boolean hasSubmenu) { 199 if (mSubMenuArrowView != null) { 200 mSubMenuArrowView.setVisibility(hasSubmenu ? View.VISIBLE : View.GONE); 201 } 202 } 203 204 public void setShortcut(boolean showShortcut, char shortcutKey) { 205 final int newVisibility = (showShortcut && mItemData.shouldShowShortcut()) 206 ? VISIBLE : GONE; 207 208 if (newVisibility == VISIBLE) { 209 mShortcutView.setText(mItemData.getShortcutLabel()); 210 } 211 212 if (mShortcutView.getVisibility() != newVisibility) { 213 mShortcutView.setVisibility(newVisibility); 214 } 215 } 216 217 public void setIcon(Drawable icon) { 218 final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon; 219 if (!showIcon && !mPreserveIconSpacing) { 220 return; 221 } 222 223 if (mIconView == null && icon == null && !mPreserveIconSpacing) { 224 return; 225 } 226 227 if (mIconView == null) { 228 insertIconView(); 229 } 230 231 if (icon != null || mPreserveIconSpacing) { 232 mIconView.setImageDrawable(showIcon ? icon : null); 233 234 if (mIconView.getVisibility() != VISIBLE) { 235 mIconView.setVisibility(VISIBLE); 236 } 237 } else { 238 mIconView.setVisibility(GONE); 239 } 240 } 241 242 @Override 243 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 244 if (mIconView != null && mPreserveIconSpacing) { 245 // Enforce minimum icon spacing 246 ViewGroup.LayoutParams lp = getLayoutParams(); 247 LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams(); 248 if (lp.height > 0 && iconLp.width <= 0) { 249 iconLp.width = lp.height; 250 } 251 } 252 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 253 } 254 255 private void insertIconView() { 256 LayoutInflater inflater = getInflater(); 257 mIconView = (ImageView) inflater.inflate(com.android.internal.R.layout.list_menu_item_icon, 258 this, false); 259 addView(mIconView, 0); 260 } 261 262 private void insertRadioButton() { 263 LayoutInflater inflater = getInflater(); 264 mRadioButton = 265 (RadioButton) inflater.inflate(com.android.internal.R.layout.list_menu_item_radio, 266 this, false); 267 addView(mRadioButton); 268 } 269 270 private void insertCheckBox() { 271 LayoutInflater inflater = getInflater(); 272 mCheckBox = 273 (CheckBox) inflater.inflate(com.android.internal.R.layout.list_menu_item_checkbox, 274 this, false); 275 addView(mCheckBox); 276 } 277 278 public boolean prefersCondensedTitle() { 279 return false; 280 } 281 282 public boolean showsIcon() { 283 return mForceShowIcon; 284 } 285 286 private LayoutInflater getInflater() { 287 if (mInflater == null) { 288 mInflater = LayoutInflater.from(mContext); 289 } 290 return mInflater; 291 } 292 293 @Override 294 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 295 super.onInitializeAccessibilityNodeInfoInternal(info); 296 297 if (mItemData != null && mItemData.hasSubMenu()) { 298 info.setCanOpenPopup(true); 299 } 300 } 301 } 302