Home | History | Annotate | Download | only in menu
      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