AAPT2: Add option to generate static library

Difference between normal app and static library is that
the R file uses non-final fields, and the extra chunks added
by AAPT2 remain in the final APK.

Change-Id: I61416387ca9bb3c21857ff7cfab5847ac3edf57a
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index dedf8b4..3377f07 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -323,9 +323,17 @@
         Compile,
     };
 
+    enum class PackageType {
+        StandardApp,
+        StaticLibrary,
+    };
+
     // The phase to process.
     Phase phase;
 
+    // The type of package to produce.
+    PackageType packageType = PackageType::StandardApp;
+
     // Details about the app.
     AppInfo appInfo;
 
@@ -800,7 +808,11 @@
 
     // Generate the Java class file.
     if (options.generateJavaClass) {
-        JavaClassGenerator generator(outTable, {});
+        JavaClassGenerator::Options javaOptions;
+        if (options.packageType == AaptOptions::PackageType::StaticLibrary) {
+            javaOptions.useFinal = false;
+        }
+        JavaClassGenerator generator(outTable, javaOptions);
 
         for (const std::u16string& package : linkedPackages) {
             Source outPath = options.generateJavaClass.value();
@@ -852,7 +864,10 @@
 
     // Flatten the resource table.
     TableFlattener::Options flattenerOptions;
-    flattenerOptions.useExtendedChunks = false;
+    if (options.packageType == AaptOptions::PackageType::StaticLibrary) {
+        flattenerOptions.useExtendedChunks = true;
+    }
+
     if (!writeResourceTable(options, outTable, flattenerOptions, &outApk)) {
         return false;
     }
@@ -999,6 +1014,7 @@
         printCommandsAndDie();
     }
 
+    bool isStaticLib = false;
     if (options.phase == AaptOptions::Phase::Compile) {
         flag::requiredFlag("--package", "Android package name",
                 [&options](const StringPiece& arg) {
@@ -1026,6 +1042,8 @@
                 [&options](const StringPiece& arg) {
                     options.generateJavaClass = Source{ arg.toString() };
                 });
+        flag::optionalSwitch("--static-lib", "generate a static Android library", true,
+                             &isStaticLib);
     }
 
     // Common flags for all steps.
@@ -1049,6 +1067,10 @@
         flag::usageAndDie(fullCommand);
     }
 
+    if (isStaticLib) {
+        options.packageType = AaptOptions::PackageType::StaticLibrary;
+    }
+
     // Copy all the remaining arguments.
     for (const std::string& arg : flag::getArgs()) {
         options.input.push_back(Source{ arg });
diff --git a/tools/aapt2/data/lib/Makefile b/tools/aapt2/data/lib/Makefile
index 8f56c54..372c225 100644
--- a/tools/aapt2/data/lib/Makefile
+++ b/tools/aapt2/data/lib/Makefile
@@ -56,7 +56,7 @@
 
 # Link: out/package-unaligned.apk <- out/values-v4.apk out/drawable-v4.apk
 $(PRIVATE_APK_UNALIGNED): $(PRIVATE_INTERMEDIATE_TABLES) $(PRIVATE_LIBS) AndroidManifest.xml
-	$(AAPT) link --manifest AndroidManifest.xml $(addprefix -I ,$(PRIVATE_LIBS)) --java $(LOCAL_GEN) -o $@ $(PRIVATE_INTERMEDIATE_TABLES)
+	$(AAPT) link --manifest AndroidManifest.xml $(addprefix -I ,$(PRIVATE_LIBS)) --java $(LOCAL_GEN) -o $@ $(PRIVATE_INTERMEDIATE_TABLES) --static-lib
 
 # R.java: gen/com/android/app/R.java <- out/resources.arsc
 # No action since R.java is generated when out/resources.arsc is.