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 */ addEntryToClasspath( IClasspathEntry[] entries, IClasspathEntry new_entry)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 */ addEntryToClasspath( IJavaProject javaProject, IClasspathEntry new_entry)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 */ removeEntryFromClasspath( IClasspathEntry[] entries, int index)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 */ getJavaDocPath(String javaDocOSLocation)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 */ findClasspathEntryByPath(IClasspathEntry[] entries, String entryPath, int entryKind)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 */ findClasspathEntryByName(IClasspathEntry[] entries, String entryName, int entryKind, int startIndex)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 */ fixProject(IProject project)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 */ fixProjectClasspathEntries(IJavaProject javaProject)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 */ checkCompilerCompliance(IJavaProject javaProject)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 */ checkCompilerCompliance(IProject project)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 */ checkAndFixCompilerCompliance(IProject project)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 */ checkAndFixCompilerCompliance(IJavaProject javaProject)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 */ findAndroidProjectByAppName(String applicationName)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 fixProjectNatureOrder(IProject project)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 */ removeNature(IProject project, String nature)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 */ hasError(IProject project, boolean includeReferencedProjects)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 */ saveStringProperty(IResource resource, String propertyName, String value)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 */ loadStringProperty(IResource resource, String propertyName)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 */ saveBooleanProperty(IResource resource, String propertyName, boolean value)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 */ loadBooleanProperty(IResource resource, String propertyName, boolean defaultValue)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 */ saveResourceProperty(IResource resource, String propertyName, IResource value)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 */ loadResourceProperty(IResource resource, String propertyName)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 */ getReferencedProjects(IProject project)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 */ checkCompliance(String optionValue)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 */ getApkFilename(IProject project, String config)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 */ getAndroidProjectDependencies(IJavaProject javaProject)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 */ getApplicationPackage(IProject project)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 */ getManifest(IProject project)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 } 784