OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / sdk / anttasks / src / com / android / ant / AaptExecLoopTask.java
1 /*
2  * Copyright (C) 2009 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 org.apache.tools.ant.BuildException;
20 import org.apache.tools.ant.Project;
21 import org.apache.tools.ant.Task;
22 import org.apache.tools.ant.taskdefs.ExecTask;
23 import org.apache.tools.ant.types.Path;
24
25 import java.io.File;
26 import java.util.ArrayList;
27
28 /**
29  * Task to execute aapt.
30  *
31  * <p>It does not follow the exec task format, instead it has its own parameters, which maps
32  * directly to aapt.</p>
33  * <p>It is able to run aapt several times if library setup requires generating several
34  * R.java files.
35  * <p>The following map shows how to use the task for each supported aapt command line
36  * parameter.</p>
37  *
38  * <table border="1">
39  * <tr><td><b>Aapt Option</b></td><td><b>Ant Name</b></td><td><b>Type</b></td></tr>
40  * <tr><td>path to aapt</td><td>executable</td><td>attribute (Path)</td>
41  * <tr><td>command</td><td>command</td><td>attribute (String)</td>
42  * <tr><td>-v</td><td>verbose</td><td>attribute (boolean)</td></tr>
43  * <tr><td>-f</td><td>force</td><td>attribute (boolean)</td></tr>
44  * <tr><td>-M AndroidManifest.xml</td><td>manifest</td><td>attribute (Path)</td></tr>
45  * <tr><td>-I base-package</td><td>androidjar</td><td>attribute (Path)</td></tr>
46  * <tr><td>-A asset-source-dir</td><td>assets</td><td>attribute (Path</td></tr>
47  * <tr><td>-S resource-sources</td><td>&lt;res path=""&gt;</td><td>nested element(s)<br>with attribute (Path)</td></tr>
48  * <tr><td>-0 extension</td><td>&lt;nocompress extension=""&gt;<br>&lt;nocompress&gt;</td><td>nested element(s)<br>with attribute (String)</td></tr>
49  * <tr><td>-F apk-file</td><td>apkfolder<br>outfolder<br>apkbasename<br>basename</td><td>attribute (Path)<br>attribute (Path) deprecated<br>attribute (String)<br>attribute (String) deprecated</td></tr>
50  * <tr><td>-J R-file-dir</td><td>rfolder</td><td>attribute (Path)<br>-m always enabled</td></tr>
51  * <tr><td></td><td></td><td></td></tr>
52  * </table>
53  */
54 public final class AaptExecLoopTask extends Task {
55
56     /**
57      * Class representing a &lt;nocompress&gt; node in the main task XML.
58      * This let the developers prevent compression of some files in assets/ and res/raw/
59      * by extension.
60      * If the extension is null, this will disable compression for all  files in assets/ and
61      * res/raw/
62      */
63     public final static class NoCompress {
64         String mExtension;
65
66         /**
67          * Sets the value of the "extension" attribute.
68          * @param extention the extension.
69          */
70         public void setExtension(String extention) {
71             mExtension = extention;
72         }
73     }
74
75     private String mExecutable;
76     private String mCommand;
77     private boolean mForce = true; // true due to legacy reasons
78     private boolean mVerbose = false;
79     private int mVersionCode = 0;
80     private String mManifest;
81     private ArrayList<Path> mResources;
82     private String mAssets;
83     private String mAndroidJar;
84     private String mApkFolder;
85     @Deprecated private String mApkBaseName;
86     private String mApkName;
87     private String mResourceFilter;
88     private String mRFolder;
89     private final ArrayList<NoCompress> mNoCompressList = new ArrayList<NoCompress>();
90
91     /**
92      * Sets the value of the "executable" attribute.
93      * @param executable the value.
94      */
95     public void setExecutable(Path executable) {
96         mExecutable = TaskHelper.checkSinglePath("executable", executable);
97     }
98
99     /**
100      * Sets the value of the "command" attribute.
101      * @param command the value.
102      */
103     public void setCommand(String command) {
104         mCommand = command;
105     }
106
107     /**
108      * Sets the value of the "force" attribute.
109      * @param force the value.
110      */
111     public void setForce(boolean force) {
112         mForce = force;
113     }
114
115     /**
116      * Sets the value of the "verbose" attribute.
117      * @param verbose the value.
118      */
119     public void setVerbose(boolean verbose) {
120         mVerbose = verbose;
121     }
122
123     public void setVersioncode(String versionCode) {
124         if (versionCode.length() > 0) {
125             try {
126                 mVersionCode = Integer.decode(versionCode);
127             } catch (NumberFormatException e) {
128                 System.out.println(String.format(
129                         "WARNING: Ignoring invalid version code value '%s'.", versionCode));
130             }
131         }
132     }
133
134     /**
135      * Sets the value of the "manifest" attribute.
136      * @param manifest the value.
137      */
138     public void setManifest(Path manifest) {
139         mManifest = TaskHelper.checkSinglePath("manifest", manifest);
140     }
141
142     /**
143      * Sets the value of the "resources" attribute.
144      * @param resources the value.
145      *
146      * @deprecated Use nested element(s) <res path="value" />
147      */
148     @Deprecated
149     public void setResources(Path resources) {
150         System.out.println("WARNNG: Using deprecated 'resources' attribute in AaptExecLoopTask." +
151                 "Use nested element(s) <res path=\"value\" /> instead.");
152         if (mResources == null) {
153             mResources = new ArrayList<Path>();
154         }
155
156         mResources.add(new Path(getProject(), resources.toString()));
157     }
158
159     /**
160      * Sets the value of the "assets" attribute.
161      * @param assets the value.
162      */
163     public void setAssets(Path assets) {
164         mAssets = TaskHelper.checkSinglePath("assets", assets);
165     }
166
167     /**
168      * Sets the value of the "androidjar" attribute.
169      * @param androidJar the value.
170      */
171     public void setAndroidjar(Path androidJar) {
172         mAndroidJar = TaskHelper.checkSinglePath("androidjar", androidJar);
173     }
174
175     /**
176      * Sets the value of the "outfolder" attribute.
177      * @param outFolder the value.
178      * @deprecated use {@link #setApkfolder(Path)}
179      */
180     @Deprecated
181     public void setOutfolder(Path outFolder) {
182         System.out.println("WARNNG: Using deprecated 'outfolder' attribute in AaptExecLoopTask." +
183                 "Use 'apkfolder' (path) instead.");
184         mApkFolder = TaskHelper.checkSinglePath("outfolder", outFolder);
185     }
186
187     /**
188      * Sets the value of the "apkfolder" attribute.
189      * @param apkFolder the value.
190      */
191     public void setApkfolder(Path apkFolder) {
192         mApkFolder = TaskHelper.checkSinglePath("apkfolder", apkFolder);
193     }
194
195     /**
196      * Sets the value of the "basename" attribute.
197      * @param baseName the value.
198      * @deprecated use {@link #setApkbasename(String)}
199      */
200     @Deprecated
201     public void setBasename(String baseName) {
202         System.out.println("WARNNG: Using deprecated 'basename' attribute in AaptExecLoopTask." +
203                 "Use 'resourcefilename' (string) instead.");
204         mApkBaseName = baseName;
205     }
206
207     /**
208      * Sets the value of the "apkbasename" attribute.
209      * @param apkbaseName the value.
210      */
211     public void setApkbasename(String apkbaseName) {
212         System.out.println("WARNNG: Using deprecated 'apkbasename' attribute in AaptExecLoopTask." +
213                 "Use 'resourcefilename' (string) instead.");
214         mApkBaseName = apkbaseName;
215     }
216
217     /**
218      * Sets the value of the resourcefilename attribute
219      * @param apkName the value
220      */
221     public void setResourcefilename(String apkName) {
222         mApkName = apkName;
223     }
224
225     /**
226      * Sets the value of the "rfolder" attribute.
227      * @param rFolder the value.
228      */
229     public void setRfolder(Path rFolder) {
230         mRFolder = TaskHelper.checkSinglePath("rfolder", rFolder);
231     }
232
233     public void setresourcefilter(String filter) {
234         if (filter != null && filter.length() > 0) {
235             mResourceFilter = filter;
236         }
237     }
238
239     /**
240      * Returns an object representing a nested <var>nocompress</var> element.
241      */
242     public Object createNocompress() {
243         NoCompress nc = new NoCompress();
244         mNoCompressList.add(nc);
245         return nc;
246     }
247
248     /**
249      * Returns an object representing a nested <var>res</var> element.
250      */
251     public Object createRes() {
252         if (mResources == null) {
253             mResources = new ArrayList<Path>();
254         }
255
256         Path path = new Path(getProject());
257         mResources.add(path);
258
259         return path;
260     }
261
262     /*
263      * (non-Javadoc)
264      *
265      * Executes the loop. Based on the values inside default.properties, this will
266      * create alternate temporary ap_ files.
267      *
268      * @see org.apache.tools.ant.Task#execute()
269      */
270     @Override
271     public void execute() throws BuildException {
272         Project taskProject = getProject();
273
274         // first do a full resource package
275         callAapt(null /*customPackage*/);
276
277         // if the parameters indicate generation of the R class, check if
278         // more R classes need to be created for libraries.
279         if (mRFolder != null && new File(mRFolder).isDirectory()) {
280             String libPkgProp = taskProject.getProperty("android.libraries.package");
281             if (libPkgProp != null) {
282                 // get the main package to compare in case the libraries use the same
283                 String mainPackage = taskProject.getProperty("manifest.package");
284
285                 String[] libPkgs = libPkgProp.split(";");
286                 for (String libPkg : libPkgs) {
287                     if (libPkg.length() > 0 && mainPackage.equals(libPkg) == false) {
288                         // FIXME: instead of recreating R.java from scratch, maybe copy
289                         // the files (R.java and manifest.java)? This would force to replace
290                         // the package line on the fly.
291                         callAapt(libPkg);
292                     }
293                 }
294             }
295         }
296     }
297
298     /**
299      * Calls aapt with the given parameters.
300      * @param resourceFilter the resource configuration filter to pass to aapt (if configName is
301      * non null)
302      * @param customPackage an optional custom package.
303      */
304     private void callAapt(String customPackage) {
305         Project taskProject = getProject();
306
307         final boolean generateRClass = mRFolder != null && new File(mRFolder).isDirectory();
308
309         if (generateRClass) {
310         } else if (mResourceFilter == null) {
311             System.out.println("Creating full resource package...");
312         } else {
313             System.out.println(String.format(
314                     "Creating resource package with filter: (%1$s)...",
315                     mResourceFilter));
316         }
317
318         // create a task for the default apk.
319         ExecTask task = new ExecTask();
320         task.setExecutable(mExecutable);
321         task.setFailonerror(true);
322
323         // aapt command. Only "package" is supported at this time really.
324         task.createArg().setValue(mCommand);
325
326         // force flag
327         if (mForce) {
328             task.createArg().setValue("-f");
329         }
330
331         // verbose flag
332         if (mVerbose) {
333             task.createArg().setValue("-v");
334         }
335
336         if (generateRClass) {
337             task.createArg().setValue("-m");
338         }
339
340         // filters if needed
341         if (mResourceFilter != null) {
342             task.createArg().setValue("-c");
343             task.createArg().setValue(mResourceFilter);
344         }
345
346         // no compress flag
347         // first look to see if there's a NoCompress object with no specified extension
348         boolean compressNothing = false;
349         for (NoCompress nc : mNoCompressList) {
350             if (nc.mExtension == null) {
351                 task.createArg().setValue("-0");
352                 task.createArg().setValue("");
353                 compressNothing = true;
354                 break;
355             }
356         }
357
358         if (compressNothing == false) {
359             for (NoCompress nc : mNoCompressList) {
360                 task.createArg().setValue("-0");
361                 task.createArg().setValue(nc.mExtension);
362             }
363         }
364
365         if (customPackage != null) {
366             task.createArg().setValue("--custom-package");
367             task.createArg().setValue(customPackage);
368         }
369
370         // if the project contains libraries, force auto-add-overlay
371         Object libSrc = taskProject.getReference("android.libraries.res");
372         if (libSrc != null) {
373             task.createArg().setValue("--auto-add-overlay");
374         }
375
376         if (mVersionCode != 0) {
377             task.createArg().setValue("--version-code");
378             task.createArg().setValue(Integer.toString(mVersionCode));
379         }
380
381         // manifest location
382         if (mManifest != null) {
383             task.createArg().setValue("-M");
384             task.createArg().setValue(mManifest);
385         }
386
387         // resources locations.
388         if (mResources.size() > 0) {
389             for (Path pathList : mResources) {
390                 for (String path : pathList.list()) {
391                     // This may not exists, and aapt doesn't like it, so we check first.
392                     File res = new File(path);
393                     if (res.isDirectory()) {
394                         task.createArg().setValue("-S");
395                         task.createArg().setValue(path);
396                     }
397                 }
398             }
399         }
400
401         // add other resources coming from library project
402         Object libPath = taskProject.getReference("android.libraries.res");
403         if (libPath instanceof Path) {
404             for (String path : ((Path)libPath).list()) {
405                 // This may not exists, and aapt doesn't like it, so we check first.
406                 File res = new File(path);
407                 if (res.isDirectory()) {
408                     task.createArg().setValue("-S");
409                     task.createArg().setValue(path);
410                 }
411             }
412         }
413
414         // assets location. This may not exists, and aapt doesn't like it, so we check first.
415         if (mAssets != null && new File(mAssets).isDirectory()) {
416             task.createArg().setValue("-A");
417             task.createArg().setValue(mAssets);
418         }
419
420         // android.jar
421         if (mAndroidJar != null) {
422             task.createArg().setValue("-I");
423             task.createArg().setValue(mAndroidJar);
424         }
425
426         // apk file. This is based on the apkFolder, apkBaseName, and the configName (if applicable)
427         String filename = null;
428         if (mApkName != null) {
429             filename = mApkName;
430         } else if (mApkBaseName != null) {
431             filename = mApkBaseName + ".ap_";
432         }
433
434         if (filename != null) {
435             File file = new File(mApkFolder, filename);
436             task.createArg().setValue("-F");
437             task.createArg().setValue(file.getAbsolutePath());
438         }
439
440         // R class generation
441         if (generateRClass) {
442             task.createArg().setValue("-J");
443             task.createArg().setValue(mRFolder);
444         }
445
446         // final setup of the task
447         task.setProject(taskProject);
448         task.setOwningTarget(getOwningTarget());
449
450         // execute it.
451         task.execute();
452     }
453 }