blob: 0d2b29b695864a2519c4b6c28e2319962ddc708c [file] [log] [blame]
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.view.menu;
import com.android.internal.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.AbsListView;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.TextView;
/**
* The item view for each item in the ListView-based MenuViews.
*/
public class ListMenuItemView extends LinearLayout
implements MenuView.ItemView, AbsListView.SelectionBoundsAdjuster {
private static final String TAG = "ListMenuItemView";
private MenuItemImpl mItemData;
private ImageView mIconView;
private RadioButton mRadioButton;
private TextView mTitleView;
private CheckBox mCheckBox;
private TextView mShortcutView;
private ImageView mSubMenuArrowView;
private ImageView mGroupDivider;
private LinearLayout mContent;
private Drawable mBackground;
private int mTextAppearance;
private Context mTextAppearanceContext;
private boolean mPreserveIconSpacing;
private Drawable mSubMenuArrow;
private boolean mHasListDivider;
private int mMenuType;
private LayoutInflater mInflater;
private boolean mForceShowIcon;
public ListMenuItemView(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.MenuView, defStyleAttr, defStyleRes);
mBackground = a.getDrawable(com.android.internal.R.styleable.MenuView_itemBackground);
mTextAppearance = a.getResourceId(com.android.internal.R.styleable.
MenuView_itemTextAppearance, -1);
mPreserveIconSpacing = a.getBoolean(
com.android.internal.R.styleable.MenuView_preserveIconSpacing, false);
mTextAppearanceContext = context;
mSubMenuArrow = a.getDrawable(com.android.internal.R.styleable.MenuView_subMenuArrow);
final TypedArray b = context.getTheme()
.obtainStyledAttributes(null, new int[] { com.android.internal.R.attr.divider },
com.android.internal.R.attr.dropDownListViewStyle, 0);
mHasListDivider = b.hasValue(0);
a.recycle();
b.recycle();
}
public ListMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public ListMenuItemView(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.listMenuViewStyle);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
setBackgroundDrawable(mBackground);
mTitleView = findViewById(com.android.internal.R.id.title);
if (mTextAppearance != -1) {
mTitleView.setTextAppearance(mTextAppearanceContext,
mTextAppearance);
}
mShortcutView = findViewById(com.android.internal.R.id.shortcut);
mSubMenuArrowView = findViewById(com.android.internal.R.id.submenuarrow);
if (mSubMenuArrowView != null) {
mSubMenuArrowView.setImageDrawable(mSubMenuArrow);
}
mGroupDivider = findViewById(com.android.internal.R.id.group_divider);
mContent = findViewById(com.android.internal.R.id.content);
}
public void initialize(MenuItemImpl itemData, int menuType) {
mItemData = itemData;
mMenuType = menuType;
setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
setTitle(itemData.getTitleForItemView(this));
setCheckable(itemData.isCheckable());
setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut());
setIcon(itemData.getIcon());
setEnabled(itemData.isEnabled());
setSubMenuArrowVisible(itemData.hasSubMenu());
setContentDescription(itemData.getContentDescription());
}
private void addContentView(View v) {
addContentView(v, -1);
}
private void addContentView(View v, int index) {
if (mContent != null) {
mContent.addView(v, index);
} else {
addView(v, index);
}
}
public void setForceShowIcon(boolean forceShow) {
mPreserveIconSpacing = mForceShowIcon = forceShow;
}
public void setTitle(CharSequence title) {
if (title != null) {
mTitleView.setText(title);
if (mTitleView.getVisibility() != VISIBLE) mTitleView.setVisibility(VISIBLE);
} else {
if (mTitleView.getVisibility() != GONE) mTitleView.setVisibility(GONE);
}
}
public MenuItemImpl getItemData() {
return mItemData;
}
public void setCheckable(boolean checkable) {
if (!checkable && mRadioButton == null && mCheckBox == null) {
return;
}
// Depending on whether its exclusive check or not, the checkbox or
// radio button will be the one in use (and the other will be otherCompoundButton)
final CompoundButton compoundButton;
final CompoundButton otherCompoundButton;
if (mItemData.isExclusiveCheckable()) {
if (mRadioButton == null) {
insertRadioButton();
}
compoundButton = mRadioButton;
otherCompoundButton = mCheckBox;
} else {
if (mCheckBox == null) {
insertCheckBox();
}
compoundButton = mCheckBox;
otherCompoundButton = mRadioButton;
}
if (checkable) {
compoundButton.setChecked(mItemData.isChecked());
final int newVisibility = checkable ? VISIBLE : GONE;
if (compoundButton.getVisibility() != newVisibility) {
compoundButton.setVisibility(newVisibility);
}
// Make sure the other compound button isn't visible
if (otherCompoundButton != null && otherCompoundButton.getVisibility() != GONE) {
otherCompoundButton.setVisibility(GONE);
}
} else {
if (mCheckBox != null) mCheckBox.setVisibility(GONE);
if (mRadioButton != null) mRadioButton.setVisibility(GONE);
}
}
public void setChecked(boolean checked) {
CompoundButton compoundButton;
if (mItemData.isExclusiveCheckable()) {
if (mRadioButton == null) {
insertRadioButton();
}
compoundButton = mRadioButton;
} else {
if (mCheckBox == null) {
insertCheckBox();
}
compoundButton = mCheckBox;
}
compoundButton.setChecked(checked);
}
private void setSubMenuArrowVisible(boolean hasSubmenu) {
if (mSubMenuArrowView != null) {
mSubMenuArrowView.setVisibility(hasSubmenu ? View.VISIBLE : View.GONE);
}
}
public void setShortcut(boolean showShortcut, char shortcutKey) {
final int newVisibility = (showShortcut && mItemData.shouldShowShortcut())
? VISIBLE : GONE;
if (newVisibility == VISIBLE) {
mShortcutView.setText(mItemData.getShortcutLabel());
}
if (mShortcutView.getVisibility() != newVisibility) {
mShortcutView.setVisibility(newVisibility);
}
}
public void setIcon(Drawable icon) {
final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon;
if (!showIcon && !mPreserveIconSpacing) {
return;
}
if (mIconView == null && icon == null && !mPreserveIconSpacing) {
return;
}
if (mIconView == null) {
insertIconView();
}
if (icon != null || mPreserveIconSpacing) {
mIconView.setImageDrawable(showIcon ? icon : null);
if (mIconView.getVisibility() != VISIBLE) {
mIconView.setVisibility(VISIBLE);
}
} else {
mIconView.setVisibility(GONE);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mIconView != null && mPreserveIconSpacing) {
// Enforce minimum icon spacing
ViewGroup.LayoutParams lp = getLayoutParams();
LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
if (lp.height > 0 && iconLp.width <= 0) {
iconLp.width = lp.height;
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void insertIconView() {
LayoutInflater inflater = getInflater();
mIconView = (ImageView) inflater.inflate(com.android.internal.R.layout.list_menu_item_icon,
this, false);
addContentView(mIconView, 0);
}
private void insertRadioButton() {
LayoutInflater inflater = getInflater();
mRadioButton =
(RadioButton) inflater.inflate(com.android.internal.R.layout.list_menu_item_radio,
this, false);
addContentView(mRadioButton);
}
private void insertCheckBox() {
LayoutInflater inflater = getInflater();
mCheckBox =
(CheckBox) inflater.inflate(com.android.internal.R.layout.list_menu_item_checkbox,
this, false);
addContentView(mCheckBox);
}
public boolean prefersCondensedTitle() {
return false;
}
public boolean showsIcon() {
return mForceShowIcon;
}
private LayoutInflater getInflater() {
if (mInflater == null) {
mInflater = LayoutInflater.from(mContext);
}
return mInflater;
}
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
if (mItemData != null && mItemData.hasSubMenu()) {
info.setCanOpenPopup(true);
}
}
/**
* Enable or disable group dividers for this view.
*/
public void setGroupDividerEnabled(boolean groupDividerEnabled) {
// If mHasListDivider is true, disabling the groupDivider.
// Otherwise, checking enbling it according to groupDividerEnabled flag.
if (mGroupDivider != null) {
mGroupDivider.setVisibility(!mHasListDivider
&& groupDividerEnabled ? View.VISIBLE : View.GONE);
}
}
@Override
public void adjustListItemSelectionBounds(Rect rect) {
if (mGroupDivider != null && mGroupDivider.getVisibility() == View.VISIBLE) {
// groupDivider is a part of MenuItemListView.
// If ListMenuItem with divider enabled is hovered/clicked, divider also gets selected.
// Clipping the selector bounds from the top divider portion when divider is enabled,
// so that divider does not get selected on hover or click.
final LayoutParams lp = (LayoutParams) mGroupDivider.getLayoutParams();
rect.top += mGroupDivider.getHeight() + lp.topMargin + lp.bottomMargin;
}
}
}