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