blob: 7a5c65f6a87efc13b2b840be9d997e32f74cd140 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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 android.view;
18
Tor Norbye7b9c9122013-05-30 16:48:33 -070019import android.annotation.MenuRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.app.Activity;
21import android.content.Context;
Yigit Boyarb8c19b12014-09-17 19:23:21 -070022import android.content.ContextWrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.res.TypedArray;
24import android.content.res.XmlResourceParser;
25import android.util.AttributeSet;
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -070026import android.util.Log;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.util.Xml;
28
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070029import com.android.internal.view.menu.MenuItemImpl;
30
31import org.xmlpull.v1.XmlPullParser;
32import org.xmlpull.v1.XmlPullParserException;
33
Adam Powellcf78b3e2010-09-12 18:25:23 -070034import java.io.IOException;
35import java.lang.reflect.Constructor;
36import java.lang.reflect.Method;
Adam Powell33b97432010-04-20 10:01:14 -070037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038/**
39 * This class is used to instantiate menu XML files into Menu objects.
40 * <p>
41 * For performance reasons, menu inflation relies heavily on pre-processing of
42 * XML files that is done at build time. Therefore, it is not currently possible
43 * to use MenuInflater with an XmlPullParser over a plain XML file at runtime;
44 * it only works with an XmlPullParser returned from a compiled resource (R.
45 * <em>something</em> file.)
46 */
47public class MenuInflater {
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -070048 private static final String LOG_TAG = "MenuInflater";
49
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 /** Menu tag name in XML. */
51 private static final String XML_MENU = "menu";
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 /** Group tag name in XML. */
54 private static final String XML_GROUP = "group";
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 /** Item tag name in XML. */
57 private static final String XML_ITEM = "item";
58
59 private static final int NO_ID = 0;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070060
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -070061 private static final Class<?>[] ACTION_VIEW_CONSTRUCTOR_SIGNATURE = new Class[] {Context.class};
62
63 private static final Class<?>[] ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE = ACTION_VIEW_CONSTRUCTOR_SIGNATURE;
64
65 private final Object[] mActionViewConstructorArguments;
66
67 private final Object[] mActionProviderConstructorArguments;
Adam Powellcf78b3e2010-09-12 18:25:23 -070068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 private Context mContext;
Dianne Hackborn92751972012-05-18 19:22:14 -070070 private Object mRealOwner;
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -070071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 /**
73 * Constructs a menu inflater.
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070074 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 * @see Activity#getMenuInflater()
76 */
77 public MenuInflater(Context context) {
78 mContext = context;
Dianne Hackborn92751972012-05-18 19:22:14 -070079 mActionViewConstructorArguments = new Object[] {context};
80 mActionProviderConstructorArguments = mActionViewConstructorArguments;
81 }
82
83 /**
84 * Constructs a menu inflater.
85 *
86 * @see Activity#getMenuInflater()
87 * @hide
88 */
89 public MenuInflater(Context context, Object realOwner) {
90 mContext = context;
91 mRealOwner = realOwner;
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -070092 mActionViewConstructorArguments = new Object[] {context};
93 mActionProviderConstructorArguments = mActionViewConstructorArguments;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 }
95
96 /**
97 * Inflate a menu hierarchy from the specified XML resource. Throws
98 * {@link InflateException} if there is an error.
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070099 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 * @param menuRes Resource ID for an XML layout resource to load (e.g.,
101 * <code>R.menu.main_activity</code>)
102 * @param menu The Menu to inflate into. The items and submenus will be
103 * added to this Menu.
104 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700105 public void inflate(@MenuRes int menuRes, Menu menu) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 XmlResourceParser parser = null;
107 try {
108 parser = mContext.getResources().getLayout(menuRes);
109 AttributeSet attrs = Xml.asAttributeSet(parser);
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 parseMenu(parser, attrs, menu);
112 } catch (XmlPullParserException e) {
113 throw new InflateException("Error inflating menu XML", e);
114 } catch (IOException e) {
115 throw new InflateException("Error inflating menu XML", e);
116 } finally {
117 if (parser != null) parser.close();
118 }
119 }
120
121 /**
122 * Called internally to fill the given menu. If a sub menu is seen, it will
123 * call this recursively.
124 */
125 private void parseMenu(XmlPullParser parser, AttributeSet attrs, Menu menu)
126 throws XmlPullParserException, IOException {
127 MenuState menuState = new MenuState(menu);
128
129 int eventType = parser.getEventType();
130 String tagName;
131 boolean lookingForEndOfUnknownTag = false;
132 String unknownTagName = null;
133
134 // This loop will skip to the menu start tag
135 do {
136 if (eventType == XmlPullParser.START_TAG) {
137 tagName = parser.getName();
138 if (tagName.equals(XML_MENU)) {
139 // Go to next tag
140 eventType = parser.next();
141 break;
142 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 throw new RuntimeException("Expecting menu, got " + tagName);
145 }
146 eventType = parser.next();
147 } while (eventType != XmlPullParser.END_DOCUMENT);
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 boolean reachedEndOfMenu = false;
150 while (!reachedEndOfMenu) {
151 switch (eventType) {
152 case XmlPullParser.START_TAG:
153 if (lookingForEndOfUnknownTag) {
154 break;
155 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 tagName = parser.getName();
158 if (tagName.equals(XML_GROUP)) {
159 menuState.readGroup(attrs);
160 } else if (tagName.equals(XML_ITEM)) {
161 menuState.readItem(attrs);
162 } else if (tagName.equals(XML_MENU)) {
163 // A menu start tag denotes a submenu for an item
164 SubMenu subMenu = menuState.addSubMenuItem();
Deepanshu Gupta10019612014-04-18 12:32:38 -0700165 registerMenu(subMenu, attrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166
167 // Parse the submenu into returned SubMenu
168 parseMenu(parser, attrs, subMenu);
169 } else {
170 lookingForEndOfUnknownTag = true;
171 unknownTagName = tagName;
172 }
173 break;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 case XmlPullParser.END_TAG:
176 tagName = parser.getName();
177 if (lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) {
178 lookingForEndOfUnknownTag = false;
179 unknownTagName = null;
180 } else if (tagName.equals(XML_GROUP)) {
181 menuState.resetGroup();
182 } else if (tagName.equals(XML_ITEM)) {
183 // Add the item if it hasn't been added (if the item was
184 // a submenu, it would have been added already)
185 if (!menuState.hasAddedItem()) {
Adam Powell961dd112011-07-12 14:25:23 -0700186 if (menuState.itemActionProvider != null &&
187 menuState.itemActionProvider.hasSubMenu()) {
Deepanshu Gupta10019612014-04-18 12:32:38 -0700188 registerMenu(menuState.addSubMenuItem(), attrs);
Adam Powell961dd112011-07-12 14:25:23 -0700189 } else {
Deepanshu Gupta10019612014-04-18 12:32:38 -0700190 registerMenu(menuState.addItem(), attrs);
Adam Powell961dd112011-07-12 14:25:23 -0700191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 }
193 } else if (tagName.equals(XML_MENU)) {
194 reachedEndOfMenu = true;
195 }
196 break;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 case XmlPullParser.END_DOCUMENT:
199 throw new RuntimeException("Unexpected end of document");
200 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 eventType = parser.next();
203 }
204 }
Deepanshu Gupta10019612014-04-18 12:32:38 -0700205
206 /**
207 * The method is a hook for layoutlib to do its magic.
208 * Nothing is needed outside of LayoutLib. However, it should not be deleted because it
209 * appears to do nothing.
210 */
211 private void registerMenu(@SuppressWarnings("unused") MenuItem item,
212 @SuppressWarnings("unused") AttributeSet set) {
213 }
214
215 /**
216 * The method is a hook for layoutlib to do its magic.
217 * Nothing is needed outside of LayoutLib. However, it should not be deleted because it
218 * appears to do nothing.
219 */
220 private void registerMenu(@SuppressWarnings("unused") SubMenu subMenu,
221 @SuppressWarnings("unused") AttributeSet set) {
222 }
223
224 // Needed by layoutlib.
225 /*package*/ Context getContext() {
226 return mContext;
227 }
228
Adam Powell33b97432010-04-20 10:01:14 -0700229 private static class InflatedOnMenuItemClickListener
230 implements MenuItem.OnMenuItemClickListener {
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -0700231 private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700232
Dianne Hackborn92751972012-05-18 19:22:14 -0700233 private Object mRealOwner;
Adam Powell33b97432010-04-20 10:01:14 -0700234 private Method mMethod;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700235
Dianne Hackborn92751972012-05-18 19:22:14 -0700236 public InflatedOnMenuItemClickListener(Object realOwner, String methodName) {
237 mRealOwner = realOwner;
238 Class<?> c = realOwner.getClass();
Adam Powell33b97432010-04-20 10:01:14 -0700239 try {
240 mMethod = c.getMethod(methodName, PARAM_TYPES);
241 } catch (Exception e) {
242 InflateException ex = new InflateException(
243 "Couldn't resolve menu item onClick handler " + methodName +
244 " in class " + c.getName());
245 ex.initCause(e);
246 throw ex;
247 }
248 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700249
Adam Powell33b97432010-04-20 10:01:14 -0700250 public boolean onMenuItemClick(MenuItem item) {
251 try {
252 if (mMethod.getReturnType() == Boolean.TYPE) {
Dianne Hackborn92751972012-05-18 19:22:14 -0700253 return (Boolean) mMethod.invoke(mRealOwner, item);
Adam Powell33b97432010-04-20 10:01:14 -0700254 } else {
Dianne Hackborn92751972012-05-18 19:22:14 -0700255 mMethod.invoke(mRealOwner, item);
Adam Powell33b97432010-04-20 10:01:14 -0700256 return true;
257 }
258 } catch (Exception e) {
259 throw new RuntimeException(e);
260 }
261 }
262 }
Yigit Boyarb8c19b12014-09-17 19:23:21 -0700263
264 private Object getRealOwner() {
265 if (mRealOwner == null) {
266 mRealOwner = findRealOwner(mContext);
267 }
268 return mRealOwner;
269 }
270
271 private Object findRealOwner(Object owner) {
272 if (owner instanceof Activity) {
273 return owner;
274 }
275 if (owner instanceof ContextWrapper) {
276 return findRealOwner(((ContextWrapper) owner).getBaseContext());
277 }
278 return owner;
279 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 /**
282 * State for the current menu.
283 * <p>
284 * Groups can not be nested unless there is another menu (which will have
285 * its state class).
286 */
287 private class MenuState {
288 private Menu menu;
289
290 /*
291 * Group state is set on items as they are added, allowing an item to
292 * override its group state. (As opposed to set on items at the group end tag.)
293 */
294 private int groupId;
295 private int groupCategory;
296 private int groupOrder;
297 private int groupCheckable;
298 private boolean groupVisible;
299 private boolean groupEnabled;
300
301 private boolean itemAdded;
302 private int itemId;
303 private int itemCategoryOrder;
Adam Powell66501852011-01-27 17:10:40 -0800304 private CharSequence itemTitle;
305 private CharSequence itemTitleCondensed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 private int itemIconResId;
307 private char itemAlphabeticShortcut;
308 private char itemNumericShortcut;
309 /**
310 * Sync to attrs.xml enum:
311 * - 0: none
312 * - 1: all
313 * - 2: exclusive
314 */
315 private int itemCheckable;
316 private boolean itemChecked;
317 private boolean itemVisible;
318 private boolean itemEnabled;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700319
Adam Powell96675b12010-06-10 18:58:59 -0700320 /**
Adam Powell89e06452010-06-23 20:24:52 -0700321 * Sync to attrs.xml enum, values in MenuItem:
Adam Powell96675b12010-06-10 18:58:59 -0700322 * - 0: never
323 * - 1: ifRoom
324 * - 2: always
Adam Powell4d9861e2010-08-17 11:14:40 -0700325 * - -1: Safe sentinel for "no value".
Adam Powell96675b12010-06-10 18:58:59 -0700326 */
Adam Powellfbb72fd2010-08-16 18:01:21 -0700327 private int itemShowAsAction;
Adam Powellcf78b3e2010-09-12 18:25:23 -0700328
329 private int itemActionViewLayout;
330 private String itemActionViewClassName;
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -0700331 private String itemActionProviderClassName;
332
Adam Powell33b97432010-04-20 10:01:14 -0700333 private String itemListenerMethodName;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700334
Adam Powell961dd112011-07-12 14:25:23 -0700335 private ActionProvider itemActionProvider;
336
Vladislav Kaznacheev7039cbc2017-01-04 10:15:31 -0800337 private CharSequence itemContentDescription;
Vladislav Kaznacheev6a944ca2017-01-19 11:02:12 -0800338 private CharSequence itemTooltipText;
Vladislav Kaznacheev7039cbc2017-01-04 10:15:31 -0800339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 private static final int defaultGroupId = NO_ID;
341 private static final int defaultItemId = NO_ID;
342 private static final int defaultItemCategory = 0;
343 private static final int defaultItemOrder = 0;
344 private static final int defaultItemCheckable = 0;
345 private static final boolean defaultItemChecked = false;
346 private static final boolean defaultItemVisible = true;
347 private static final boolean defaultItemEnabled = true;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 public MenuState(final Menu menu) {
350 this.menu = menu;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 resetGroup();
353 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 public void resetGroup() {
356 groupId = defaultGroupId;
357 groupCategory = defaultItemCategory;
358 groupOrder = defaultItemOrder;
359 groupCheckable = defaultItemCheckable;
360 groupVisible = defaultItemVisible;
361 groupEnabled = defaultItemEnabled;
362 }
363
364 /**
365 * Called when the parser is pointing to a group tag.
366 */
367 public void readGroup(AttributeSet attrs) {
368 TypedArray a = mContext.obtainStyledAttributes(attrs,
369 com.android.internal.R.styleable.MenuGroup);
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 groupId = a.getResourceId(com.android.internal.R.styleable.MenuGroup_id, defaultGroupId);
372 groupCategory = a.getInt(com.android.internal.R.styleable.MenuGroup_menuCategory, defaultItemCategory);
373 groupOrder = a.getInt(com.android.internal.R.styleable.MenuGroup_orderInCategory, defaultItemOrder);
374 groupCheckable = a.getInt(com.android.internal.R.styleable.MenuGroup_checkableBehavior, defaultItemCheckable);
375 groupVisible = a.getBoolean(com.android.internal.R.styleable.MenuGroup_visible, defaultItemVisible);
376 groupEnabled = a.getBoolean(com.android.internal.R.styleable.MenuGroup_enabled, defaultItemEnabled);
377
378 a.recycle();
379 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 /**
382 * Called when the parser is pointing to an item tag.
383 */
384 public void readItem(AttributeSet attrs) {
385 TypedArray a = mContext.obtainStyledAttributes(attrs,
386 com.android.internal.R.styleable.MenuItem);
387
388 // Inherit attributes from the group as default value
389 itemId = a.getResourceId(com.android.internal.R.styleable.MenuItem_id, defaultItemId);
390 final int category = a.getInt(com.android.internal.R.styleable.MenuItem_menuCategory, groupCategory);
391 final int order = a.getInt(com.android.internal.R.styleable.MenuItem_orderInCategory, groupOrder);
392 itemCategoryOrder = (category & Menu.CATEGORY_MASK) | (order & Menu.USER_MASK);
Adam Powell66501852011-01-27 17:10:40 -0800393 itemTitle = a.getText(com.android.internal.R.styleable.MenuItem_title);
394 itemTitleCondensed = a.getText(com.android.internal.R.styleable.MenuItem_titleCondensed);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 itemIconResId = a.getResourceId(com.android.internal.R.styleable.MenuItem_icon, 0);
396 itemAlphabeticShortcut =
397 getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_alphabeticShortcut));
398 itemNumericShortcut =
399 getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_numericShortcut));
400 if (a.hasValue(com.android.internal.R.styleable.MenuItem_checkable)) {
401 // Item has attribute checkable, use it
402 itemCheckable = a.getBoolean(com.android.internal.R.styleable.MenuItem_checkable, false) ? 1 : 0;
403 } else {
404 // Item does not have attribute, use the group's (group can have one more state
405 // for checkable that represents the exclusive checkable)
406 itemCheckable = groupCheckable;
407 }
408 itemChecked = a.getBoolean(com.android.internal.R.styleable.MenuItem_checked, defaultItemChecked);
409 itemVisible = a.getBoolean(com.android.internal.R.styleable.MenuItem_visible, groupVisible);
410 itemEnabled = a.getBoolean(com.android.internal.R.styleable.MenuItem_enabled, groupEnabled);
Adam Powell4d9861e2010-08-17 11:14:40 -0700411 itemShowAsAction = a.getInt(com.android.internal.R.styleable.MenuItem_showAsAction, -1);
Adam Powell33b97432010-04-20 10:01:14 -0700412 itemListenerMethodName = a.getString(com.android.internal.R.styleable.MenuItem_onClick);
Adam Powellcf78b3e2010-09-12 18:25:23 -0700413 itemActionViewLayout = a.getResourceId(com.android.internal.R.styleable.MenuItem_actionLayout, 0);
414 itemActionViewClassName = a.getString(com.android.internal.R.styleable.MenuItem_actionViewClass);
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -0700415 itemActionProviderClassName = a.getString(com.android.internal.R.styleable.MenuItem_actionProviderClass);
416
Adam Powell961dd112011-07-12 14:25:23 -0700417 final boolean hasActionProvider = itemActionProviderClassName != null;
418 if (hasActionProvider && itemActionViewLayout == 0 && itemActionViewClassName == null) {
419 itemActionProvider = newInstance(itemActionProviderClassName,
420 ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE,
421 mActionProviderConstructorArguments);
422 } else {
423 if (hasActionProvider) {
424 Log.w(LOG_TAG, "Ignoring attribute 'actionProviderClass'."
425 + " Action view already specified.");
426 }
427 itemActionProvider = null;
428 }
429
Vladislav Kaznacheev7039cbc2017-01-04 10:15:31 -0800430 itemContentDescription =
431 a.getText(com.android.internal.R.styleable.MenuItem_contentDescription);
Vladislav Kaznacheev6a944ca2017-01-19 11:02:12 -0800432 itemTooltipText = a.getText(com.android.internal.R.styleable.MenuItem_tooltipText);
Vladislav Kaznacheev7039cbc2017-01-04 10:15:31 -0800433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 a.recycle();
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -0700435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 itemAdded = false;
437 }
438
439 private char getShortcut(String shortcutString) {
440 if (shortcutString == null) {
441 return 0;
442 } else {
443 return shortcutString.charAt(0);
444 }
445 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700446
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 private void setItem(MenuItem item) {
448 item.setChecked(itemChecked)
449 .setVisible(itemVisible)
450 .setEnabled(itemEnabled)
451 .setCheckable(itemCheckable >= 1)
452 .setTitleCondensed(itemTitleCondensed)
453 .setIcon(itemIconResId)
454 .setAlphabeticShortcut(itemAlphabeticShortcut)
Adam Powell4d9861e2010-08-17 11:14:40 -0700455 .setNumericShortcut(itemNumericShortcut);
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700456
Adam Powell4d9861e2010-08-17 11:14:40 -0700457 if (itemShowAsAction >= 0) {
458 item.setShowAsAction(itemShowAsAction);
459 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700460
Adam Powell33b97432010-04-20 10:01:14 -0700461 if (itemListenerMethodName != null) {
Adam Powell5d279772010-07-27 16:34:07 -0700462 if (mContext.isRestricted()) {
463 throw new IllegalStateException("The android:onClick attribute cannot "
464 + "be used within a restricted context");
465 }
Adam Powell33b97432010-04-20 10:01:14 -0700466 item.setOnMenuItemClickListener(
Yigit Boyarb8c19b12014-09-17 19:23:21 -0700467 new InflatedOnMenuItemClickListener(getRealOwner(), itemListenerMethodName));
Adam Powell33b97432010-04-20 10:01:14 -0700468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469
Adam Powell96675b12010-06-10 18:58:59 -0700470 if (item instanceof MenuItemImpl) {
471 MenuItemImpl impl = (MenuItemImpl) item;
472 if (itemCheckable >= 2) {
473 impl.setExclusiveCheckable(true);
474 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 }
Adam Powellcf78b3e2010-09-12 18:25:23 -0700476
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -0700477 boolean actionViewSpecified = false;
Adam Powellcf78b3e2010-09-12 18:25:23 -0700478 if (itemActionViewClassName != null) {
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -0700479 View actionView = (View) newInstance(itemActionViewClassName,
480 ACTION_VIEW_CONSTRUCTOR_SIGNATURE, mActionViewConstructorArguments);
481 item.setActionView(actionView);
482 actionViewSpecified = true;
483 }
484 if (itemActionViewLayout > 0) {
485 if (!actionViewSpecified) {
486 item.setActionView(itemActionViewLayout);
487 actionViewSpecified = true;
488 } else {
489 Log.w(LOG_TAG, "Ignoring attribute 'itemActionViewLayout'."
490 + " Action view already specified.");
Adam Powellcf78b3e2010-09-12 18:25:23 -0700491 }
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -0700492 }
Adam Powell961dd112011-07-12 14:25:23 -0700493 if (itemActionProvider != null) {
494 item.setActionProvider(itemActionProvider);
Adam Powellcf78b3e2010-09-12 18:25:23 -0700495 }
Vladislav Kaznacheev7039cbc2017-01-04 10:15:31 -0800496
497 item.setContentDescription(itemContentDescription);
Vladislav Kaznacheev6a944ca2017-01-19 11:02:12 -0800498 item.setTooltipText(itemTooltipText);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 }
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -0700500
Deepanshu Gupta10019612014-04-18 12:32:38 -0700501 public MenuItem addItem() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 itemAdded = true;
Deepanshu Gupta10019612014-04-18 12:32:38 -0700503 MenuItem item = menu.add(groupId, itemId, itemCategoryOrder, itemTitle);
504 setItem(item);
505 return item;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 public SubMenu addSubMenuItem() {
509 itemAdded = true;
510 SubMenu subMenu = menu.addSubMenu(groupId, itemId, itemCategoryOrder, itemTitle);
511 setItem(subMenu.getItem());
512 return subMenu;
513 }
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 public boolean hasAddedItem() {
516 return itemAdded;
517 }
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -0700518
519 @SuppressWarnings("unchecked")
520 private <T> T newInstance(String className, Class<?>[] constructorSignature,
521 Object[] arguments) {
522 try {
523 Class<?> clazz = mContext.getClassLoader().loadClass(className);
524 Constructor<?> constructor = clazz.getConstructor(constructorSignature);
Alan Viverette904de2e2015-05-04 10:32:57 -0700525 constructor.setAccessible(true);
Svetoslav Ganov51ac0e92011-06-17 13:45:13 -0700526 return (T) constructor.newInstance(arguments);
527 } catch (Exception e) {
528 Log.w(LOG_TAG, "Cannot instantiate class: " + className, e);
529 }
530 return null;
531 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533}