View Javadoc
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 }