Add Api level annotations support for Metalava.

Test: m -j docs with Api level annotations enabled.
Bug: b/78245848

Change-Id: Ife93899cdcf5b54ee0c75003c295aa4b917d3dba
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 3123baf..ad2a580 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -321,6 +321,10 @@
 	// the generated removed Dex API filename by Doclava.
 	Removed_dex_api_filename *string
 
+	// mapping of dex signatures to source file and line number. This is a temporary property and
+	// will be deleted; you probably shouldn't be using it.
+	Dex_mapping_filename *string
+
 	// the generated exact API filename by Doclava.
 	Exact_api_filename *string
 
@@ -341,6 +345,16 @@
 
 	// if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
 	Create_doc_stubs *bool
+
+	// is set to true, Metalava will allow framework SDK to contain API levels annotations.
+	Api_levels_annotations_enabled *bool
+
+	// the dirs which Metalava extracts API levels annotations from.
+	Api_levels_annotations_dirs []string
+
+	// if set to true, collect the values used by the Dev tools and
+	// write them in files packaged with the SDK. Defaults to false.
+	Write_sdk_values *bool
 }
 
 //
@@ -357,9 +371,9 @@
 	doclavaDocsFlags  string
 	postDoclavaCmds   string
 
-	metalavaStubsFlags       string
-	metalavaAnnotationsFlags string
-	metalavaJavadocFlags     string
+	metalavaStubsFlags                string
+	metalavaAnnotationsFlags          string
+	metalavaApiLevelsAnnotationsFlags string
 
 	metalavaDokkaFlags string
 }
@@ -643,7 +657,7 @@
 	j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
 	j.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
 
-	if j.properties.Local_sourcepaths == nil {
+	if j.properties.Local_sourcepaths == nil && len(j.srcFiles) > 0 {
 		j.properties.Local_sourcepaths = append(j.properties.Local_sourcepaths, ".")
 	}
 	j.sourcepaths = android.PathsForModuleSrc(ctx, j.properties.Local_sourcepaths)
@@ -831,7 +845,16 @@
 	dokkaClasspath = append(dokkaClasspath, deps.classpath...)
 	flags.dokkaClasspathArgs = dokkaClasspath.FormJavaClassPath("-classpath")
 
-	flags.sourcepathArgs = "-sourcepath " + strings.Join(d.Javadoc.sourcepaths.Strings(), ":")
+	// TODO(nanzhang): Remove this if- statement once we finish migration for all Doclava
+	// based stubs generation.
+	// In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar
+	// dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out
+	// the correct package name base path.
+	if len(d.Javadoc.properties.Local_sourcepaths) > 0 {
+		flags.sourcepathArgs = "-sourcepath " + strings.Join(d.Javadoc.sourcepaths.Strings(), ":")
+	} else {
+		flags.sourcepathArgs = "-sourcepath " + android.PathForModuleOut(ctx, "srcjars").String()
+	}
 
 	return flags, nil
 }
@@ -1173,6 +1196,7 @@
 	privateDexApiFile android.WritablePath
 	removedApiFile    android.WritablePath
 	removedDexApiFile android.WritablePath
+	apiMappingFile    android.WritablePath
 	exactApiFile      android.WritablePath
 
 	checkCurrentApiTimestamp      android.WritablePath
@@ -1180,6 +1204,7 @@
 	checkLastReleasedApiTimestamp android.WritablePath
 
 	annotationsZip android.WritablePath
+	apiVersionsXml android.WritablePath
 
 	apiFilePath android.Path
 }
@@ -1230,6 +1255,12 @@
 			ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
 		}
 	}
+
+	if len(d.properties.Api_levels_annotations_dirs) != 0 {
+		for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
+			ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
+		}
+	}
 }
 
 func (d *Droidstubs) initBuilderFlags(ctx android.ModuleContext, implicits *android.Paths,
@@ -1302,6 +1333,16 @@
 		*implicitOutputs = append(*implicitOutputs, d.exactApiFile)
 	}
 
+	if String(d.properties.Dex_mapping_filename) != "" {
+		d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
+		metalavaFlags = metalavaFlags + " --dex-api-mapping " + d.apiMappingFile.String()
+		*implicitOutputs = append(*implicitOutputs, d.apiMappingFile)
+	}
+
+	if Bool(d.properties.Write_sdk_values) {
+		metalavaFlags = metalavaFlags + " --sdk-values " + android.PathForModuleOut(ctx, "out").String()
+	}
+
 	if Bool(d.properties.Create_doc_stubs) {
 		metalavaFlags += " --doc-stubs " + android.PathForModuleOut(ctx, "stubsDir").String()
 	} else {
@@ -1331,7 +1372,7 @@
 		flags += " --extract-annotations " + d.annotationsZip.String()
 
 		if len(d.properties.Merge_annotations_dirs) == 0 {
-			ctx.PropertyErrorf("metalava_merge_annotations_dirs",
+			ctx.PropertyErrorf("merge_annotations_dirs",
 				"has to be non-empty if annotations was enabled!")
 		}
 		ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
@@ -1339,7 +1380,7 @@
 				*implicits = append(*implicits, t.deps...)
 				flags += " --merge-annotations " + t.dir.String()
 			} else {
-				ctx.PropertyErrorf("metalava_merge_annotations_dirs",
+				ctx.PropertyErrorf("merge_annotations_dirs",
 					"module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
 			}
 		})
@@ -1350,9 +1391,47 @@
 	return flags
 }
 
+func (d *Droidstubs) collectAPILevelsAnnotationsFlags(ctx android.ModuleContext,
+	implicits *android.Paths, implicitOutputs *android.WritablePaths) string {
+	var flags string
+	if Bool(d.properties.Api_levels_annotations_enabled) {
+		d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml")
+		*implicitOutputs = append(*implicitOutputs, d.apiVersionsXml)
+
+		if len(d.properties.Api_levels_annotations_dirs) == 0 {
+			ctx.PropertyErrorf("api_levels_annotations_dirs",
+				"has to be non-empty if api levels annotations was enabled!")
+		}
+
+		flags = " --generate-api-levels " + d.apiVersionsXml.String() + " --apply-api-levels " +
+			d.apiVersionsXml.String() + " --current-version " + ctx.Config().PlatformSdkVersion() +
+			" --current-codename " + ctx.Config().PlatformSdkCodename() + " "
+
+		ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
+			if t, ok := m.(*ExportedDroiddocDir); ok {
+				var androidJars android.Paths
+				for _, dep := range t.deps {
+					if strings.HasSuffix(dep.String(), "android.jar") {
+						androidJars = append(androidJars, dep)
+					}
+				}
+				*implicits = append(*implicits, androidJars...)
+				flags += " --android-jar-pattern " + t.dir.String() + "/%/android.jar "
+			} else {
+				ctx.PropertyErrorf("api_levels_annotations_dirs",
+					"module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
+			}
+		})
+
+	}
+
+	return flags
+}
+
 func (d *Droidstubs) transformMetalava(ctx android.ModuleContext, implicits android.Paths,
 	implicitOutputs android.WritablePaths, javaVersion,
 	bootclasspathArgs, classpathArgs, sourcepathArgs, opts string) {
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:            metalava,
 		Description:     "Metalava",
@@ -1401,9 +1480,6 @@
 func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	deps := d.Javadoc.collectDeps(ctx)
 
-	// always set installable to false for droidstubs, since droidstubs doesn't create doc.zip file.
-	*d.Javadoc.properties.Installable = false
-
 	javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d))
 
 	var implicits android.Paths
@@ -1423,6 +1499,7 @@
 
 	flags.metalavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs)
 	flags.metalavaAnnotationsFlags = d.collectAnnotationsFlags(ctx, &implicits, &implicitOutputs)
+	flags.metalavaApiLevelsAnnotationsFlags = d.collectAPILevelsAnnotationsFlags(ctx, &implicits, &implicitOutputs)
 	if strings.Contains(d.Javadoc.args, "--generate-documentation") {
 		// Currently Metalava have the ability to invoke Javadoc in a seperate process.
 		// Pass "-nodocs" to suppress the Javadoc invocation when Metalava receives
@@ -1431,7 +1508,8 @@
 	}
 	d.transformMetalava(ctx, implicits, implicitOutputs, javaVersion,
 		flags.bootClasspathArgs, flags.classpathArgs, flags.sourcepathArgs,
-		flags.metalavaStubsFlags+flags.metalavaAnnotationsFlags+" "+d.Javadoc.args)
+		flags.metalavaStubsFlags+flags.metalavaAnnotationsFlags+
+			flags.metalavaApiLevelsAnnotationsFlags+" "+d.Javadoc.args)
 
 	if apiCheckEnabled(d.properties.Check_api.Current, "current") &&
 		!ctx.Config().IsPdkBuild() {
@@ -1489,6 +1567,7 @@
 //
 var droiddocTemplateTag = dependencyTag{name: "droiddoc-template"}
 var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
+var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
 
 type ExportedDroiddocDirProperties struct {
 	// path to the directory containing Droiddoc related files.