OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / sdk / eclipse / plugins / com.android.ide.eclipse.adt / src / com / android / ide / eclipse / adt / internal / project / ProjectHelper.java
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
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
17 package com.android.ide.eclipse.adt.internal.project;
18
19 import com.android.ide.eclipse.adt.AdtPlugin;
20 import com.android.ide.eclipse.adt.AndroidConstants;
21 import com.android.sdklib.SdkConstants;
22 import com.android.sdklib.xml.ManifestData;
23
24 import org.eclipse.core.resources.IFile;
25 import org.eclipse.core.resources.IFolder;
26 import org.eclipse.core.resources.IMarker;
27 import org.eclipse.core.resources.IProject;
28 import org.eclipse.core.resources.IProjectDescription;
29 import org.eclipse.core.resources.IResource;
30 import org.eclipse.core.resources.IWorkspace;
31 import org.eclipse.core.resources.IncrementalProjectBuilder;
32 import org.eclipse.core.resources.ResourcesPlugin;
33 import org.eclipse.core.runtime.CoreException;
34 import org.eclipse.core.runtime.IPath;
35 import org.eclipse.core.runtime.NullProgressMonitor;
36 import org.eclipse.core.runtime.Path;
37 import org.eclipse.core.runtime.QualifiedName;
38 import org.eclipse.jdt.core.IClasspathEntry;
39 import org.eclipse.jdt.core.IJavaModel;
40 import org.eclipse.jdt.core.IJavaProject;
41 import org.eclipse.jdt.core.JavaCore;
42 import org.eclipse.jdt.core.JavaModelException;
43 import org.eclipse.jdt.launching.JavaRuntime;
44
45 import java.util.ArrayList;
46 import java.util.List;
47
48 /**
49  * Utility class to manipulate Project parameters/properties.
50  */
51 public final class ProjectHelper {
52     public final static int COMPILER_COMPLIANCE_OK = 0;
53     public final static int COMPILER_COMPLIANCE_LEVEL = 1;
54     public final static int COMPILER_COMPLIANCE_SOURCE = 2;
55     public final static int COMPILER_COMPLIANCE_CODEGEN_TARGET = 3;
56
57     /**
58      * Adds the corresponding source folder to the class path entries.
59      *
60      * @param entries The class path entries to read. A copy will be returned.
61      * @param new_entry The parent source folder to remove.
62      * @return A new class path entries array.
63      */
64     public static IClasspathEntry[] addEntryToClasspath(
65             IClasspathEntry[] entries, IClasspathEntry new_entry) {
66         int n = entries.length;
67         IClasspathEntry[] newEntries = new IClasspathEntry[n + 1];
68         System.arraycopy(entries, 0, newEntries, 0, n);
69         newEntries[n] = new_entry;
70         return newEntries;
71     }
72
73     /**
74      * Adds the corresponding source folder to the project's class path entries.
75      *
76      * @param javaProject The java project of which path entries to update.
77      * @param new_entry The parent source folder to remove.
78      * @throws JavaModelException
79      */
80     public static void addEntryToClasspath(
81             IJavaProject javaProject, IClasspathEntry new_entry)
82             throws JavaModelException {
83
84         IClasspathEntry[] entries = javaProject.getRawClasspath();
85         entries = addEntryToClasspath(entries, new_entry);
86         javaProject.setRawClasspath(entries, new NullProgressMonitor());
87     }
88
89     /**
90      * Remove a classpath entry from the array.
91      * @param entries The class path entries to read. A copy will be returned
92      * @param index The index to remove.
93      * @return A new class path entries array.
94      */
95     public static IClasspathEntry[] removeEntryFromClasspath(
96             IClasspathEntry[] entries, int index) {
97         int n = entries.length;
98         IClasspathEntry[] newEntries = new IClasspathEntry[n-1];
99
100         // copy the entries before index
101         System.arraycopy(entries, 0, newEntries, 0, index);
102
103         // copy the entries after index
104         System.arraycopy(entries, index + 1, newEntries, index,
105                 entries.length - index - 1);
106
107         return newEntries;
108     }
109
110     /**
111      * Converts a OS specific path into a path valid for the java doc location
112      * attributes of a project.
113      * @param javaDocOSLocation The OS specific path.
114      * @return a valid path for the java doc location.
115      */
116     public static String getJavaDocPath(String javaDocOSLocation) {
117         // first thing we do is convert the \ into /
118         String javaDoc = javaDocOSLocation.replaceAll("\\\\", //$NON-NLS-1$
119                 AndroidConstants.WS_SEP);
120
121         // then we add file: at the beginning for unix path, and file:/ for non
122         // unix path
123         if (javaDoc.startsWith(AndroidConstants.WS_SEP)) {
124             return "file:" + javaDoc; //$NON-NLS-1$
125         }
126
127         return "file:/" + javaDoc; //$NON-NLS-1$
128     }
129
130     /**
131      * Look for a specific classpath entry by full path and return its index.
132      * @param entries The entry array to search in.
133      * @param entryPath The OS specific path of the entry.
134      * @param entryKind The kind of the entry. Accepted values are 0
135      * (no filter), IClasspathEntry.CPE_LIBRARY, IClasspathEntry.CPE_PROJECT,
136      * IClasspathEntry.CPE_SOURCE, IClasspathEntry.CPE_VARIABLE,
137      * and IClasspathEntry.CPE_CONTAINER
138      * @return the index of the found classpath entry or -1.
139      */
140     public static int findClasspathEntryByPath(IClasspathEntry[] entries,
141             String entryPath, int entryKind) {
142         for (int i = 0 ; i < entries.length ; i++) {
143             IClasspathEntry entry = entries[i];
144
145             int kind = entry.getEntryKind();
146
147             if (kind == entryKind || entryKind == 0) {
148                 // get the path
149                 IPath path = entry.getPath();
150
151                 String osPathString = path.toOSString();
152                 if (osPathString.equals(entryPath)) {
153                     return i;
154                 }
155             }
156         }
157
158         // not found, return bad index.
159         return -1;
160     }
161
162     /**
163      * Look for a specific classpath entry for file name only and return its
164      *  index.
165      * @param entries The entry array to search in.
166      * @param entryName The filename of the entry.
167      * @param entryKind The kind of the entry. Accepted values are 0
168      * (no filter), IClasspathEntry.CPE_LIBRARY, IClasspathEntry.CPE_PROJECT,
169      * IClasspathEntry.CPE_SOURCE, IClasspathEntry.CPE_VARIABLE,
170      * and IClasspathEntry.CPE_CONTAINER
171      * @param startIndex Index where to start the search
172      * @return the index of the found classpath entry or -1.
173      */
174     public static int findClasspathEntryByName(IClasspathEntry[] entries,
175             String entryName, int entryKind, int startIndex) {
176         if (startIndex < 0) {
177             startIndex = 0;
178         }
179         for (int i = startIndex ; i < entries.length ; i++) {
180             IClasspathEntry entry = entries[i];
181
182             int kind = entry.getEntryKind();
183
184             if (kind == entryKind || entryKind == 0) {
185                 // get the path
186                 IPath path = entry.getPath();
187                 String name = path.segment(path.segmentCount()-1);
188
189                 if (name.equals(entryName)) {
190                     return i;
191                 }
192             }
193         }
194
195         // not found, return bad index.
196         return -1;
197     }
198
199     /**
200      * Fix the project. This checks the SDK location.
201      * @param project The project to fix.
202      * @throws JavaModelException
203      */
204     public static void fixProject(IProject project) throws JavaModelException {
205         if (AdtPlugin.getOsSdkFolder().length() == 0) {
206             AdtPlugin.printToConsole(project, "Unknown SDK Location, project not fixed.");
207             return;
208         }
209
210         // get a java project
211         IJavaProject javaProject = JavaCore.create(project);
212         fixProjectClasspathEntries(javaProject);
213     }
214
215     /**
216      * Fix the project classpath entries. The method ensures that:
217      * <ul>
218      * <li>The project does not reference any old android.zip/android.jar archive.</li>
219      * <li>The project does not use its output folder as a sourc folder.</li>
220      * <li>The project does not reference a desktop JRE</li>
221      * <li>The project references the AndroidClasspathContainer.
222      * </ul>
223      * @param javaProject The project to fix.
224      * @throws JavaModelException
225      */
226     public static void fixProjectClasspathEntries(IJavaProject javaProject)
227             throws JavaModelException {
228
229         // get the project classpath
230         IClasspathEntry[] entries = javaProject.getRawClasspath();
231         IClasspathEntry[] oldEntries = entries;
232
233         // check if the JRE is set as library
234         int jreIndex = ProjectHelper.findClasspathEntryByPath(entries, JavaRuntime.JRE_CONTAINER,
235                 IClasspathEntry.CPE_CONTAINER);
236         if (jreIndex != -1) {
237             // the project has a JRE included, we remove it
238             entries = ProjectHelper.removeEntryFromClasspath(entries, jreIndex);
239         }
240
241         // get the output folder
242         IPath outputFolder = javaProject.getOutputLocation();
243
244         boolean foundContainer = false;
245
246         for (int i = 0 ; i < entries.length ;) {
247             // get the entry and kind
248             IClasspathEntry entry = entries[i];
249             int kind = entry.getEntryKind();
250
251             if (kind == IClasspathEntry.CPE_SOURCE) {
252                 IPath path = entry.getPath();
253
254                 if (path.equals(outputFolder)) {
255                     entries = ProjectHelper.removeEntryFromClasspath(entries, i);
256
257                     // continue, to skip the i++;
258                     continue;
259                 }
260             } else if (kind == IClasspathEntry.CPE_CONTAINER) {
261                 if (AndroidClasspathContainerInitializer.checkPath(entry.getPath())) {
262                     foundContainer = true;
263                 }
264             }
265
266             i++;
267         }
268
269         // if the framework container is not there, we add it
270         if (foundContainer == false) {
271             // add the android container to the array
272             entries = ProjectHelper.addEntryToClasspath(entries,
273                     AndroidClasspathContainerInitializer.getContainerEntry());
274         }
275
276         // set the new list of entries to the project
277         if (entries != oldEntries) {
278             javaProject.setRawClasspath(entries, new NullProgressMonitor());
279         }
280
281         // If needed, check and fix compiler compliance and source compatibility
282         ProjectHelper.checkAndFixCompilerCompliance(javaProject);
283     }
284
285
286     /**
287      * Checks the project compiler compliance level is supported.
288      * @param javaProject The project to check
289      * @return <ul>
290      * <li><code>COMPILER_COMPLIANCE_OK</code> if the project is properly configured</li>
291      * <li><code>COMPILER_COMPLIANCE_LEVEL</code> for unsupported compiler level</li>
292      * <li><code>COMPILER_COMPLIANCE_SOURCE</code> for unsupported source compatibility</li>
293      * <li><code>COMPILER_COMPLIANCE_CODEGEN_TARGET</code> for unsupported .class format</li>
294      * </ul>
295      */
296     public static final int checkCompilerCompliance(IJavaProject javaProject) {
297         // get the project compliance level option
298         String compliance = javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);
299
300         // check it against a list of valid compliance level strings.
301         if (checkCompliance(compliance) == false) {
302             // if we didn't find the proper compliance level, we return an error
303             return COMPILER_COMPLIANCE_LEVEL;
304         }
305
306         // otherwise we check source compatibility
307         String source = javaProject.getOption(JavaCore.COMPILER_SOURCE, true);
308
309         // check it against a list of valid compliance level strings.
310         if (checkCompliance(source) == false) {
311             // if we didn't find the proper compliance level, we return an error
312             return COMPILER_COMPLIANCE_SOURCE;
313         }
314
315         // otherwise check codegen level
316         String codeGen = javaProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true);
317
318         // check it against a list of valid compliance level strings.
319         if (checkCompliance(codeGen) == false) {
320             // if we didn't find the proper compliance level, we return an error
321             return COMPILER_COMPLIANCE_CODEGEN_TARGET;
322         }
323
324         return COMPILER_COMPLIANCE_OK;
325     }
326
327     /**
328      * Checks the project compiler compliance level is supported.
329      * @param project The project to check
330      * @return <ul>
331      * <li><code>COMPILER_COMPLIANCE_OK</code> if the project is properly configured</li>
332      * <li><code>COMPILER_COMPLIANCE_LEVEL</code> for unsupported compiler level</li>
333      * <li><code>COMPILER_COMPLIANCE_SOURCE</code> for unsupported source compatibility</li>
334      * <li><code>COMPILER_COMPLIANCE_CODEGEN_TARGET</code> for unsupported .class format</li>
335      * </ul>
336      */
337     public static final int checkCompilerCompliance(IProject project) {
338         // get the java project from the IProject resource object
339         IJavaProject javaProject = JavaCore.create(project);
340
341         // check and return the result.
342         return checkCompilerCompliance(javaProject);
343     }
344
345
346     /**
347      * Checks, and fixes if needed, the compiler compliance level, and the source compatibility
348      * level
349      * @param project The project to check and fix.
350      */
351     public static final void checkAndFixCompilerCompliance(IProject project) {
352         // get the java project from the IProject resource object
353         IJavaProject javaProject = JavaCore.create(project);
354
355         // Now we check the compiler compliance level and make sure it is valid
356         checkAndFixCompilerCompliance(javaProject);
357     }
358
359     /**
360      * Checks, and fixes if needed, the compiler compliance level, and the source compatibility
361      * level
362      * @param javaProject The Java project to check and fix.
363      */
364     public static final void checkAndFixCompilerCompliance(IJavaProject javaProject) {
365         if (checkCompilerCompliance(javaProject) != COMPILER_COMPLIANCE_OK) {
366             // setup the preferred compiler compliance level.
367             javaProject.setOption(JavaCore.COMPILER_COMPLIANCE,
368                     AndroidConstants.COMPILER_COMPLIANCE_PREFERRED);
369             javaProject.setOption(JavaCore.COMPILER_SOURCE,
370                     AndroidConstants.COMPILER_COMPLIANCE_PREFERRED);
371             javaProject.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM,
372                     AndroidConstants.COMPILER_COMPLIANCE_PREFERRED);
373
374             // clean the project to make sure we recompile
375             try {
376                 javaProject.getProject().build(IncrementalProjectBuilder.CLEAN_BUILD,
377                         new NullProgressMonitor());
378             } catch (CoreException e) {
379                 AdtPlugin.printErrorToConsole(javaProject.getProject(),
380                         "Project compiler settings changed. Clean your project.");
381             }
382         }
383     }
384
385     /**
386      * Returns a {@link IProject} by its running application name, as it returned by the AVD.
387      * <p/>
388      * <var>applicationName</var> will in most case be the package declared in the manifest, but
389      * can, in some cases, be a custom process name declared in the manifest, in the
390      * <code>application</code>, <code>activity</code>, <code>receiver</code>, or
391      * <code>service</code> nodes.
392      * @param applicationName The application name.
393      * @return a project or <code>null</code> if no matching project were found.
394      */
395     public static IProject findAndroidProjectByAppName(String applicationName) {
396         // Get the list of project for the current workspace
397         IWorkspace workspace = ResourcesPlugin.getWorkspace();
398         IProject[] projects = workspace.getRoot().getProjects();
399
400         // look for a project that matches the packageName of the app
401         // we're trying to debug
402         for (IProject p : projects) {
403             if (p.isOpen()) {
404                 try {
405                     if (p.hasNature(AndroidConstants.NATURE_DEFAULT) == false) {
406                         // ignore non android projects
407                         continue;
408                     }
409                 } catch (CoreException e) {
410                     // failed to get the nature? skip project.
411                     continue;
412                 }
413
414                 // check that there is indeed a manifest file.
415                 IFile manifestFile = getManifest(p);
416                 if (manifestFile == null) {
417                     // no file? skip this project.
418                     continue;
419                 }
420
421                 ManifestData data = AndroidManifestHelper.parseForData(manifestFile);
422                 if (data == null) {
423                     // skip this project.
424                     continue;
425                 }
426
427                 String manifestPackage = data.getPackage();
428
429                 if (manifestPackage != null && manifestPackage.equals(applicationName)) {
430                     // this is the project we were looking for!
431                     return p;
432                 } else {
433                     // if the package and application name don't match,
434                     // we look for other possible process names declared in the manifest.
435                     String[] processes = data.getProcesses();
436                     for (String process : processes) {
437                         if (process.equals(applicationName)) {
438                             return p;
439                         }
440                     }
441                 }
442             }
443         }
444
445         return null;
446
447     }
448
449     public static void fixProjectNatureOrder(IProject project) throws CoreException {
450         IProjectDescription description = project.getDescription();
451         String[] natures = description.getNatureIds();
452
453         // if the android nature is not the first one, we reorder them
454         if (AndroidConstants.NATURE_DEFAULT.equals(natures[0]) == false) {
455             // look for the index
456             for (int i = 0 ; i < natures.length ; i++) {
457                 if (AndroidConstants.NATURE_DEFAULT.equals(natures[i])) {
458                     // if we try to just reorder the array in one pass, this doesn't do
459                     // anything. I guess JDT check that we are actually adding/removing nature.
460                     // So, first we'll remove the android nature, and then add it back.
461
462                     // remove the android nature
463                     removeNature(project, AndroidConstants.NATURE_DEFAULT);
464
465                     // now add it back at the first index.
466                     description = project.getDescription();
467                     natures = description.getNatureIds();
468
469                     String[] newNatures = new String[natures.length + 1];
470
471                     // first one is android
472                     newNatures[0] = AndroidConstants.NATURE_DEFAULT;
473
474                     // next the rest that was before the android nature
475                     System.arraycopy(natures, 0, newNatures, 1, natures.length);
476
477                     // set the new natures
478                     description.setNatureIds(newNatures);
479                     project.setDescription(description, null);
480
481                     // and stop
482                     break;
483                 }
484             }
485         }
486     }
487
488
489     /**
490      * Removes a specific nature from a project.
491      * @param project The project to remove the nature from.
492      * @param nature The nature id to remove.
493      * @throws CoreException
494      */
495     public static void removeNature(IProject project, String nature) throws CoreException {
496         IProjectDescription description = project.getDescription();
497         String[] natures = description.getNatureIds();
498
499         // check if the project already has the android nature.
500         for (int i = 0; i < natures.length; ++i) {
501             if (nature.equals(natures[i])) {
502                 String[] newNatures = new String[natures.length - 1];
503                 if (i > 0) {
504                     System.arraycopy(natures, 0, newNatures, 0, i);
505                 }
506                 System.arraycopy(natures, i + 1, newNatures, i, natures.length - i - 1);
507                 description.setNatureIds(newNatures);
508                 project.setDescription(description, null);
509
510                 return;
511             }
512         }
513
514     }
515
516     /**
517      * Returns if the project has error level markers.
518      * @param includeReferencedProjects flag to also test the referenced projects.
519      * @throws CoreException
520      */
521     public static boolean hasError(IProject project, boolean includeReferencedProjects)
522     throws CoreException {
523         IMarker[] markers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
524         if (markers != null && markers.length > 0) {
525             // the project has marker(s). even though they are "problem" we
526             // don't know their severity. so we loop on them and figure if they
527             // are warnings or errors
528             for (IMarker m : markers) {
529                 int s = m.getAttribute(IMarker.SEVERITY, -1);
530                 if (s == IMarker.SEVERITY_ERROR) {
531                     return true;
532                 }
533             }
534         }
535
536         // test the referenced projects if needed.
537         if (includeReferencedProjects) {
538             IProject[] projects = getReferencedProjects(project);
539
540             for (IProject p : projects) {
541                 if (hasError(p, false)) {
542                     return true;
543                 }
544             }
545         }
546
547         return false;
548     }
549
550     /**
551      * Saves a String property into the persistent storage of a resource.
552      * @param resource The resource into which the string value is saved.
553      * @param propertyName the name of the property. The id of the plug-in is added to this string.
554      * @param value the value to save
555      * @return true if the save succeeded.
556      */
557     public static boolean saveStringProperty(IResource resource, String propertyName,
558             String value) {
559         QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID, propertyName);
560
561         try {
562             resource.setPersistentProperty(qname, value);
563         } catch (CoreException e) {
564             return false;
565         }
566
567         return true;
568     }
569
570     /**
571      * Loads a String property from the persistent storage of a resource.
572      * @param resource The resource from which the string value is loaded.
573      * @param propertyName the name of the property. The id of the plug-in is added to this string.
574      * @return the property value or null if it was not found.
575      */
576     public static String loadStringProperty(IResource resource, String propertyName) {
577         QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID, propertyName);
578
579         try {
580             String value = resource.getPersistentProperty(qname);
581             return value;
582         } catch (CoreException e) {
583             return null;
584         }
585     }
586
587     /**
588      * Saves a property into the persistent storage of a resource.
589      * @param resource The resource into which the boolean value is saved.
590      * @param propertyName the name of the property. The id of the plug-in is added to this string.
591      * @param value the value to save
592      * @return true if the save succeeded.
593      */
594     public static boolean saveBooleanProperty(IResource resource, String propertyName,
595             boolean value) {
596         return saveStringProperty(resource, propertyName, Boolean.toString(value));
597     }
598
599     /**
600      * Loads a boolean property from the persistent storage of a resource.
601      * @param resource The resource from which the boolean value is loaded.
602      * @param propertyName the name of the property. The id of the plug-in is added to this string.
603      * @param defaultValue The default value to return if the property was not found.
604      * @return the property value or the default value if the property was not found.
605      */
606     public static boolean loadBooleanProperty(IResource resource, String propertyName,
607             boolean defaultValue) {
608         String value = loadStringProperty(resource, propertyName);
609         if (value != null) {
610             return Boolean.parseBoolean(value);
611         }
612
613         return defaultValue;
614     }
615
616     /**
617      * Saves the path of a resource into the persistent storage of a resource.
618      * @param resource The resource into which the resource path is saved.
619      * @param propertyName the name of the property. The id of the plug-in is added to this string.
620      * @param value The resource to save. It's its path that is actually stored. If null, an
621      *      empty string is stored.
622      * @return true if the save succeeded
623      */
624     public static boolean saveResourceProperty(IResource resource, String propertyName,
625             IResource value) {
626         if (value != null) {
627             IPath iPath = value.getFullPath();
628             return saveStringProperty(resource, propertyName, iPath.toString());
629         }
630
631         return saveStringProperty(resource, propertyName, ""); //$NON-NLS-1$
632     }
633
634     /**
635      * Loads the path of a resource from the persistent storage of a resource, and returns the
636      * corresponding IResource object.
637      * @param resource The resource from which the resource path is loaded.
638      * @param propertyName the name of the property. The id of the plug-in is added to this string.
639      * @return The corresponding IResource object (or children interface) or null
640      */
641     public static IResource loadResourceProperty(IResource resource, String propertyName) {
642         String value = loadStringProperty(resource, propertyName);
643
644         if (value != null && value.length() > 0) {
645             return ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(value));
646         }
647
648         return null;
649     }
650
651     /**
652      * Returns the list of referenced project that are opened and Java projects.
653      * @param project
654      * @return list of opened referenced java project.
655      * @throws CoreException
656      */
657     public static IProject[] getReferencedProjects(IProject project) throws CoreException {
658         IProject[] projects = project.getReferencedProjects();
659
660         ArrayList<IProject> list = new ArrayList<IProject>();
661
662         for (IProject p : projects) {
663             if (p.isOpen() && p.hasNature(JavaCore.NATURE_ID)) {
664                 list.add(p);
665             }
666         }
667
668         return list.toArray(new IProject[list.size()]);
669     }
670
671
672     /**
673      * Checks a Java project compiler level option against a list of supported versions.
674      * @param optionValue the Compiler level option.
675      * @return true if the option value is supproted.
676      */
677     private static boolean checkCompliance(String optionValue) {
678         for (String s : AndroidConstants.COMPILER_COMPLIANCE) {
679             if (s != null && s.equals(optionValue)) {
680                 return true;
681             }
682         }
683
684         return false;
685     }
686
687     /**
688      * Returns the apk filename for the given project
689      * @param project The project.
690      * @param config An optional config name. Can be null.
691      */
692     public static String getApkFilename(IProject project, String config) {
693         if (config != null) {
694             return project.getName() + "-" + config + AndroidConstants.DOT_ANDROID_PACKAGE; //$NON-NLS-1$
695         }
696
697         return project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
698     }
699
700     /**
701      * Find the list of projects on which this JavaProject is dependent on at the compilation level.
702      *
703      * @param javaProject Java project that we are looking for the dependencies.
704      * @return A list of Java projects for which javaProject depend on.
705      * @throws JavaModelException
706      */
707     public static List<IJavaProject> getAndroidProjectDependencies(IJavaProject javaProject)
708         throws JavaModelException {
709         String[] requiredProjectNames = javaProject.getRequiredProjectNames();
710
711         // Go from java project name to JavaProject name
712         IJavaModel javaModel = javaProject.getJavaModel();
713
714         // loop through all dependent projects and keep only those that are Android projects
715         List<IJavaProject> projectList = new ArrayList<IJavaProject>(requiredProjectNames.length);
716         for (String javaProjectName : requiredProjectNames) {
717             IJavaProject androidJavaProject = javaModel.getJavaProject(javaProjectName);
718
719             //Verify that the project has also the Android Nature
720             try {
721                 if (!androidJavaProject.getProject().hasNature(AndroidConstants.NATURE_DEFAULT)) {
722                     continue;
723                 }
724             } catch (CoreException e) {
725                 continue;
726             }
727
728             projectList.add(androidJavaProject);
729         }
730
731         return projectList;
732     }
733
734     /**
735      * Returns the android package file as an IFile object for the specified
736      * project.
737      * @param project The project
738      * @return The android package as an IFile object or null if not found.
739      */
740     public static IFile getApplicationPackage(IProject project) {
741         // get the output folder
742         IFolder outputLocation = BaseProjectHelper.getOutputFolder(project);
743
744         if (outputLocation == null) {
745             AdtPlugin.printErrorToConsole(project,
746                     "Failed to get the output location of the project. Check build path properties"
747                     );
748             return null;
749         }
750
751
752         // get the package path
753         String packageName = project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
754         IResource r = outputLocation.findMember(packageName);
755
756         // check the package is present
757         if (r instanceof IFile && r.exists()) {
758             return (IFile)r;
759         }
760
761         String msg = String.format("Could not find %1$s!", packageName);
762         AdtPlugin.printErrorToConsole(project, msg);
763
764         return null;
765     }
766
767     /**
768      * Returns an {@link IFile} object representing the manifest for the given project.
769      *
770      * @param project The project containing the manifest file.
771      * @return An IFile object pointing to the manifest or null if the manifest
772      *         is missing.
773      */
774     public static IFile getManifest(IProject project) {
775         IResource r = project.findMember(AndroidConstants.WS_SEP
776                 + SdkConstants.FN_ANDROID_MANIFEST_XML);
777
778         if (r == null || r.exists() == false || (r instanceof IFile) == false) {
779             return null;
780         }
781         return (IFile) r;
782     }
783 }