package com.actionbarsherlock.view;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
import android.view.InflateException;
import android.view.View;
import com.actionbarsherlock.internal.view.menu.MenuItemImpl;
public class {
private static final String LOG_TAG = "MenuInflater";
private static final String XML_NS = "http://schemas.android.com/apk/res/android";
private static final String XML_MENU = "menu";
private static final String XML_GROUP = "group";
private static final String XML_ITEM = "item";
private static final int NO_ID = 0;
private static final Class<?>[] ACTION_VIEW_CONSTRUCTOR_SIGNATURE = new Class[] {Context.class};
private static final Class<?>[] ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE = ACTION_VIEW_CONSTRUCTOR_SIGNATURE;
private final Object[] mActionViewConstructorArguments;
private final Object[] mActionProviderConstructorArguments;
private Context mContext;
public (Context context) {
mContext = context;
mActionViewConstructorArguments = new Object[] {context};
mActionProviderConstructorArguments = mActionViewConstructorArguments;
}
public void (int menuRes, Menu menu) {
XmlResourceParser parser = null;
try {
parser = mContext.getResources().getLayout(menuRes);
AttributeSet attrs = Xml.asAttributeSet(parser);
parseMenu(parser, attrs, menu);
} catch (XmlPullParserException e) {
throw new InflateException("Error inflating menu XML", e);
} catch (IOException e) {
throw new InflateException("Error inflating menu XML", e);
} finally {
if (parser != null) parser.close();
}
}
private void (XmlPullParser parser, AttributeSet attrs, Menu menu)
throws XmlPullParserException, IOException {
MenuState menuState = new MenuState(menu);
int eventType = parser.getEventType();
String tagName;
boolean lookingForEndOfUnknownTag = false;
String unknownTagName = null;
do {
if (eventType == XmlPullParser.START_TAG) {
tagName = parser.getName();
if (tagName.equals(XML_MENU)) {
eventType = parser.next();
break;
}
throw new RuntimeException("Expecting menu, got " + tagName);
}
eventType = parser.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
boolean reachedEndOfMenu = false;
while (!reachedEndOfMenu) {
switch (eventType) {
case XmlPullParser.START_TAG:
if (lookingForEndOfUnknownTag) {
break;
}
tagName = parser.getName();
if (tagName.equals(XML_GROUP)) {
menuState.readGroup(attrs);
} else if (tagName.equals(XML_ITEM)) {
menuState.readItem(attrs);
} else if (tagName.equals(XML_MENU)) {
SubMenu subMenu = menuState.addSubMenuItem();
parseMenu(parser, attrs, subMenu);
} else {
lookingForEndOfUnknownTag = true;
unknownTagName = tagName;
}
break;
case XmlPullParser.END_TAG:
tagName = parser.getName();
if (lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) {
lookingForEndOfUnknownTag = false;
unknownTagName = null;
} else if (tagName.equals(XML_GROUP)) {
menuState.resetGroup();
} else if (tagName.equals(XML_ITEM)) {
if (!menuState.hasAddedItem()) {
if (menuState.itemActionProvider != null &&
menuState.itemActionProvider.hasSubMenu()) {
menuState.addSubMenuItem();
} else {
menuState.addItem();
}
}
} else if (tagName.equals(XML_MENU)) {
reachedEndOfMenu = true;
}
break;
case XmlPullParser.END_DOCUMENT:
throw new RuntimeException("Unexpected end of document");
}
eventType = parser.next();
}
}
private static class
implements MenuItem.OnMenuItemClickListener {
private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };
private Context mContext;
private Method mMethod;
public (Context context, String methodName) {
mContext = context;
Class<?> c = context.getClass();
try {
mMethod = c.getMethod(methodName, PARAM_TYPES);
} catch (Exception e) {
InflateException ex = new InflateException(
"Couldn't resolve menu item onClick handler " + methodName +
" in class " + c.getName());
ex.initCause(e);
throw ex;
}
}
public boolean (MenuItem item) {
try {
if (mMethod.getReturnType() == Boolean.TYPE) {
return (Boolean) mMethod.invoke(mContext, item);
} else {
mMethod.invoke(mContext, item);
return true;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private class {
private Menu menu;
private int groupId;
private int groupCategory;
private int groupOrder;
private int groupCheckable;
private boolean groupVisible;
private boolean groupEnabled;
private boolean itemAdded;
private int itemId;
private int itemCategoryOrder;
private CharSequence itemTitle;
private CharSequence itemTitleCondensed;
private int itemIconResId;
private char itemAlphabeticShortcut;
private char itemNumericShortcut;
private int itemCheckable;
private boolean itemChecked;
private boolean itemVisible;
private boolean itemEnabled;
private int itemShowAsAction;
private int itemActionViewLayout;
private String itemActionViewClassName;
private String itemActionProviderClassName;
private String itemListenerMethodName;
private ActionProvider itemActionProvider;
private static final int defaultGroupId = NO_ID;
private static final int defaultItemId = NO_ID;
private static final int defaultItemCategory = 0;
private static final int defaultItemOrder = 0;
private static final int defaultItemCheckable = 0;
private static final boolean defaultItemChecked = false;
private static final boolean defaultItemVisible = true;
private static final boolean defaultItemEnabled = true;
public (final Menu menu) {
this.menu = menu;
resetGroup();
}
groupId = defaultGroupId;
groupCategory = defaultItemCategory;
groupOrder = defaultItemOrder;
groupCheckable = defaultItemCheckable;
groupVisible = defaultItemVisible;
groupEnabled = defaultItemEnabled;
}
groupId = attrs.getAttributeResourceValue(XML_NS, "id", defaultGroupId);
groupCategory = attrs.getAttributeIntValue(XML_NS, "menuCategory", defaultItemCategory);
groupOrder = attrs.getAttributeIntValue(XML_NS, "orderInCategory", defaultItemOrder);
groupCheckable = attrs.getAttributeIntValue(XML_NS, "checkableBehavior", defaultItemCheckable);
groupVisible = attrs.getAttributeBooleanValue(XML_NS, "visible", defaultItemVisible);
groupEnabled = attrs.getAttributeBooleanValue(XML_NS, "enabled", defaultItemEnabled);
}
public void readItem(AttributeSet attrs) {
itemId = attrs.getAttributeResourceValue(XML_NS, "id", defaultItemId);
final int category = attrs.getAttributeIntValue(XML_NS, "menuCategory", groupCategory);
final int order = attrs.getAttributeIntValue(XML_NS, "orderInCategory", groupOrder);
itemCategoryOrder = (category & Menu.CATEGORY_MASK) | (order & Menu.USER_MASK);
final int itemTitleId = attrs.getAttributeResourceValue(XML_NS, "title", 0);
if (itemTitleId != 0) {
itemTitle = mContext.getString(itemTitleId);
} else {
itemTitle = attrs.getAttributeValue(XML_NS, "title");
}
final int itemTitleCondensedId = attrs.getAttributeResourceValue(XML_NS, "titleCondensed", 0);
if (itemTitleCondensedId != 0) {
itemTitleCondensed = mContext.getString(itemTitleCondensedId);
} else {
itemTitleCondensed = attrs.getAttributeValue(XML_NS, "titleCondensed");
}
itemIconResId = attrs.getAttributeResourceValue(XML_NS, "icon", 0);
itemAlphabeticShortcut = getShortcut(attrs.getAttributeValue(XML_NS, "alphabeticShortcut"));
itemNumericShortcut = getShortcut(attrs.getAttributeValue(XML_NS, "numericShortcut"));
if (attrs.getAttributeValue(XML_NS, "checkable") != null) {
itemCheckable = attrs.getAttributeBooleanValue(XML_NS, "checkable", false) ? 1 : 0;
} else {
itemCheckable = groupCheckable;
}
itemChecked = attrs.getAttributeBooleanValue(XML_NS, "checked", defaultItemChecked);
itemVisible = attrs.getAttributeBooleanValue(XML_NS, "visible", groupVisible);
itemEnabled = attrs.getAttributeBooleanValue(XML_NS, "enabled", groupEnabled);
itemShowAsAction = attrs.getAttributeIntValue(XML_NS, "showAsAction", -1);
itemListenerMethodName = attrs.getAttributeValue(XML_NS, "onClick");
itemActionViewLayout = attrs.getAttributeResourceValue(XML_NS, "actionLayout", 0);
itemActionViewClassName = attrs.getAttributeValue(XML_NS, "actionViewClass");
itemActionProviderClassName = attrs.getAttributeValue(XML_NS, "actionProviderClass");
final boolean hasActionProvider = itemActionProviderClassName != null;
if (hasActionProvider && itemActionViewLayout == 0 && itemActionViewClassName == null) {
itemActionProvider = newInstance(itemActionProviderClassName,
ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE,
mActionProviderConstructorArguments);
} else {
if (hasActionProvider) {
Log.w(LOG_TAG, "Ignoring attribute 'actionProviderClass'."
+ " Action view already specified.");
}
itemActionProvider = null;
}
itemAdded = false;
}
if (shortcutString == null) {
return 0;
} else {
return shortcutString.charAt(0);
}
}
private void (MenuItem item) {
item.setChecked(itemChecked)
.setVisible(itemVisible)
.setEnabled(itemEnabled)
.setCheckable(itemCheckable >= 1)
.setTitleCondensed(itemTitleCondensed)
.setIcon(itemIconResId)
.setAlphabeticShortcut(itemAlphabeticShortcut)
.setNumericShortcut(itemNumericShortcut);
if (itemShowAsAction >= 0) {
item.setShowAsAction(itemShowAsAction);
}
if (itemListenerMethodName != null) {
if (mContext.isRestricted()) {
throw new IllegalStateException("The android:onClick attribute cannot "
+ "be used within a restricted context");
}
item.setOnMenuItemClickListener(
new InflatedOnMenuItemClickListener(mContext, itemListenerMethodName));
}
if (item instanceof MenuItemImpl) {
MenuItemImpl impl = (MenuItemImpl) item;
if (itemCheckable >= 2) {
impl.setExclusiveCheckable(true);
}
}
boolean actionViewSpecified = false;
if (itemActionViewClassName != null) {
View actionView = (View) newInstance(itemActionViewClassName,
ACTION_VIEW_CONSTRUCTOR_SIGNATURE, mActionViewConstructorArguments);
item.setActionView(actionView);
actionViewSpecified = true;
}
if (itemActionViewLayout > 0) {
if (!actionViewSpecified) {
item.setActionView(itemActionViewLayout);
actionViewSpecified = true;
} else {
Log.w(LOG_TAG, "Ignoring attribute 'itemActionViewLayout'."
+ " Action view already specified.");
}
}
if (itemActionProvider != null) {
item.setActionProvider(itemActionProvider);
}
}
itemAdded = true;
setItem(menu.add(groupId, itemId, itemCategoryOrder, itemTitle));
}
public SubMenu () {
itemAdded = true;
SubMenu subMenu = menu.addSubMenu(groupId, itemId, itemCategoryOrder, itemTitle);
setItem(subMenu.getItem());
return subMenu;
}
return itemAdded;
}
@SuppressWarnings("unchecked")
private <T> T
newInstance(String className, Class<?>[] constructorSignature,
Object[] arguments) {
try {
Class<?> clazz = mContext.getClassLoader().loadClass(className);
Constructor<?> constructor = clazz.getConstructor(constructorSignature);
return (T) constructor.newInstance(arguments);
} catch (Exception e) {
Log.w(LOG_TAG, "Cannot instantiate class: " + className, e);
}
return null;
}
}
}