1 package com.simpligility.maven.plugins.android.common;
2
3 import org.apache.commons.lang3.StringUtils;
4 import org.apache.maven.plugin.logging.Log;
5
6 import java.io.File;
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.Collections;
10 import java.util.List;
11
12 /**
13 * Collates commands used to invoke Aapt.
14 *
15 * @author Oleg Green
16 * @author William Ferguson
17 * @author Manfred Moser
18 */
19 public class AaptCommandBuilder
20 {
21 protected final List<String> commands;
22 protected final Log log;
23
24 protected AaptCommandBuilder( Log log )
25 {
26 this.log = log;
27 this.commands = new ArrayList<String>();
28 }
29
30 /**
31 * Package the android resources.
32 *
33 * @return instance of {@link AaptPackageCommandBuilder}
34 */
35 public static AaptPackageCommandBuilder packageResources( Log log )
36 {
37 return new AaptPackageCommandBuilder( log );
38 }
39
40 /**
41 * Dump label, icon, permissions, compiled xmls etc.
42 *
43 * @return instance of {@link AaptDumpCommandBuilder}
44 */
45 public static final AaptDumpCommandBuilder dump( Log log )
46 {
47 return new AaptDumpCommandBuilder( log );
48 }
49
50 /**
51 * Class that responsible for building appt commands for packaging resources
52 */
53 public static final class AaptPackageCommandBuilder extends AaptCommandBuilder
54 {
55 public AaptPackageCommandBuilder( Log log )
56 {
57 super( log );
58 commands.add( "package" );
59 }
60
61 /**
62 * Make the resources ID non constant.
63 *
64 * This is required to make an R java class
65 * that does not contain the final value but is used to make reusable compiled
66 * libraries that need to access resources.
67 *
68 * @return current instance of {@link AaptPackageCommandBuilder}
69 */
70 public AaptPackageCommandBuilder makeResourcesNonConstant()
71 {
72 return makeResourcesNonConstant( true );
73 }
74
75 /**
76 * Make the resources ID non constant.
77 *
78 * This is required to make an R java class
79 * that does not contain the final value but is used to make reusable compiled
80 * libraries that need to access resources.
81 *
82 * @param make if true make resources ID non constant, otherwise ignore
83 * @return current instance of {@link AaptPackageCommandBuilder}
84 */
85 public AaptPackageCommandBuilder makeResourcesNonConstant( boolean make )
86 {
87 if ( make )
88 {
89 log.debug( "Adding non-constant-id" );
90 commands.add( "--non-constant-id" );
91 }
92 return this;
93 }
94
95 /**
96 * Make package directories under location specified by {@link #setResourceConstantsFolder}.
97 *
98 * @return current instance of {@link AaptCommandBuilder}
99 */
100 public AaptPackageCommandBuilder makePackageDirectories()
101 {
102 commands.add( "-m" );
103 return this;
104 }
105
106 /**
107 * Specify where the R java resource constant definitions should be generated or found.
108 *
109 * @param path path to resource constants folder.
110 * @return current instance of {@link AaptCommandBuilder}
111 */
112 public AaptPackageCommandBuilder setResourceConstantsFolder( File path )
113 {
114 commands.add( "-J" );
115 commands.add( path.getAbsolutePath() );
116 return this;
117 }
118
119 /**
120 * Generates R java into a different package.
121 *
122 * @param packageName package name which generate R.java into
123 * @return current instance of {@link AaptCommandBuilder}
124 */
125 public AaptPackageCommandBuilder generateRIntoPackage( String packageName )
126 {
127 if ( StringUtils.isNotBlank( packageName ) )
128 {
129 commands.add( "--custom-package" );
130 commands.add( packageName );
131 }
132 return this;
133 }
134
135 /**
136 * Specify full path to AndroidManifest.xml to include in zip.
137 *
138 * @param path Path to AndroidManifest.xml
139 * @return current instance of {@link AaptCommandBuilder}
140 */
141 public AaptPackageCommandBuilder setPathToAndroidManifest( File path )
142 {
143 commands.add( "-M" );
144 commands.add( path.getAbsolutePath() );
145 return this;
146 }
147
148 /**
149 * Directory in which to find resources.
150 *
151 * Multiple directories will be scanned and the first match found (left to right) will take precedence.
152 *
153 * @param resourceDirectory resource directory {@link File}
154 * @return current instance of {@link AaptCommandBuilder}
155 */
156 public AaptPackageCommandBuilder addResourceDirectoryIfExists( File resourceDirectory )
157 {
158 if ( resourceDirectory != null && resourceDirectory.exists() )
159 {
160 commands.add( "-S" );
161 commands.add( resourceDirectory.getAbsolutePath() );
162 }
163 return this;
164 }
165
166 /**
167 * Directories in which to find resources.
168 *
169 * Multiple directories will be scanned and the first match found (left to right) will take precedence.
170 *
171 * @param resourceDirectories {@link List} of resource directories {@link File}
172 * @return current instance of {@link AaptCommandBuilder}
173 */
174 public AaptPackageCommandBuilder addResourceDirectoriesIfExists( List<File> resourceDirectories )
175 {
176 if ( resourceDirectories != null )
177 {
178 for ( File resourceDirectory : resourceDirectories )
179 {
180 addResourceDirectoryIfExists( resourceDirectory );
181 }
182 }
183 return this;
184 }
185
186 /**
187 * Directories in which to find resources.
188 *
189 * Multiple directories will be scanned and the first match found (left to right) will take precedence.
190 *
191 * @param resourceDirectories array of resource directories {@link File}
192 * @return current instance of {@link AaptCommandBuilder}
193 */
194 public AaptPackageCommandBuilder addResourceDirectoriesIfExists( File[] resourceDirectories )
195 {
196 if ( resourceDirectories != null )
197 {
198 for ( File resourceDirectory : resourceDirectories )
199 {
200 addResourceDirectoryIfExists( resourceDirectory );
201 }
202 }
203 return this;
204 }
205
206 /**
207 * Automatically add resources that are only in overlays.
208 *
209 * @return current instance of {@link AaptCommandBuilder}
210 */
211 public AaptPackageCommandBuilder autoAddOverlay()
212 {
213 commands.add( "--auto-add-overlay" );
214 return this;
215 }
216
217 /**
218 * Additional directory in which to find raw asset files.
219 *
220 * @param assetsFolder Folder containing the combined raw assets to add.
221 * @return current instance of {@link AaptCommandBuilder}
222 */
223 public AaptPackageCommandBuilder addRawAssetsDirectoryIfExists( File assetsFolder )
224 {
225 if ( assetsFolder != null && assetsFolder.exists() )
226 {
227 log.debug( "Adding assets folder : " + assetsFolder );
228 commands.add( "-A" );
229 commands.add( assetsFolder.getAbsolutePath() );
230 }
231 return this;
232 }
233
234 /**
235 * Add an existing package to base include set.
236 *
237 * @param path Path to existing package to add.
238 * @return current instance of {@link AaptCommandBuilder}
239 */
240 public AaptPackageCommandBuilder addExistingPackageToBaseIncludeSet( File path )
241 {
242 commands.add( "-I" );
243 commands.add( path.getAbsolutePath() );
244 return this;
245 }
246
247 /**
248 * Specify which configurations to include.
249 *
250 * The default is all configurations. The value of the parameter should be a comma
251 * separated list of configuration values. Locales should be specified
252 * as either a language or language-region pair.
253 *
254 * <p>Some examples:<ul>
255 * <li>en</li>
256 * <li>port,en</li>
257 * <li>port,land,en_US</li></ul>
258 *
259 * <p>If you put the special locale, zz_ZZ on the list, it will perform
260 * pseudolocalization on the default locale, modifying all of the
261 * strings so you can look for strings that missed the
262 * internationalization process.
263 * <p>For example:<ul>
264 * <li>port,land,zz_ZZ </li></ul>
265 *
266 * @param configurations configuration to include in form of {@link String}
267 * @return current instance of {@link AaptCommandBuilder}
268 */
269 public AaptPackageCommandBuilder addConfigurations( String configurations )
270 {
271 if ( StringUtils.isNotBlank( configurations ) )
272 {
273 commands.add( "-c" );
274 commands.add( configurations );
275 }
276 return this;
277 }
278
279 /**
280 * Adds some additional aapt arguments that are not represented as separate parameters
281 * android-maven-plugin configuration.
282 *
283 * @param extraArguments Array of extra arguments to pass to Aapt.
284 * @return current instance of {@link AaptCommandBuilder}
285 */
286 public AaptPackageCommandBuilder addExtraArguments( String[] extraArguments )
287 {
288 if ( extraArguments != null )
289 {
290 commands.addAll( Arrays.asList( extraArguments ) );
291 }
292 return this;
293 }
294
295 /**
296 * Makes output verbose.
297 *
298 * @param isVerbose if true aapt will be verbose, otherwise - no
299 * @return current instance of {@link AaptCommandBuilder}
300 */
301 public AaptPackageCommandBuilder setVerbose( boolean isVerbose )
302 {
303 if ( isVerbose )
304 {
305 commands.add( "-v" );
306 }
307 return this;
308 }
309
310 /**
311 * Generates a text file containing the resource symbols of the R class in the
312 * specified folder.
313 *
314 * @param folderForR folder in which text file will be generated
315 * @return current instance of {@link AaptCommandBuilder}
316 */
317 public AaptPackageCommandBuilder generateRTextFile( File folderForR )
318 {
319 commands.add( "--output-text-symbols" );
320 commands.add( folderForR.getAbsolutePath() );
321 return this;
322 }
323
324 /**
325 * Force overwrite of existing files.
326 *
327 * @return current instance of {@link AaptCommandBuilder}
328 */
329 public AaptPackageCommandBuilder forceOverwriteExistingFiles()
330 {
331 commands.add( "-f" );
332 return this;
333 }
334
335 /**
336 * Disable PNG crunching.
337 *
338 * @return current instance of {@link AaptCommandBuilder}
339 */
340 public AaptPackageCommandBuilder disablePngCrunching()
341 {
342 commands.add( "--no-crunch" );
343 return this;
344 }
345
346 /**
347 * Specify the apk file to output.
348 *
349 * @return current instance of {@link AaptCommandBuilder}
350 */
351 public AaptPackageCommandBuilder setOutputApkFile( File outputFile )
352 {
353 commands.add( "-F" );
354 commands.add( outputFile.getAbsolutePath() );
355 return this;
356 }
357
358 /**
359 * Output Proguard options to a File.
360 *
361 * @return current instance of {@link AaptCommandBuilder}
362 */
363 public AaptPackageCommandBuilder setProguardOptionsOutputFile( File outputFile )
364 {
365 if ( outputFile != null )
366 {
367 final File parentFolder = outputFile.getParentFile();
368 if ( parentFolder != null )
369 {
370 parentFolder.mkdirs();
371 }
372 log.debug( "Adding proguard file : " + outputFile );
373 commands.add( "-G" );
374 commands.add( outputFile.getAbsolutePath() );
375 }
376 return this;
377 }
378
379 /**
380 * Rewrite the manifest so that its package name is the package name given here. <br>
381 * Relative class names (for example .Foo) will be changed to absolute names with the old package
382 * so that the code does not need to change.
383 *
384 * @param manifestPackage new manifest package to apply
385 * @return current instance of {@link AaptPackageCommandBuilder}
386 */
387 public AaptPackageCommandBuilder renameManifestPackage( String manifestPackage )
388 {
389 if ( StringUtils.isNotBlank( manifestPackage ) )
390 {
391 commands.add( "--rename-manifest-package" );
392 commands.add( manifestPackage );
393 }
394 return this;
395 }
396
397 /**
398 * Rewrite the manifest so that all of its instrumentation components target the given package. <br>
399 * Useful when used in conjunction with --rename-manifest-package to fix tests against
400 * a package that has been renamed.
401 *
402 * @param instrumentationPackage new instrumentation target package to apply
403 * @return current instance of {@link AaptPackageCommandBuilder}
404 */
405 public AaptPackageCommandBuilder renameInstrumentationTargetPackage( String instrumentationPackage )
406 {
407 if ( StringUtils.isNotBlank( instrumentationPackage ) )
408 {
409 commands.add( "--rename-instrumentation-target-package" );
410 commands.add( instrumentationPackage );
411 }
412 return this;
413 }
414
415 /**
416 * Inserts android:debuggable="true" into the application node of the
417 * manifest, making the application debuggable even on production devices.
418 *
419 * @return current instance of {@link AaptPackageCommandBuilder}
420 */
421 public AaptPackageCommandBuilder setDebugMode( boolean isDebugMode )
422 {
423 if ( isDebugMode )
424 {
425 log.info( "Generating debug apk." );
426 commands.add( "--debug-mode" );
427 }
428 else
429 {
430 log.info( "Generating release apk." );
431 }
432 return this;
433 }
434 }
435
436 /**
437 * Class that responsible for building aapt commands for dumping information from apk file
438 */
439 public static final class AaptDumpCommandBuilder extends AaptCommandBuilder
440 {
441 public AaptDumpCommandBuilder( Log log )
442 {
443 super( log );
444 commands.add( "dump" );
445 }
446 /**
447 * Print the compiled xmls in the given assets.
448 *
449 * @return current instance of {@link AaptDumpCommandBuilder}
450 */
451 public AaptDumpCommandBuilder xmlTree()
452 {
453 commands.add( "xmltree" );
454 return this;
455 }
456
457 /**
458 * Set path to Apk file where to dump info from.
459 *
460 * @param pathToApk path to apk file for dumping
461 * @return current instance of {@link AaptDumpCommandBuilder}
462 */
463 public AaptDumpCommandBuilder setPathToApk( String pathToApk )
464 {
465 commands.add( pathToApk );
466 return this;
467 }
468
469 /**
470 *
471 * @param assetFile name of the asset file
472 * @return current instance of {@link AaptDumpCommandBuilder}
473 */
474 public AaptDumpCommandBuilder addAssetFile( String assetFile )
475 {
476 commands.add( assetFile );
477 return this;
478 }
479 }
480
481 @Override
482 public String toString()
483 {
484 return commands.toString();
485 }
486
487 /**
488 * Provides unmodifiable list of a aapt commands
489 *
490 * @return unmodifiable {@link List} of {@link String} commands
491 */
492 public List<String> build()
493 {
494 return Collections.unmodifiableList( commands );
495 }
496 }