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