Make CompiledResourcesMonitor#getRClassName more error proof.

This commit is contained in:
Xavier Ducrohet
2009-05-29 15:01:18 -07:00
parent e0fbae303c
commit 3106768f31
2 changed files with 134 additions and 130 deletions

View File

@@ -75,28 +75,28 @@ public class AndroidManifestParser {
private final static String ACTION_MAIN = "android.intent.action.MAIN"; //$NON-NLS-1$ 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$ private final static String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$
public final static int INVALID_MIN_SDK = -1; public final static int INVALID_MIN_SDK = -1;
/** /**
* Instrumentation info obtained from manifest * Instrumentation info obtained from manifest
*/ */
public static class Instrumentation { public static class Instrumentation {
private final String mName; private final String mName;
private final String mTargetPackage; private final String mTargetPackage;
Instrumentation(String name, String targetPackage) { Instrumentation(String name, String targetPackage) {
mName = name; mName = name;
mTargetPackage = targetPackage; mTargetPackage = targetPackage;
} }
/** /**
* Returns the fully qualified instrumentation class name * Returns the fully qualified instrumentation class name
*/ */
public String getName() { public String getName() {
return mName; return mName;
} }
/** /**
* Returns the Android app package that is the target of this instrumentation * Returns the Android app package that is the target of this instrumentation
*/ */
@@ -104,7 +104,7 @@ public class AndroidManifestParser {
return mTargetPackage; return mTargetPackage;
} }
} }
/** /**
* Activity info obtained from the manifest. * Activity info obtained from the manifest.
*/ */
@@ -114,32 +114,32 @@ public class AndroidManifestParser {
private boolean mHasAction = false; private boolean mHasAction = false;
private boolean mHasMainAction = false; private boolean mHasMainAction = false;
private boolean mHasLauncherCategory = false; private boolean mHasLauncherCategory = false;
public Activity(String name, boolean exported) { public Activity(String name, boolean exported) {
mName = name; mName = name;
mIsExported = exported; mIsExported = exported;
} }
public String getName() { public String getName() {
return mName; return mName;
} }
public boolean isExported() { public boolean isExported() {
return mIsExported; return mIsExported;
} }
public boolean hasAction() { public boolean hasAction() {
return mHasAction; return mHasAction;
} }
public boolean isHomeActivity() { public boolean isHomeActivity() {
return mHasMainAction && mHasLauncherCategory; return mHasMainAction && mHasLauncherCategory;
} }
void setHasAction(boolean hasAction) { void setHasAction(boolean hasAction) {
mHasAction = hasAction; mHasAction = hasAction;
} }
/** If the activity doesn't yet have a filter set for the launcher, this resets both /** If the activity doesn't yet have a filter set for the launcher, this resets both
* flags. This is to handle multiple intent-filters where one could have the valid * flags. This is to handle multiple intent-filters where one could have the valid
* action, and another one of the valid category. * action, and another one of the valid category.
@@ -149,16 +149,16 @@ public class AndroidManifestParser {
mHasMainAction = mHasLauncherCategory = false; mHasMainAction = mHasLauncherCategory = false;
} }
} }
void setHasMainAction(boolean hasMainAction) { void setHasMainAction(boolean hasMainAction) {
mHasMainAction = hasMainAction; mHasMainAction = hasMainAction;
} }
void setHasLauncherCategory(boolean hasLauncherCategory) { void setHasLauncherCategory(boolean hasLauncherCategory) {
mHasLauncherCategory = hasLauncherCategory; mHasLauncherCategory = hasLauncherCategory;
} }
} }
/** /**
* XML error & data handler used when parsing the AndroidManifest.xml file. * XML error & data handler used when parsing the AndroidManifest.xml file.
* <p/> * <p/>
@@ -166,9 +166,9 @@ public class AndroidManifestParser {
* to collect data from the manifest. * to collect data from the manifest.
*/ */
private static class ManifestHandler extends XmlErrorHandler { private static class ManifestHandler extends XmlErrorHandler {
//--- data read from the parsing //--- data read from the parsing
/** Application package */ /** Application package */
private String mPackage; private String mPackage;
/** List of all activities */ /** List of all activities */
@@ -196,10 +196,10 @@ public class AndroidManifestParser {
private int mValidLevel = 0; private int mValidLevel = 0;
private Activity mCurrentActivity = null; private Activity mCurrentActivity = null;
private Locator mLocator; private Locator mLocator;
/** /**
* Creates a new {@link ManifestHandler}, which is also an {@link XmlErrorHandler}. * Creates a new {@link ManifestHandler}, which is also an {@link XmlErrorHandler}.
* *
* @param manifestFile The manifest file being parsed. Can be null. * @param manifestFile The manifest file being parsed. Can be null.
* @param errorListener An optional error listener. * @param errorListener An optional error listener.
* @param gatherData True if data should be gathered. * @param gatherData True if data should be gathered.
@@ -221,24 +221,24 @@ public class AndroidManifestParser {
String getPackage() { String getPackage() {
return mPackage; return mPackage;
} }
/** /**
* Returns the list of activities found in the manifest. * Returns the list of activities found in the manifest.
* @return An array of fully qualified class names, or empty if no activity were found. * @return An array of fully qualified class names, or empty if no activity were found.
*/ */
Activity[] getActivities() { Activity[] getActivities() {
return mActivities.toArray(new Activity[mActivities.size()]); return mActivities.toArray(new Activity[mActivities.size()]);
} }
/** /**
* Returns the name of one activity found in the manifest, that is configured to show * Returns the name of one activity found in the manifest, that is configured to show
* up in the HOME screen. * up in the HOME screen.
* @return the fully qualified name of a HOME activity or null if none were found. * @return the fully qualified name of a HOME activity or null if none were found.
*/ */
Activity getLauncherActivity() { Activity getLauncherActivity() {
return mLauncherActivity; return mLauncherActivity;
} }
/** /**
* Returns the list of process names declared by the manifest. * Returns the list of process names declared by the manifest.
*/ */
@@ -246,42 +246,42 @@ public class AndroidManifestParser {
if (mProcesses != null) { if (mProcesses != null) {
return mProcesses.toArray(new String[mProcesses.size()]); return mProcesses.toArray(new String[mProcesses.size()]);
} }
return new String[0]; return new String[0];
} }
/** /**
* Returns the <code>debuggable</code> attribute value or null if it is not set. * Returns the <code>debuggable</code> attribute value or null if it is not set.
*/ */
Boolean getDebuggable() { Boolean getDebuggable() {
return mDebuggable; return mDebuggable;
} }
/** /**
* Returns the <code>minSdkVersion</code> attribute, or * Returns the <code>minSdkVersion</code> attribute, or
* {@link AndroidManifestParser#INVALID_MIN_SDK} if it's not set. * {@link AndroidManifestParser#INVALID_MIN_SDK} if it's not set.
*/ */
int getApiLevelRequirement() { int getApiLevelRequirement() {
return mApiLevelRequirement; return mApiLevelRequirement;
} }
/** /**
* Returns the list of instrumentations found in the manifest. * Returns the list of instrumentations found in the manifest.
* @return An array of {@link Instrumentation}, or empty if no instrumentations were * @return An array of {@link Instrumentation}, or empty if no instrumentations were
* found. * found.
*/ */
Instrumentation[] getInstrumentations() { Instrumentation[] getInstrumentations() {
return mInstrumentations.toArray(new Instrumentation[mInstrumentations.size()]); return mInstrumentations.toArray(new Instrumentation[mInstrumentations.size()]);
} }
/** /**
* Returns the list of libraries in use found in the manifest. * Returns the list of libraries in use found in the manifest.
* @return An array of library names, or empty if no libraries were found. * @return An array of library names, or empty if no libraries were found.
*/ */
String[] getUsesLibraries() { String[] getUsesLibraries() {
return mLibraries.toArray(new String[mLibraries.size()]); return mLibraries.toArray(new String[mLibraries.size()]);
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator) * @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator)
*/ */
@@ -290,7 +290,7 @@ public class AndroidManifestParser {
mLocator = locator; mLocator = locator;
super.setDocumentLocator(locator); super.setDocumentLocator(locator);
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
* java.lang.String, org.xml.sax.Attributes) * java.lang.String, org.xml.sax.Attributes)
@@ -322,18 +322,18 @@ public class AndroidManifestParser {
if (value != null) { if (value != null) {
addProcessName(value); addProcessName(value);
} }
value = getAttributeValue(attributes, ATTRIBUTE_DEBUGGABLE, value = getAttributeValue(attributes, ATTRIBUTE_DEBUGGABLE,
true /* hasNamespace*/); true /* hasNamespace*/);
if (value != null) { if (value != null) {
mDebuggable = Boolean.parseBoolean(value); mDebuggable = Boolean.parseBoolean(value);
} }
mValidLevel++; mValidLevel++;
} else if (NODE_USES_SDK.equals(localName)) { } else if (NODE_USES_SDK.equals(localName)) {
value = getAttributeValue(attributes, ATTRIBUTE_MIN_SDK_VERSION, value = getAttributeValue(attributes, ATTRIBUTE_MIN_SDK_VERSION,
true /* hasNamespace */); true /* hasNamespace */);
if (value != null) { if (value != null) {
try { try {
mApiLevelRequirement = Integer.parseInt(value); mApiLevelRequirement = Integer.parseInt(value);
@@ -343,7 +343,7 @@ public class AndroidManifestParser {
} }
} else if (NODE_INSTRUMENTATION.equals(localName)) { } else if (NODE_INSTRUMENTATION.equals(localName)) {
processInstrumentationNode(attributes); processInstrumentationNode(attributes);
} }
break; break;
case LEVEL_ACTIVITY: case LEVEL_ACTIVITY:
if (NODE_ACTIVITY.equals(localName)) { if (NODE_ACTIVITY.equals(localName)) {
@@ -364,7 +364,7 @@ public class AndroidManifestParser {
if (value != null) { if (value != null) {
mLibraries.add(value); mLibraries.add(value);
} }
} }
break; break;
case LEVEL_INTENT_FILTER: case LEVEL_INTENT_FILTER:
// only process this level if we are in an activity // only process this level if we are in an activity
@@ -391,7 +391,7 @@ public class AndroidManifestParser {
mCurrentActivity.setHasLauncherCategory(true); mCurrentActivity.setHasLauncherCategory(true);
} }
} }
// no need to increase mValidLevel as we don't process anything // no need to increase mValidLevel as we don't process anything
// below this level. // below this level.
} }
@@ -415,13 +415,13 @@ public class AndroidManifestParser {
if (mGatherData == false) { if (mGatherData == false) {
return; return;
} }
// decrement the levels. // decrement the levels.
if (mValidLevel == mCurrentLevel) { if (mValidLevel == mCurrentLevel) {
mValidLevel--; mValidLevel--;
} }
mCurrentLevel--; mCurrentLevel--;
// if we're at a valid level // if we're at a valid level
// process the end of the element // process the end of the element
if (mValidLevel == mCurrentLevel) { if (mValidLevel == mCurrentLevel) {
@@ -442,13 +442,13 @@ public class AndroidManifestParser {
default: default:
break; break;
} }
} }
} finally { } finally {
super.endElement(uri, localName, name); super.endElement(uri, localName, name);
} }
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException) * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
*/ */
@@ -478,7 +478,7 @@ public class AndroidManifestParser {
super.warning(e); super.warning(e);
} }
} }
/** /**
* Processes the activity node. * Processes the activity node.
* @param attributes the attributes for the activity node. * @param attributes the attributes for the activity node.
@@ -489,14 +489,14 @@ public class AndroidManifestParser {
true /* hasNamespace */); true /* hasNamespace */);
if (activityName != null) { if (activityName != null) {
activityName = combinePackageAndClassName(mPackage, activityName); activityName = combinePackageAndClassName(mPackage, activityName);
// get the exported flag. // get the exported flag.
String exportedStr = getAttributeValue(attributes, ATTRIBUTE_EXPORTED, true); String exportedStr = getAttributeValue(attributes, ATTRIBUTE_EXPORTED, true);
boolean exported = exportedStr == null || boolean exported = exportedStr == null ||
exportedStr.toLowerCase().equals("true"); // $NON-NLS-1$ exportedStr.toLowerCase().equals("true"); // $NON-NLS-1$
mCurrentActivity = new Activity(activityName, exported); mCurrentActivity = new Activity(activityName, exported);
mActivities.add(mCurrentActivity); mActivities.add(mCurrentActivity);
if (mMarkErrors) { if (mMarkErrors) {
checkClass(activityName, AndroidConstants.CLASS_ACTIVITY, checkClass(activityName, AndroidConstants.CLASS_ACTIVITY,
true /* testVisibility */); true /* testVisibility */);
@@ -506,7 +506,7 @@ public class AndroidManifestParser {
// so we don't have to do anything // so we don't have to do anything
mCurrentActivity = null; mCurrentActivity = null;
} }
String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS, String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS,
true /* hasNamespace */); true /* hasNamespace */);
if (processName != null) { if (processName != null) {
@@ -526,19 +526,19 @@ public class AndroidManifestParser {
true /* hasNamespace */); true /* hasNamespace */);
if (serviceName != null) { if (serviceName != null) {
serviceName = combinePackageAndClassName(mPackage, serviceName); serviceName = combinePackageAndClassName(mPackage, serviceName);
if (mMarkErrors) { if (mMarkErrors) {
checkClass(serviceName, superClassName, false /* testVisibility */); checkClass(serviceName, superClassName, false /* testVisibility */);
} }
} }
String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS, String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS,
true /* hasNamespace */); true /* hasNamespace */);
if (processName != null) { if (processName != null) {
addProcessName(processName); addProcessName(processName);
} }
} }
/** /**
* Processes the instrumentation nodes. * Processes the instrumentation nodes.
* @param attributes the attributes for the activity node. * @param attributes the attributes for the activity node.
@@ -563,7 +563,7 @@ public class AndroidManifestParser {
/** /**
* Checks that a class is valid and can be used in the Android Manifest. * Checks that a class is valid and can be used in the Android Manifest.
* <p/> * <p/>
* Errors are put as {@link IMarker} on the manifest file. * Errors are put as {@link IMarker} on the manifest file.
* @param className the fully qualified name of the class to test. * @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 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 * @param testVisibility if <code>true</code>, the method will check the visibility of
@@ -579,12 +579,12 @@ public class AndroidManifestParser {
if (result != BaseProjectHelper.TEST_CLASS_OK) { if (result != BaseProjectHelper.TEST_CLASS_OK) {
// get the line number // get the line number
int line = mLocator.getLineNumber(); int line = mLocator.getLineNumber();
// mark the file // mark the file
IMarker marker = BaseProjectHelper.addMarker(getFile(), IMarker marker = BaseProjectHelper.addMarker(getFile(),
AndroidConstants.MARKER_ANDROID, AndroidConstants.MARKER_ANDROID,
result, line, IMarker.SEVERITY_ERROR); result, line, IMarker.SEVERITY_ERROR);
// add custom attributes to be used by the manifest editor. // add custom attributes to be used by the manifest editor.
if (marker != null) { if (marker != null) {
try { try {
@@ -594,7 +594,7 @@ public class AndroidManifestParser {
} catch (CoreException e) { } catch (CoreException e) {
} }
} }
} }
} }
/** /**
@@ -616,21 +616,21 @@ public class AndroidManifestParser {
return attributes.getValue(i); return attributes.getValue(i);
} }
} }
return null; return null;
} }
private void addProcessName(String processName) { private void addProcessName(String processName) {
if (mProcesses == null) { if (mProcesses == null) {
mProcesses = new TreeSet<String>(); mProcesses = new TreeSet<String>();
} }
mProcesses.add(processName); mProcesses.add(processName);
} }
} }
private static SAXParserFactory sParserFactory; private static SAXParserFactory sParserFactory;
private final String mJavaPackage; private final String mJavaPackage;
private final Activity[] mActivities; private final Activity[] mActivities;
private final Activity mLauncherActivity; private final Activity mLauncherActivity;
@@ -644,14 +644,14 @@ public class AndroidManifestParser {
sParserFactory = SAXParserFactory.newInstance(); sParserFactory = SAXParserFactory.newInstance();
sParserFactory.setNamespaceAware(true); sParserFactory.setNamespaceAware(true);
} }
/** /**
* Parses the Android Manifest, and returns an object containing the result of the parsing. * Parses the Android Manifest, and returns an object containing the result of the parsing.
* <p/> * <p/>
* This method is useful to parse a specific {@link IFile} in a Java project. * This method is useful to parse a specific {@link IFile} in a Java project.
* <p/> * <p/>
* If you only want to gather data, consider {@link #parseForData(IFile)} instead. * If you only want to gather data, consider {@link #parseForData(IFile)} instead.
* *
* @param javaProject The java project. * @param javaProject The java project.
* @param manifestFile the {@link IFile} representing the manifest file. * @param manifestFile the {@link IFile} representing the manifest file.
* @param errorListener * @param errorListener
@@ -670,41 +670,42 @@ public class AndroidManifestParser {
boolean markErrors) boolean markErrors)
throws CoreException { throws CoreException {
try { try {
SAXParser parser = sParserFactory.newSAXParser(); if (manifestFile != null) {
SAXParser parser = sParserFactory.newSAXParser();
ManifestHandler manifestHandler = new ManifestHandler(manifestFile, ManifestHandler manifestHandler = new ManifestHandler(manifestFile,
errorListener, gatherData, javaProject, markErrors); errorListener, gatherData, javaProject, markErrors);
parser.parse(new InputSource(manifestFile.getContents()), manifestHandler); parser.parse(new InputSource(manifestFile.getContents()), manifestHandler);
// get the result from the handler // get the result from the handler
return new AndroidManifestParser(manifestHandler.getPackage(),
return new AndroidManifestParser(manifestHandler.getPackage(), manifestHandler.getActivities(),
manifestHandler.getActivities(), manifestHandler.getLauncherActivity(),
manifestHandler.getLauncherActivity(), manifestHandler.getProcesses(),
manifestHandler.getProcesses(), manifestHandler.getDebuggable(),
manifestHandler.getDebuggable(), manifestHandler.getApiLevelRequirement(),
manifestHandler.getApiLevelRequirement(), manifestHandler.getInstrumentations(),
manifestHandler.getInstrumentations(), manifestHandler.getUsesLibraries());
manifestHandler.getUsesLibraries()); }
} catch (ParserConfigurationException e) { } catch (ParserConfigurationException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(), AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Bad parser configuration for %s: %s", "Bad parser configuration for %s: %s",
manifestFile.getFullPath(), manifestFile.getFullPath(),
e.getMessage()); e.getMessage());
} catch (SAXException e) { } catch (SAXException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(), AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Parser exception for %s: %s", "Parser exception for %s: %s",
manifestFile.getFullPath(), manifestFile.getFullPath(),
e.getMessage()); e.getMessage());
} catch (IOException e) { } catch (IOException e) {
// Don't log a console error when failing to read a non-existing file // Don't log a console error when failing to read a non-existing file
if (!(e instanceof FileNotFoundException)) { if (!(e instanceof FileNotFoundException)) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(), AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"I/O error for %s: %s", "I/O error for %s: %s",
manifestFile.getFullPath(), manifestFile.getFullPath(),
e.getMessage()); e.getMessage());
} }
} }
return null; return null;
} }
@@ -716,7 +717,7 @@ public class AndroidManifestParser {
* parsing a file that is not part of an Eclipse Java project. * parsing a file that is not part of an Eclipse Java project.
* <p/> * <p/>
* It assumes errors cannot be marked on the file and that data gathering is enabled. * It assumes errors cannot be marked on the file and that data gathering is enabled.
* *
* @param manifestFile the manifest file to parse. * @param manifestFile the manifest file to parse.
* @return an {@link AndroidManifestParser} or null if the parsing failed. * @return an {@link AndroidManifestParser} or null if the parsing failed.
* @throws CoreException * @throws CoreException
@@ -733,11 +734,11 @@ public class AndroidManifestParser {
null, //javaProject null, //javaProject
false //markErrors false //markErrors
); );
parser.parse(new InputSource(new FileReader(manifestFile)), manifestHandler); parser.parse(new InputSource(new FileReader(manifestFile)), manifestHandler);
// get the result from the handler // get the result from the handler
return new AndroidManifestParser(manifestHandler.getPackage(), return new AndroidManifestParser(manifestHandler.getPackage(),
manifestHandler.getActivities(), manifestHandler.getActivities(),
manifestHandler.getLauncherActivity(), manifestHandler.getLauncherActivity(),
@@ -747,25 +748,25 @@ public class AndroidManifestParser {
manifestHandler.getInstrumentations(), manifestHandler.getInstrumentations(),
manifestHandler.getUsesLibraries()); manifestHandler.getUsesLibraries());
} catch (ParserConfigurationException e) { } catch (ParserConfigurationException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(), AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Bad parser configuration for %s: %s", "Bad parser configuration for %s: %s",
manifestFile.getAbsolutePath(), manifestFile.getAbsolutePath(),
e.getMessage()); e.getMessage());
} catch (SAXException e) { } catch (SAXException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(), AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Parser exception for %s: %s", "Parser exception for %s: %s",
manifestFile.getAbsolutePath(), manifestFile.getAbsolutePath(),
e.getMessage()); e.getMessage());
} catch (IOException e) { } catch (IOException e) {
// Don't log a console error when failing to read a non-existing file // Don't log a console error when failing to read a non-existing file
if (!(e instanceof FileNotFoundException)) { if (!(e instanceof FileNotFoundException)) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(), AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"I/O error for %s: %s", "I/O error for %s: %s",
manifestFile.getAbsolutePath(), manifestFile.getAbsolutePath(),
e.getMessage()); e.getMessage());
} }
} }
return null; return null;
} }
@@ -788,9 +789,9 @@ public class AndroidManifestParser {
boolean gatherData, boolean gatherData,
boolean markErrors) boolean markErrors)
throws CoreException { throws CoreException {
IFile manifestFile = getManifest(javaProject.getProject()); IFile manifestFile = getManifest(javaProject.getProject());
try { try {
SAXParser parser = sParserFactory.newSAXParser(); SAXParser parser = sParserFactory.newSAXParser();
@@ -799,25 +800,25 @@ public class AndroidManifestParser {
errorListener, gatherData, javaProject, markErrors); errorListener, gatherData, javaProject, markErrors);
parser.parse(new InputSource(manifestFile.getContents()), manifestHandler); parser.parse(new InputSource(manifestFile.getContents()), manifestHandler);
// get the result from the handler // get the result from the handler
return new AndroidManifestParser(manifestHandler.getPackage(), return new AndroidManifestParser(manifestHandler.getPackage(),
manifestHandler.getActivities(), manifestHandler.getLauncherActivity(), manifestHandler.getActivities(), manifestHandler.getLauncherActivity(),
manifestHandler.getProcesses(), manifestHandler.getDebuggable(), manifestHandler.getProcesses(), manifestHandler.getDebuggable(),
manifestHandler.getApiLevelRequirement(), manifestHandler.getApiLevelRequirement(),
manifestHandler.getInstrumentations(), manifestHandler.getUsesLibraries()); manifestHandler.getInstrumentations(), manifestHandler.getUsesLibraries());
} }
} catch (ParserConfigurationException e) { } catch (ParserConfigurationException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(), AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Bad parser configuration for %s", manifestFile.getFullPath()); "Bad parser configuration for %s", manifestFile.getFullPath());
} catch (SAXException e) { } catch (SAXException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(), AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Parser exception for %s", manifestFile.getFullPath()); "Parser exception for %s", manifestFile.getFullPath());
} catch (IOException e) { } catch (IOException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(), AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"I/O error for %s", manifestFile.getFullPath()); "I/O error for %s", manifestFile.getFullPath());
} }
return null; return null;
} }
@@ -849,7 +850,7 @@ public class AndroidManifestParser {
/** /**
* Parses the manifest file, and collects data. * Parses the manifest file, and collects data.
* *
* @param osManifestFilePath The OS path of the manifest file to parse. * @param osManifestFilePath The OS path of the manifest file to parse.
* @return an {@link AndroidManifestParser} or null if the parsing failed. * @return an {@link AndroidManifestParser} or null if the parsing failed.
*/ */
@@ -871,7 +872,7 @@ public class AndroidManifestParser {
return mJavaPackage; return mJavaPackage;
} }
/** /**
* Returns the list of activities found in the manifest. * Returns the list of activities found in the manifest.
* @return An array of {@link Activity}, or empty if no activity were found. * @return An array of {@link Activity}, or empty if no activity were found.
*/ */
@@ -881,35 +882,35 @@ public class AndroidManifestParser {
/** /**
* Returns the name of one activity found in the manifest, that is configured to show * Returns the name of one activity found in the manifest, that is configured to show
* up in the HOME screen. * up in the HOME screen.
* @return The {@link Activity} representing a HOME activity or null if none were found. * @return The {@link Activity} representing a HOME activity or null if none were found.
*/ */
public Activity getLauncherActivity() { public Activity getLauncherActivity() {
return mLauncherActivity; return mLauncherActivity;
} }
/** /**
* Returns the list of process names declared by the manifest. * Returns the list of process names declared by the manifest.
*/ */
public String[] getProcesses() { public String[] getProcesses() {
return mProcesses; return mProcesses;
} }
/** /**
* Returns the debuggable attribute value or <code>null</code> if it is not set. * Returns the debuggable attribute value or <code>null</code> if it is not set.
*/ */
public Boolean getDebuggable() { public Boolean getDebuggable() {
return mDebuggable; return mDebuggable;
} }
/** /**
* Returns the <code>minSdkVersion</code> attribute, or {@link #INVALID_MIN_SDK} * Returns the <code>minSdkVersion</code> attribute, or {@link #INVALID_MIN_SDK}
* if it's not set. * if it's not set.
*/ */
public int getApiLevelRequirement() { public int getApiLevelRequirement() {
return mApiLevelRequirement; return mApiLevelRequirement;
} }
/** /**
* Returns the list of instrumentations found in the manifest. * Returns the list of instrumentations found in the manifest.
* @return An array of {@link Instrumentation}, or empty if no instrumentations were found. * @return An array of {@link Instrumentation}, or empty if no instrumentations were found.
@@ -917,7 +918,7 @@ public class AndroidManifestParser {
public Instrumentation[] getInstrumentations() { public Instrumentation[] getInstrumentations() {
return mInstrumentations; return mInstrumentations;
} }
/** /**
* Returns the list of libraries in use found in the manifest. * Returns the list of libraries in use found in the manifest.
* @return An array of library names, or empty if no uses-library declarations were found. * @return An array of library names, or empty if no uses-library declarations were found.
@@ -926,7 +927,7 @@ public class AndroidManifestParser {
return mLibraries; return mLibraries;
} }
/** /**
* Private constructor to enforce using * Private constructor to enforce using
* {@link #parse(IJavaProject, XmlErrorListener, boolean, boolean)}, * {@link #parse(IJavaProject, XmlErrorListener, boolean, boolean)},
@@ -977,7 +978,7 @@ public class AndroidManifestParser {
* Combines a java package, with a class value from the manifest to make a fully qualified * Combines a java package, with a class value from the manifest to make a fully qualified
* class name * class name
* @param javaPackage the java package from the manifest. * @param javaPackage the java package from the manifest.
* @param className the class name from the manifest. * @param className the class name from the manifest.
* @return the fully qualified class name. * @return the fully qualified class name.
*/ */
public static String combinePackageAndClassName(String javaPackage, String className) { public static String combinePackageAndClassName(String javaPackage, String className) {
@@ -1010,8 +1011,8 @@ public class AndroidManifestParser {
* Given a fully qualified activity name (e.g. com.foo.test.MyClass) and given a project * Given a fully qualified activity name (e.g. com.foo.test.MyClass) and given a project
* package base name (e.g. com.foo), returns the relative activity name that would be used * package base name (e.g. com.foo), returns the relative activity name that would be used
* the "name" attribute of an "activity" element. * the "name" attribute of an "activity" element.
* *
* @param fullActivityName a fully qualified activity class name, e.g. "com.foo.test.MyClass" * @param fullActivityName a fully qualified activity class name, e.g. "com.foo.test.MyClass"
* @param packageName The project base package name, e.g. "com.foo" * @param packageName The project base package name, e.g. "com.foo"
* @return The relative activity name if it can be computed or the original fullActivityName. * @return The relative activity name if it can be computed or the original fullActivityName.
*/ */

View File

@@ -26,6 +26,7 @@ import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor.IP
import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
@@ -42,7 +43,7 @@ import java.util.Map;
public final class CompiledResourcesMonitor implements IFileListener, IProjectListener { public final class CompiledResourcesMonitor implements IFileListener, IProjectListener {
private final static CompiledResourcesMonitor sThis = new CompiledResourcesMonitor(); private final static CompiledResourcesMonitor sThis = new CompiledResourcesMonitor();
/** /**
* Sets up the monitoring system. * Sets up the monitoring system.
* @param monitor The main Resource Monitor. * @param monitor The main Resource Monitor.
@@ -62,12 +63,12 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
/* (non-Javadoc) /* (non-Javadoc)
* Sent when a file changed : if the file is the R class, then it is parsed again to update * Sent when a file changed : if the file is the R class, then it is parsed again to update
* the internal data. * the internal data.
* *
* @param file The file that changed. * @param file The file that changed.
* @param markerDeltas The marker deltas for the file. * @param markerDeltas The marker deltas for the file.
* @param kind The change kind. This is equivalent to * @param kind The change kind. This is equivalent to
* {@link IResourceDelta#accept(IResourceDeltaVisitor)} * {@link IResourceDelta#accept(IResourceDeltaVisitor)}
* *
* @see IFileListener#fileChanged * @see IFileListener#fileChanged
*/ */
public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) { public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) {
@@ -111,7 +112,7 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
// pass // pass
} }
} }
private void loadAndParseRClass(IProject project) { private void loadAndParseRClass(IProject project) {
try { try {
// first check there's a ProjectResources to store the content // first check there's a ProjectResources to store the content
@@ -129,13 +130,13 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
return; return;
} }
// create a temporary class loader to load it. // create a temporary class loader to load it.
ProjectClassLoader loader = new ProjectClassLoader(null /* parentClassLoader */, ProjectClassLoader loader = new ProjectClassLoader(null /* parentClassLoader */,
project); project);
try { try {
Class<?> clazz = loader.loadClass(className); Class<?> clazz = loader.loadClass(className);
if (clazz != null) { if (clazz != null) {
// create the maps to store the result of the parsing // create the maps to store the result of the parsing
Map<String, Map<String, Integer>> resourceValueMap = Map<String, Map<String, Integer>> resourceValueMap =
@@ -144,7 +145,7 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
new HashMap<Integer, String[]>(); new HashMap<Integer, String[]>();
Map<IntArrayWrapper, String> styleableValueToNameMap = Map<IntArrayWrapper, String> styleableValueToNameMap =
new HashMap<IntArrayWrapper, String>(); new HashMap<IntArrayWrapper, String>();
// parse the class // parse the class
if (parseClass(clazz, genericValueToNameMap, styleableValueToNameMap, if (parseClass(clazz, genericValueToNameMap, styleableValueToNameMap,
resourceValueMap)) { resourceValueMap)) {
@@ -180,7 +181,7 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
Map<String, Integer> fullMap = new HashMap<String, Integer>(); Map<String, Integer> fullMap = new HashMap<String, Integer>();
resourceValueMap.put(resType, fullMap); resourceValueMap.put(resType, fullMap);
for (Field f : inner.getDeclaredFields()) { for (Field f : inner.getDeclaredFields()) {
// only process static final fields. // only process static final fields.
int modifiers = f.getModifiers(); int modifiers = f.getModifiers();
@@ -191,7 +192,7 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
styleableValueToNameMap.put(new IntArrayWrapper((int[]) f.get(null)), styleableValueToNameMap.put(new IntArrayWrapper((int[]) f.get(null)),
f.getName()); f.getName());
} else if (type == int.class) { } else if (type == int.class) {
Integer value = (Integer) f.get(null); Integer value = (Integer) f.get(null);
genericValueToNameMap.put(value, new String[] { f.getName(), resType }); genericValueToNameMap.put(value, new String[] { f.getName(), resType });
fullMap.put(f.getName(), value); fullMap.put(f.getName(), value);
} else { } else {
@@ -210,16 +211,18 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
/** /**
* Returns the class name of the R class, based on the project's manifest's package. * Returns the class name of the R class, based on the project's manifest's package.
* *
* @return A class name (e.g. "my.app.R") or null if there's no valid package in the manifest. * @return A class name (e.g. "my.app.R") or null if there's no valid package in the manifest.
*/ */
private String getRClassName(IProject project) { private String getRClassName(IProject project) {
try { try {
IFile manifestFile = AndroidManifestParser.getManifest(project); IFile manifestFile = AndroidManifestParser.getManifest(project);
AndroidManifestParser data = AndroidManifestParser.parseForData(manifestFile); if (manifestFile != null && manifestFile.isSynchronized(IResource.DEPTH_ZERO)) {
if (data != null) { AndroidManifestParser data = AndroidManifestParser.parseForData(manifestFile);
String javaPackage = data.getPackage(); if (data != null) {
return javaPackage + ".R"; //$NON-NLS-1$ String javaPackage = data.getPackage();
return javaPackage + ".R"; //$NON-NLS-1$
}
} }
} catch (CoreException e) { } catch (CoreException e) {
// This will typically happen either because the manifest file is not present // This will typically happen either because the manifest file is not present
@@ -232,5 +235,5 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
} }
return null; return null;
} }
} }