aboutsummaryrefslogtreecommitdiffstats
path: root/ide_common/src/com/android/ide/common/xml/AndroidManifestParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'ide_common/src/com/android/ide/common/xml/AndroidManifestParser.java')
-rw-r--r--ide_common/src/com/android/ide/common/xml/AndroidManifestParser.java671
1 files changed, 671 insertions, 0 deletions
diff --git a/ide_common/src/com/android/ide/common/xml/AndroidManifestParser.java b/ide_common/src/com/android/ide/common/xml/AndroidManifestParser.java
new file mode 100644
index 0000000..38dc1c4
--- /dev/null
+++ b/ide_common/src/com/android/ide/common/xml/AndroidManifestParser.java
@@ -0,0 +1,671 @@
+/*
+ * Copyright (C) 2007 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.ide.common.xml;
+
+import com.android.SdkConstants;
+import com.android.ide.common.xml.ManifestData.Activity;
+import com.android.ide.common.xml.ManifestData.Instrumentation;
+import com.android.ide.common.xml.ManifestData.SupportsScreens;
+import com.android.ide.common.xml.ManifestData.UsesConfiguration;
+import com.android.ide.common.xml.ManifestData.UsesFeature;
+import com.android.ide.common.xml.ManifestData.UsesLibrary;
+import com.android.io.IAbstractFile;
+import com.android.io.IAbstractFolder;
+import com.android.io.StreamException;
+import com.android.resources.Keyboard;
+import com.android.resources.Navigation;
+import com.android.resources.TouchScreen;
+import com.android.xml.AndroidManifest;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+public class AndroidManifestParser {
+
+ private final static int LEVEL_TOP = 0;
+ private final static int LEVEL_INSIDE_MANIFEST = 1;
+ private final static int LEVEL_INSIDE_APPLICATION = 2;
+ private final static int LEVEL_INSIDE_APP_COMPONENT = 3;
+ private final static int LEVEL_INSIDE_INTENT_FILTER = 4;
+
+ private final static String ACTION_MAIN = "android.intent.action.MAIN"; //$NON-NLS-1$
+ private final static String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$
+
+ public interface ManifestErrorHandler extends ErrorHandler {
+ /**
+ * Handles a parsing error and an optional line number.
+ */
+ void handleError(Exception exception, int lineNumber);
+
+ /**
+ * Checks that a class is valid and can be used in the Android Manifest.
+ * <p/>
+ * Errors are put as {@code org.eclipse.core.resources.IMarker} on the manifest file.
+ *
+ * @param locator
+ * @param className the fully qualified name of the class to test.
+ * @param superClassName the fully qualified name of the class it is supposed to extend.
+ * @param testVisibility if <code>true</code>, the method will check the visibility of
+ * the class or of its constructors.
+ */
+ void checkClass(Locator locator, String className, String superClassName,
+ boolean testVisibility);
+ }
+
+ /**
+ * XML error & data handler used when parsing the AndroidManifest.xml file.
+ * <p/>
+ * During parsing this will fill up the {@link ManifestData} object given to the constructor
+ * and call out errors to the given {@link ManifestErrorHandler}.
+ */
+ private static class ManifestHandler extends DefaultHandler {
+
+ //--- temporary data/flags used during parsing
+ private final ManifestData mManifestData;
+ private final ManifestErrorHandler mErrorHandler;
+ private int mCurrentLevel = 0;
+ private int mValidLevel = 0;
+ private Activity mCurrentActivity = null;
+ private Locator mLocator;
+
+ /**
+ * Creates a new {@link ManifestHandler}.
+ *
+ * @param manifestFile The manifest file being parsed. Can be null.
+ * @param manifestData Class containing the manifest info obtained during the parsing.
+ * @param errorHandler An optional error handler.
+ */
+ ManifestHandler(IAbstractFile manifestFile, ManifestData manifestData,
+ ManifestErrorHandler errorHandler) {
+ super();
+ mManifestData = manifestData;
+ mErrorHandler = errorHandler;
+ }
+
+ /* (non-Javadoc)
+ * @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator)
+ */
+ @Override
+ public void setDocumentLocator(Locator locator) {
+ mLocator = locator;
+ super.setDocumentLocator(locator);
+ }
+
+ /* (non-Javadoc)
+ * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
+ * java.lang.String, org.xml.sax.Attributes)
+ */
+ @Override
+ public void startElement(String uri, String localName, String name, Attributes attributes)
+ throws SAXException {
+ try {
+ if (mManifestData == null) {
+ return;
+ }
+
+ // if we're at a valid level
+ if (mValidLevel == mCurrentLevel) {
+ String value;
+ switch (mValidLevel) {
+ case LEVEL_TOP:
+ if (AndroidManifest.NODE_MANIFEST.equals(localName)) {
+ // lets get the package name.
+ mManifestData.mPackage = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_PACKAGE,
+ false /* hasNamespace */);
+
+ // and the versionCode
+ String tmp = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_VERSIONCODE, true);
+ if (tmp != null) {
+ try {
+ mManifestData.mVersionCode = Integer.valueOf(tmp);
+ } catch (NumberFormatException e) {
+ // keep null in the field.
+ }
+ }
+ mValidLevel++;
+ }
+ break;
+ case LEVEL_INSIDE_MANIFEST:
+ if (AndroidManifest.NODE_APPLICATION.equals(localName)) {
+ value = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_PROCESS,
+ true /* hasNamespace */);
+ if (value != null) {
+ mManifestData.addProcessName(value);
+ }
+
+ value = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_DEBUGGABLE,
+ true /* hasNamespace*/);
+ if (value != null) {
+ mManifestData.mDebuggable = Boolean.parseBoolean(value);
+ }
+
+ mValidLevel++;
+ } else if (AndroidManifest.NODE_USES_SDK.equals(localName)) {
+ mManifestData.setMinSdkVersionString(getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION,
+ true /* hasNamespace */));
+ mManifestData.setTargetSdkVersionString(getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_TARGET_SDK_VERSION,
+ true /* hasNamespace */));
+ } else if (AndroidManifest.NODE_INSTRUMENTATION.equals(localName)) {
+ processInstrumentationNode(attributes);
+
+ } else if (AndroidManifest.NODE_SUPPORTS_SCREENS.equals(localName)) {
+ processSupportsScreensNode(attributes);
+
+ } else if (AndroidManifest.NODE_USES_CONFIGURATION.equals(localName)) {
+ processUsesConfiguration(attributes);
+
+ } else if (AndroidManifest.NODE_USES_FEATURE.equals(localName)) {
+ UsesFeature feature = new UsesFeature();
+
+ // get the name
+ value = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (value != null) {
+ feature.mName = value;
+ }
+
+ // read the required attribute
+ value = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_REQUIRED,
+ true /*hasNamespace*/);
+ if (value != null) {
+ Boolean b = Boolean.valueOf(value);
+ if (b != null) {
+ feature.mRequired = b;
+ }
+ }
+
+ // read the gl es attribute
+ value = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_GLESVERSION,
+ true /*hasNamespace*/);
+ if (value != null) {
+ try {
+ int version = Integer.decode(value);
+ feature.mGlEsVersion = version;
+ } catch (NumberFormatException e) {
+ // ignore
+ }
+
+ }
+
+ mManifestData.mFeatures.add(feature);
+ }
+ break;
+ case LEVEL_INSIDE_APPLICATION:
+ if (AndroidManifest.NODE_ACTIVITY.equals(localName)) {
+ processActivityNode(attributes);
+ mValidLevel++;
+ } else if (AndroidManifest.NODE_SERVICE.equals(localName)) {
+ processNode(attributes, SdkConstants.CLASS_SERVICE);
+ mValidLevel++;
+ } else if (AndroidManifest.NODE_RECEIVER.equals(localName)) {
+ processNode(attributes, SdkConstants.CLASS_BROADCASTRECEIVER);
+ mValidLevel++;
+ } else if (AndroidManifest.NODE_PROVIDER.equals(localName)) {
+ processNode(attributes, SdkConstants.CLASS_CONTENTPROVIDER);
+ mValidLevel++;
+ } else if (AndroidManifest.NODE_USES_LIBRARY.equals(localName)) {
+ value = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (value != null) {
+ UsesLibrary library = new UsesLibrary();
+ library.mName = value;
+
+ // read the required attribute
+ value = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_REQUIRED,
+ true /*hasNamespace*/);
+ if (value != null) {
+ Boolean b = Boolean.valueOf(value);
+ if (b != null) {
+ library.mRequired = b;
+ }
+ }
+
+ mManifestData.mLibraries.add(library);
+ }
+ }
+ break;
+ case LEVEL_INSIDE_APP_COMPONENT:
+ // only process this level if we are in an activity
+ if (mCurrentActivity != null &&
+ AndroidManifest.NODE_INTENT.equals(localName)) {
+ mCurrentActivity.resetIntentFilter();
+ mValidLevel++;
+ }
+ break;
+ case LEVEL_INSIDE_INTENT_FILTER:
+ if (mCurrentActivity != null) {
+ if (AndroidManifest.NODE_ACTION.equals(localName)) {
+ // get the name attribute
+ String action = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (action != null) {
+ mCurrentActivity.setHasAction(true);
+ mCurrentActivity.setHasMainAction(
+ ACTION_MAIN.equals(action));
+ }
+ } else if (AndroidManifest.NODE_CATEGORY.equals(localName)) {
+ String category = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (CATEGORY_LAUNCHER.equals(category)) {
+ mCurrentActivity.setHasLauncherCategory(true);
+ }
+ }
+
+ // no need to increase mValidLevel as we don't process anything
+ // below this level.
+ }
+ break;
+ }
+ }
+
+ mCurrentLevel++;
+ } finally {
+ super.startElement(uri, localName, name, attributes);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public void endElement(String uri, String localName, String name) throws SAXException {
+ try {
+ if (mManifestData == null) {
+ return;
+ }
+
+ // decrement the levels.
+ if (mValidLevel == mCurrentLevel) {
+ mValidLevel--;
+ }
+ mCurrentLevel--;
+
+ // if we're at a valid level
+ // process the end of the element
+ if (mValidLevel == mCurrentLevel) {
+ switch (mValidLevel) {
+ case LEVEL_INSIDE_APPLICATION:
+ mCurrentActivity = null;
+ break;
+ case LEVEL_INSIDE_APP_COMPONENT:
+ // if we found both a main action and a launcher category, this is our
+ // launcher activity!
+ if (mManifestData.mLauncherActivity == null &&
+ mCurrentActivity != null &&
+ mCurrentActivity.isHomeActivity() &&
+ mCurrentActivity.isExported()) {
+ mManifestData.mLauncherActivity = mCurrentActivity;
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+ } finally {
+ super.endElement(uri, localName, name);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
+ */
+ @Override
+ public void error(SAXParseException e) {
+ if (mErrorHandler != null) {
+ mErrorHandler.handleError(e, e.getLineNumber());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
+ */
+ @Override
+ public void fatalError(SAXParseException e) {
+ if (mErrorHandler != null) {
+ mErrorHandler.handleError(e, e.getLineNumber());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
+ */
+ @Override
+ public void warning(SAXParseException e) throws SAXException {
+ if (mErrorHandler != null) {
+ mErrorHandler.warning(e);
+ }
+ }
+
+ /**
+ * Processes the activity node.
+ * @param attributes the attributes for the activity node.
+ */
+ private void processActivityNode(Attributes attributes) {
+ // lets get the activity name, and add it to the list
+ String activityName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (activityName != null) {
+ activityName = AndroidManifest.combinePackageAndClassName(mManifestData.mPackage,
+ activityName);
+
+ // get the exported flag.
+ String exportedStr = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_EXPORTED, true);
+ boolean exported = exportedStr == null ||
+ exportedStr.toLowerCase(Locale.US).equals("true"); //$NON-NLS-1$
+ mCurrentActivity = new Activity(activityName, exported);
+ mManifestData.mActivities.add(mCurrentActivity);
+
+ if (mErrorHandler != null) {
+ mErrorHandler.checkClass(mLocator, activityName, SdkConstants.CLASS_ACTIVITY,
+ true /* testVisibility */);
+ }
+ } else {
+ // no activity found! Aapt will output an error,
+ // so we don't have to do anything
+ mCurrentActivity = null;
+ }
+
+ String processName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_PROCESS,
+ true /* hasNamespace */);
+ if (processName != null) {
+ mManifestData.addProcessName(processName);
+ }
+ }
+
+ /**
+ * Processes the service/receiver/provider nodes.
+ * @param attributes the attributes for the activity node.
+ * @param superClassName the fully qualified name of the super class that this
+ * node is representing
+ */
+ private void processNode(Attributes attributes, String superClassName) {
+ // lets get the class name, and check it if required.
+ String serviceName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (serviceName != null) {
+ serviceName = AndroidManifest.combinePackageAndClassName(mManifestData.mPackage,
+ serviceName);
+
+ if (mErrorHandler != null) {
+ mErrorHandler.checkClass(mLocator, serviceName, superClassName,
+ false /* testVisibility */);
+ }
+ }
+
+ String processName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_PROCESS,
+ true /* hasNamespace */);
+ if (processName != null) {
+ mManifestData.addProcessName(processName);
+ }
+ }
+
+ /**
+ * Processes the instrumentation node.
+ * @param attributes the attributes for the instrumentation node.
+ */
+ private void processInstrumentationNode(Attributes attributes) {
+ // lets get the class name, and check it if required.
+ String instrumentationName = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (instrumentationName != null) {
+ String instrClassName = AndroidManifest.combinePackageAndClassName(
+ mManifestData.mPackage, instrumentationName);
+ String targetPackage = getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_TARGET_PACKAGE,
+ true /* hasNamespace */);
+ mManifestData.mInstrumentations.add(
+ new Instrumentation(instrClassName, targetPackage));
+ if (mErrorHandler != null) {
+ mErrorHandler.checkClass(mLocator, instrClassName,
+ SdkConstants.CLASS_INSTRUMENTATION, true /* testVisibility */);
+ }
+ }
+ }
+
+ /**
+ * Processes the supports-screens node.
+ * @param attributes the attributes for the supports-screens node.
+ */
+ private void processSupportsScreensNode(Attributes attributes) {
+ mManifestData.mSupportsScreensFromManifest = new SupportsScreens();
+
+ mManifestData.mSupportsScreensFromManifest.setResizeable(getAttributeBooleanValue(
+ attributes, AndroidManifest.ATTRIBUTE_RESIZEABLE, true /*hasNamespace*/));
+
+ mManifestData.mSupportsScreensFromManifest.setAnyDensity(getAttributeBooleanValue(
+ attributes, AndroidManifest.ATTRIBUTE_ANYDENSITY, true /*hasNamespace*/));
+
+ mManifestData.mSupportsScreensFromManifest.setSmallScreens(getAttributeBooleanValue(
+ attributes, AndroidManifest.ATTRIBUTE_SMALLSCREENS, true /*hasNamespace*/));
+
+ mManifestData.mSupportsScreensFromManifest.setNormalScreens(getAttributeBooleanValue(
+ attributes, AndroidManifest.ATTRIBUTE_NORMALSCREENS, true /*hasNamespace*/));
+
+ mManifestData.mSupportsScreensFromManifest.setLargeScreens(getAttributeBooleanValue(
+ attributes, AndroidManifest.ATTRIBUTE_LARGESCREENS, true /*hasNamespace*/));
+ }
+
+ /**
+ * Processes the supports-screens node.
+ * @param attributes the attributes for the supports-screens node.
+ */
+ private void processUsesConfiguration(Attributes attributes) {
+ mManifestData.mUsesConfiguration = new UsesConfiguration();
+
+ mManifestData.mUsesConfiguration.mReqFiveWayNav = getAttributeBooleanValue(
+ attributes,
+ AndroidManifest.ATTRIBUTE_REQ_5WAYNAV, true /*hasNamespace*/);
+ mManifestData.mUsesConfiguration.mReqNavigation = Navigation.getEnum(
+ getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_REQ_NAVIGATION, true /*hasNamespace*/));
+ mManifestData.mUsesConfiguration.mReqHardKeyboard = getAttributeBooleanValue(
+ attributes,
+ AndroidManifest.ATTRIBUTE_REQ_HARDKEYBOARD, true /*hasNamespace*/);
+ mManifestData.mUsesConfiguration.mReqKeyboardType = Keyboard.getEnum(
+ getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_REQ_KEYBOARDTYPE, true /*hasNamespace*/));
+ mManifestData.mUsesConfiguration.mReqTouchScreen = TouchScreen.getEnum(
+ getAttributeValue(attributes,
+ AndroidManifest.ATTRIBUTE_REQ_TOUCHSCREEN, true /*hasNamespace*/));
+ }
+
+ /**
+ * Searches through the attributes list for a particular one and returns its value.
+ * @param attributes the attribute list to search through
+ * @param attributeName the name of the attribute to look for.
+ * @param hasNamespace Indicates whether the attribute has an android namespace.
+ * @return a String with the value or null if the attribute was not found.
+ * @see SdkConstants#NS_RESOURCES
+ */
+ private String getAttributeValue(Attributes attributes, String attributeName,
+ boolean hasNamespace) {
+ int count = attributes.getLength();
+ for (int i = 0 ; i < count ; i++) {
+ if (attributeName.equals(attributes.getLocalName(i)) &&
+ ((hasNamespace &&
+ SdkConstants.NS_RESOURCES.equals(attributes.getURI(i))) ||
+ (hasNamespace == false && attributes.getURI(i).length() == 0))) {
+ return attributes.getValue(i);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Searches through the attributes list for a particular one and returns its value as a
+ * Boolean. If the attribute is not present, this will return null.
+ * @param attributes the attribute list to search through
+ * @param attributeName the name of the attribute to look for.
+ * @param hasNamespace Indicates whether the attribute has an android namespace.
+ * @return a String with the value or null if the attribute was not found.
+ * @see SdkConstants#NS_RESOURCES
+ */
+ private Boolean getAttributeBooleanValue(Attributes attributes, String attributeName,
+ boolean hasNamespace) {
+ int count = attributes.getLength();
+ for (int i = 0 ; i < count ; i++) {
+ if (attributeName.equals(attributes.getLocalName(i)) &&
+ ((hasNamespace &&
+ SdkConstants.NS_RESOURCES.equals(attributes.getURI(i))) ||
+ (hasNamespace == false && attributes.getURI(i).length() == 0))) {
+ String attr = attributes.getValue(i);
+ if (attr != null) {
+ return Boolean.valueOf(attr);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ }
+
+ private final static SAXParserFactory sParserFactory;
+
+ static {
+ sParserFactory = SAXParserFactory.newInstance();
+ sParserFactory.setNamespaceAware(true);
+ }
+
+ /**
+ * Parses the Android Manifest, and returns a {@link ManifestData} object containing the
+ * result of the parsing.
+ *
+ * @param manifestFile the {@link IAbstractFile} representing the manifest file.
+ * @param gatherData indicates whether the parsing will extract data from the manifest. If false
+ * the method will always return null.
+ * @param errorHandler an optional errorHandler.
+ * @return A class containing the manifest info obtained during the parsing, or null on error.
+ *
+ * @throws StreamException
+ * @throws IOException
+ * @throws SAXException
+ * @throws ParserConfigurationException
+ */
+ public static ManifestData parse(
+ IAbstractFile manifestFile,
+ boolean gatherData,
+ ManifestErrorHandler errorHandler)
+ throws SAXException, IOException, StreamException, ParserConfigurationException {
+ if (manifestFile != null) {
+ SAXParser parser = sParserFactory.newSAXParser();
+
+ ManifestData data = null;
+ if (gatherData) {
+ data = new ManifestData();
+ }
+
+ ManifestHandler manifestHandler = new ManifestHandler(manifestFile,
+ data, errorHandler);
+ parser.parse(new InputSource(manifestFile.getContents()), manifestHandler);
+
+ return data;
+ }
+
+ return null;
+ }
+
+ /**
+ * Parses the Android Manifest, and returns an object containing the result of the parsing.
+ *
+ * <p/>
+ * This is the equivalent of calling <pre>parse(manifestFile, true, null)</pre>
+ *
+ * @param manifestFile the manifest file to parse.
+ *
+ * @throws ParserConfigurationException
+ * @throws StreamException
+ * @throws IOException
+ * @throws SAXException
+ */
+ public static ManifestData parse(IAbstractFile manifestFile)
+ throws SAXException, IOException, StreamException, ParserConfigurationException {
+ return parse(manifestFile, true, null);
+ }
+
+ public static ManifestData parse(IAbstractFolder projectFolder)
+ throws SAXException, IOException, StreamException, ParserConfigurationException {
+ IAbstractFile manifestFile = AndroidManifest.getManifest(projectFolder);
+ if (manifestFile == null) {
+ throw new FileNotFoundException();
+ }
+
+ return parse(manifestFile, true, null);
+ }
+
+ /**
+ * Parses the Android Manifest from an {@link InputStream}, and returns a {@link ManifestData}
+ * object containing the result of the parsing.
+ *
+ * @param manifestFileStream the {@link InputStream} representing the manifest file.
+ * @return A class containing the manifest info obtained during the parsing or null on error.
+ *
+ * @throws StreamException
+ * @throws IOException
+ * @throws SAXException
+ * @throws ParserConfigurationException
+ */
+ public static ManifestData parse(InputStream manifestFileStream)
+ throws SAXException, IOException, StreamException, ParserConfigurationException {
+ if (manifestFileStream != null) {
+ SAXParser parser = sParserFactory.newSAXParser();
+
+ ManifestData data = new ManifestData();
+
+ ManifestHandler manifestHandler = new ManifestHandler(null, data, null);
+ parser.parse(new InputSource(manifestFileStream), manifestHandler);
+
+ return data;
+ }
+
+ return null;
+ }
+}