1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 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.ant; 18 19 import com.android.ant.DependencyHelper.LibraryProcessorFor3rdPartyJars; 20 import com.android.io.FileWrapper; 21 import com.android.sdklib.SdkConstants; 22 import com.android.sdklib.internal.project.IPropertySource; 23 import com.android.sdklib.xml.AndroidManifest; 24 25 import org.apache.tools.ant.BuildException; 26 import org.apache.tools.ant.Project; 27 import org.apache.tools.ant.types.Path; 28 import org.apache.tools.ant.types.Path.PathElement; 29 30 import java.io.File; 31 import java.util.List; 32 33 /** 34 * Computes the dependency of the current project. 35 * 36 * Out params: 37 * <code>libraryResFolderPathOut</code>: the Path object containing the res folder for all the 38 * library projects in the order needed by aapt. 39 * 40 * <code>libraryPackagesOut</code>: a simple property containing ;-separated package name from 41 * the library projects. 42 * 43 * <code>jarLibraryPathOut</code>: the Path object containing all the 3rd party jar files. 44 * 45 * <code>libraryNativeFolderPathOut</code>: the Path with all the native folder for the library 46 * projects. 47 * 48 * 49 * In params: 50 * <code>targetApi</code>: the compilation target api. 51 * <code>verbose</code>: whether the build is verbose. 52 * 53 */ 54 public class ComputeDependencyTask extends GetLibraryListTask { 55 56 private String mLibraryManifestFilePathOut; 57 private String mLibraryResFolderPathOut; 58 private String mLibraryPackagesOut; 59 private String mJarLibraryPathOut; 60 private String mLibraryNativeFolderPathOut; 61 private int mTargetApi = -1; 62 private boolean mVerbose = false; 63 64 public void setLibraryManifestFilePathOut(String libraryManifestFilePathOut) { 65 mLibraryManifestFilePathOut = libraryManifestFilePathOut; 66 } 67 68 public void setLibraryResFolderPathOut(String libraryResFolderPathOut) { 69 mLibraryResFolderPathOut = libraryResFolderPathOut; 70 } 71 72 public void setLibraryPackagesOut(String libraryPackagesOut) { 73 mLibraryPackagesOut = libraryPackagesOut; 74 } 75 76 public void setJarLibraryPathOut(String jarLibraryPathOut) { 77 mJarLibraryPathOut = jarLibraryPathOut; 78 } 79 80 public void setLibraryNativeFolderPathOut(String libraryNativeFolderPathOut) { 81 mLibraryNativeFolderPathOut = libraryNativeFolderPathOut; 82 } 83 84 public void setTargetApi(int targetApi) { 85 mTargetApi = targetApi; 86 } 87 88 /** 89 * Sets the value of the "verbose" attribute. 90 * @param verbose the value. 91 */ 92 public void setVerbose(boolean verbose) { 93 mVerbose = verbose; 94 } 95 96 @Override 97 public void execute() throws BuildException { 98 if (mLibraryManifestFilePathOut == null) { 99 throw new BuildException("Missing attribute libraryManifestFilePathOut"); 100 } 101 if (mLibraryResFolderPathOut == null) { 102 throw new BuildException("Missing attribute libraryResFolderPathOut"); 103 } 104 if (mLibraryPackagesOut == null) { 105 throw new BuildException("Missing attribute libraryPackagesOut"); 106 } 107 if (mJarLibraryPathOut == null) { 108 throw new BuildException("Missing attribute jarLibraryPathOut"); 109 } 110 if (mLibraryNativeFolderPathOut == null) { 111 throw new BuildException("Missing attribute libraryNativeFolderPathOut"); 112 } 113 if (mTargetApi == -1) { 114 throw new BuildException("Missing attribute targetApi"); 115 } 116 117 final Project antProject = getProject(); 118 119 // get the SDK location 120 File sdkDir = TaskHelper.getSdkLocation(antProject); 121 122 // prepare several paths for future tasks 123 final Path manifestFilePath = new Path(antProject); 124 final Path resFolderPath = new Path(antProject); 125 final Path nativeFolderPath = new Path(antProject); 126 final StringBuilder packageStrBuilder = new StringBuilder(); 127 128 LibraryProcessorFor3rdPartyJars processor = new LibraryProcessorFor3rdPartyJars() { 129 @Override 130 public void processLibrary(String libRootPath) { 131 // let the super class handle the jar files 132 super.processLibrary(libRootPath); 133 134 // get the AndroidManifest.xml path. 135 // FIXME: support renamed location. 136 PathElement element = manifestFilePath.createPathElement(); 137 element.setPath(libRootPath + "/" + SdkConstants.FN_ANDROID_MANIFEST_XML); 138 139 // get the res path. $PROJECT/res as well as the crunch cache. 140 // FIXME: support renamed folders. 141 element = resFolderPath.createPathElement(); 142 element.setPath(libRootPath + "/" + SdkConstants.FD_OUTPUT + 143 "/" + SdkConstants.FD_RES); 144 element = resFolderPath.createPathElement(); 145 element.setPath(libRootPath + "/" + SdkConstants.FD_RESOURCES); 146 147 148 // get the folder for the native libraries. Always $PROJECT/libs 149 // FIXME: support renamed folder. 150 element = nativeFolderPath.createPathElement(); 151 element.setPath(libRootPath + "/" + SdkConstants.FD_NATIVE_LIBS); 152 153 // get the package from the manifest. 154 FileWrapper manifest = new FileWrapper(libRootPath, 155 SdkConstants.FN_ANDROID_MANIFEST_XML); 156 157 try { 158 String value = AndroidManifest.getPackage(manifest); 159 if (value != null) { // aapt will complain if it's missing. 160 packageStrBuilder.append(';'); 161 packageStrBuilder.append(value); 162 } 163 } catch (Exception e) { 164 throw new BuildException(e); 165 } 166 } 167 }; 168 169 // list of all the jars that are on the classpath. This will receive the 170 // project's libs/*.jar files, the Library Projects output and their own libs/*.jar 171 List<File> jars = processor.getJars(); 172 173 174 // in case clean has been called before a build type target, the list of 175 // libraries has already been computed so we don't need to compute it again. 176 Path libraryFolderPath = (Path) antProject.getReference(getLibraryFolderPathOut()); 177 if (libraryFolderPath == null) { 178 execute(processor); 179 } else { 180 // this contains the list of library folder in reverse order (compilation order). 181 // We need to process it in the normal order (res order). 182 System.out.println("Ordered libraries:"); 183 184 String[] libraries = libraryFolderPath.list(); 185 for (int i = libraries.length - 1 ; i >= 0 ; i--) { 186 String libRootPath = libraries[i]; 187 System.out.println(libRootPath); 188 189 processor.processLibrary(libRootPath); 190 } 191 } 192 193 boolean hasLibraries = jars.size() > 0; 194 195 if (mTargetApi <= 15) { 196 System.out.println("\n------------------"); 197 System.out.println("API<=15: Adding annotations.jar to the classpath."); 198 199 jars.add(new File(sdkDir, SdkConstants.FD_TOOLS + 200 "/" + SdkConstants.FD_SUPPORT + 201 "/" + SdkConstants.FN_ANNOTATIONS_JAR)); 202 203 } 204 205 // even with no libraries, always setup these so that various tasks in Ant don't complain 206 // (the task themselves can handle a ref to an empty Path) 207 antProject.addReference(mLibraryNativeFolderPathOut, nativeFolderPath); 208 antProject.addReference(mLibraryManifestFilePathOut, manifestFilePath); 209 210 // the rest is done only if there's a library. 211 if (hasLibraries) { 212 antProject.addReference(mLibraryResFolderPathOut, resFolderPath); 213 antProject.setProperty(mLibraryPackagesOut, packageStrBuilder.toString()); 214 } 215 216 File projectFolder = antProject.getBaseDir(); 217 218 // add the project's own content of libs/*.jar 219 File libsFolder = new File(projectFolder, SdkConstants.FD_NATIVE_LIBS); 220 File[] jarFiles = libsFolder.listFiles(processor.getFilter()); 221 if (jarFiles != null) { 222 for (File jarFile : jarFiles) { 223 jars.add(jarFile); 224 } 225 } 226 227 // now sanitize the path to remove dups 228 jars = DependencyHelper.sanitizePaths(projectFolder, new IPropertySource() { 229 @Override 230 public String getProperty(String name) { 231 return antProject.getProperty(name); 232 } 233 }, jars); 234 235 // and create a Path object for them 236 Path jarsPath = new Path(antProject); 237 if (mVerbose) { 238 System.out.println("\n------------------\nSanitized jar list:"); 239 } 240 for (File f : jars) { 241 if (mVerbose) { 242 System.out.println("- " + f.getAbsolutePath()); 243 } 244 PathElement element = jarsPath.createPathElement(); 245 element.setPath(f.getAbsolutePath()); 246 } 247 antProject.addReference(mJarLibraryPathOut, jarsPath); 248 249 if (mVerbose) { 250 System.out.println(); 251 } 252 253 } 254 } 255