summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenuInflater.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenuInflater.java')
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenuInflater.java163
1 files changed, 163 insertions, 0 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenuInflater.java b/mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenuInflater.java
new file mode 100644
index 000000000..dfcb31c5f
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenuInflater.java
@@ -0,0 +1,163 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.menu;
+
+import java.io.IOException;
+
+import org.mozilla.gecko.AppConstants.Versions;
+import org.mozilla.gecko.R;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.AttributeSet;
+import android.util.Xml;
+import android.view.InflateException;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.SubMenu;
+
+public class GeckoMenuInflater extends MenuInflater {
+ private static final String TAG_MENU = "menu";
+ private static final String TAG_ITEM = "item";
+ private static final int NO_ID = 0;
+
+ private final Context mContext;
+
+ // Private class to hold the parsed menu item.
+ private class ParsedItem {
+ public int id;
+ public int order;
+ public CharSequence title;
+ public int iconRes;
+ public boolean checkable;
+ public boolean checked;
+ public boolean visible;
+ public boolean enabled;
+ public int showAsAction;
+ public boolean hasSubMenu;
+ }
+
+ public GeckoMenuInflater(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ @Override
+ public void inflate(int menuRes, Menu menu) {
+
+ // This does not check for a well-formed XML.
+
+ XmlResourceParser parser = null;
+ try {
+ parser = mContext.getResources().getXml(menuRes);
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ parseMenu(parser, attrs, menu);
+
+ } catch (XmlPullParserException | IOException e) {
+ throw new InflateException("Error inflating menu XML", e);
+ } finally {
+ if (parser != null)
+ parser.close();
+ }
+ }
+
+ private void parseMenu(XmlResourceParser parser, AttributeSet attrs, Menu menu)
+ throws XmlPullParserException, IOException {
+ ParsedItem item = null;
+
+ String tag;
+ int eventType = parser.getEventType();
+
+ do {
+ tag = parser.getName();
+
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ if (tag.equals(TAG_ITEM)) {
+ // Parse the menu item.
+ item = new ParsedItem();
+ parseItem(item, attrs);
+ } else if (tag.equals(TAG_MENU)) {
+ if (item != null) {
+ // Add the submenu item.
+ SubMenu subMenu = menu.addSubMenu(NO_ID, item.id, item.order, item.title);
+ item.hasSubMenu = true;
+
+ // Set the menu item in main menu.
+ MenuItem menuItem = subMenu.getItem();
+ setValues(item, menuItem);
+
+ // Start parsing the sub menu.
+ parseMenu(parser, attrs, subMenu);
+ }
+ }
+ break;
+
+ case XmlPullParser.END_TAG:
+ if (parser.getName().equals(TAG_ITEM)) {
+ if (!item.hasSubMenu) {
+ // Add the item.
+ MenuItem menuItem = menu.add(NO_ID, item.id, item.order, item.title);
+ setValues(item, menuItem);
+ }
+ } else if (tag.equals(TAG_MENU)) {
+ return;
+ }
+ break;
+ }
+
+ eventType = parser.next();
+
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+ }
+
+ public void parseItem(ParsedItem item, AttributeSet attrs) {
+ TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.MenuItem);
+
+ item.id = a.getResourceId(R.styleable.MenuItem_android_id, NO_ID);
+ item.order = a.getInt(R.styleable.MenuItem_android_orderInCategory, 0);
+ item.title = a.getText(R.styleable.MenuItem_android_title);
+ item.checkable = a.getBoolean(R.styleable.MenuItem_android_checkable, false);
+ item.checked = a.getBoolean(R.styleable.MenuItem_android_checked, false);
+ item.visible = a.getBoolean(R.styleable.MenuItem_android_visible, true);
+ item.enabled = a.getBoolean(R.styleable.MenuItem_android_enabled, true);
+ item.hasSubMenu = false;
+ item.iconRes = a.getResourceId(R.styleable.MenuItem_android_icon, 0);
+ item.showAsAction = a.getInt(R.styleable.MenuItem_android_showAsAction, 0);
+
+ a.recycle();
+ }
+
+ public void setValues(ParsedItem item, MenuItem menuItem) {
+ // We are blocking any presenter updates during inflation.
+ GeckoMenuItem geckoItem = null;
+ if (menuItem instanceof GeckoMenuItem) {
+ geckoItem = (GeckoMenuItem) menuItem;
+ }
+
+ if (geckoItem != null) {
+ geckoItem.stopDispatchingChanges();
+ }
+
+ menuItem.setChecked(item.checked)
+ .setVisible(item.visible)
+ .setEnabled(item.enabled)
+ .setCheckable(item.checkable)
+ .setIcon(item.iconRes);
+
+ menuItem.setShowAsAction(item.showAsAction);
+
+ if (geckoItem != null) {
+ // We don't need to allow presenter updates during inflation,
+ // so we use the weak form of re-enabling changes.
+ geckoItem.resumeDispatchingChanges();
+ }
+ }
+}