Merge pi-qpr1-release PQ1A.181105.017.A1 to pi-platform-release

Change-Id: Idaf2f036566669baa1500525d3beae2efdacd531
diff --git a/manual/master.txt b/manual/master.txt
new file mode 100644
index 0000000..b239c51
--- /dev/null
+++ b/manual/master.txt
@@ -0,0 +1,142 @@
+// APIs annotated in master that haven't been annotated in pi-dev
+package android.content.pm {
+  public abstract class PackageManager {
+    method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setApplicationEnabledSetting(String, int, int);
+    method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
+  }
+}
+package android.graphics {
+  public class Path {
+    method @NonNull public android.graphics.Path.FillType getFillType();
+  }
+  public final class Rect implements android.os.Parcelable {
+    method @NonNull public String flattenToString();
+    method @NonNull public String toShortString();
+    method @Nullable public static android.graphics.Rect unflattenFromString(@Nullable String);
+  }
+  public class RectF implements android.os.Parcelable {
+    method @NonNull public String toShortString();
+  }
+}
+package android.os {
+  public class DropBoxManager {
+    method @RequiresPermission(allOf={android.Manifest.permission.READ_LOGS, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.DropBoxManager.Entry getNextEntry(String, long);
+  }
+  public final class Parcel {
+    method @Nullable public android.os.IBinder[] createBinderArray();
+    method @Nullable public java.util.ArrayList<android.os.IBinder> createBinderArrayList();
+    method @Nullable public boolean[] createBooleanArray();
+    method @Nullable public byte[] createByteArray();
+    method @Nullable public char[] createCharArray();
+    method @Nullable public double[] createDoubleArray();
+    method @Nullable public float[] createFloatArray();
+    method @Nullable public int[] createIntArray();
+    method @Nullable public long[] createLongArray();
+    method @Nullable public String[] createStringArray();
+    method @Nullable public java.util.ArrayList<java.lang.String> createStringArrayList();
+    method @Nullable public <T> T[] createTypedArray(@NonNull android.os.Parcelable.Creator<T>);
+    method @Nullable public <T> java.util.ArrayList<T> createTypedArrayList(@NonNull android.os.Parcelable.Creator<T>);
+    method @NonNull public static android.os.Parcel obtain();
+    method @Nullable public Object[] readArray(@Nullable ClassLoader);
+    method @Nullable public java.util.ArrayList readArrayList(@Nullable ClassLoader);
+    method @Nullable public android.os.Bundle readBundle();
+    method @Nullable public android.os.Bundle readBundle(@Nullable ClassLoader);
+    method @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader);
+    method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
+    method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
+    method @Nullable public android.os.PersistableBundle readPersistableBundle();
+    method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
+    method @Nullable public java.io.Serializable readSerializable();
+    method @NonNull public android.util.Size readSize();
+    method @NonNull public android.util.SizeF readSizeF();
+    method @Nullable public android.util.SparseArray readSparseArray(@Nullable ClassLoader);
+    method @Nullable public android.util.SparseBooleanArray readSparseBooleanArray();
+    method @Nullable public String readString();
+    method @Nullable public <T> T readTypedObject(@NonNull android.os.Parcelable.Creator<T>);
+    method @Nullable public Object readValue(@Nullable ClassLoader);
+  }
+}
+package android.util {
+  public final class Log {
+    method @NonNull public static String getStackTraceString(@Nullable Throwable);
+  }
+}
+package android.view {
+  public abstract class Window {
+    method @NonNull public abstract android.view.View getDecorView();
+  }
+}
+package java.lang {
+  public final class Character implements java.lang.Comparable<java.lang.Character> java.io.Serializable {
+    method @NonNull public static char @NonNull [] toChars(int);
+  }
+  public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
+    method @Nullable public T cast(@Nullable Object);
+    method @NonNull public static Class<?> forName(@NonNull String) throws java.lang.ClassNotFoundException;
+    method @NonNull public static Class<?> forName(@NonNull String, boolean, @Nullable ClassLoader) throws java.lang.ClassNotFoundException;
+    method @Nullable public <A extends java.lang.annotation.Annotation> A getAnnotation(@NonNull Class<A>);
+    method @NonNull public java.lang.annotation.Annotation @NonNull [] getAnnotations();
+    method @NonNull public <A extends java.lang.annotation.Annotation> A @NonNull [] getAnnotationsByType(@NonNull Class<A>);
+    method @Nullable public String getCanonicalName();
+    method @Nullable public ClassLoader getClassLoader();
+    method @NonNull public Class<?> @NonNull [] getClasses();
+    method @Nullable public Class<?> getComponentType();
+    method @NonNull public java.lang.reflect.Constructor<?> @NonNull [] getConstructors() throws java.lang.SecurityException;
+    method @Nullable public native <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(@NonNull Class<A>);
+    method @NonNull public native java.lang.annotation.Annotation @NonNull [] getDeclaredAnnotations();
+    method @NonNull public native Class<?> @NonNull [] getDeclaredClasses();
+    method @NonNull public java.lang.reflect.Constructor<?> @NonNull [] getDeclaredConstructors() throws java.lang.SecurityException;
+    method @NonNull public native java.lang.reflect.Field getDeclaredField(@NonNull String) throws java.lang.NoSuchFieldException;
+    method @NonNull public native java.lang.reflect.Field @NonNull [] getDeclaredFields();
+    method @NonNull public java.lang.reflect.Method @NonNull [] getDeclaredMethods() throws java.lang.SecurityException;
+    method @Nullable public native Class<?> getDeclaringClass();
+    method @Nullable public native Class<?> getEnclosingClass();
+    method @Nullable public java.lang.reflect.Constructor<?> getEnclosingConstructor();
+    method @Nullable public java.lang.reflect.Method getEnclosingMethod();
+    method @NonNull public T @Nullable [] getEnumConstants();
+    method @NonNull public java.lang.reflect.Field getField(@NonNull String) throws java.lang.NoSuchFieldException;
+    method @NonNull public java.lang.reflect.Field @NonNull [] getFields() throws java.lang.SecurityException;
+    method @NonNull public java.lang.reflect.Type @NonNull [] getGenericInterfaces();
+    method @Nullable public java.lang.reflect.Type getGenericSuperclass();
+    method @NonNull public Class<?> @NonNull [] getInterfaces();
+    method @NonNull public java.lang.reflect.Method @NonNull [] getMethods() throws java.lang.SecurityException;
+    method @NonNull public String getName();
+    method @Nullable public Package getPackage();
+    method @Nullable public java.security.ProtectionDomain getProtectionDomain();
+    method @Nullable public java.net.URL getResource(@NonNull String);
+    method @Nullable public java.io.InputStream getResourceAsStream(@NonNull String);
+    method @NonNull public Object @Nullable [] getSigners();
+    method @NonNull public String getSimpleName();
+    method @Nullable public Class<? super T> getSuperclass();
+    method @NonNull public synchronized java.lang.reflect.TypeVariable<java.lang.@NonNull Class<T>> @NonNull [] getTypeParameters();
+    method @NonNull public native T newInstance() throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method @NonNull public String toGenericString();
+  }
+  public class Object {
+    method @NonNull public final Class<?> getClass();
+    method @NonNull public String toString();
+  }
+  public final class System {
+    method @NonNull public static java.util.Map<java.lang.String,java.lang.String> getenv();
+  }
+  public class ThreadLocal<T> {
+    method @NonNull public static <S> ThreadLocal<S> withInitial(@NonNull java.util.function.Supplier<? extends S>);
+  }
+}
+package java.util {
+  public class ArrayList<E> extends java.util.AbstractList<E> implements java.lang.Cloneable java.util.List<E> java.util.RandomAccess java.io.Serializable {
+    method @NonNull public Object clone();
+  }
+  public class HashMap<K, V> extends java.util.AbstractMap<K,V> implements java.lang.Cloneable java.util.Map<K,V> java.io.Serializable {
+    method @NonNull public Object clone();
+    method @NonNull public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
+  }
+  public interface Map<K, V> {
+    method @Nullable public V get(@Nullable Object);
+    method @Nullable public default V getOrDefault(@Nullable Object, @Nullable V);
+    method @Nullable public V put(K, V);
+    method @Nullable public default V putIfAbsent(K, V);
+    method @Nullable public V remove(@Nullable Object);
+    method @Nullable public default V replace(K, V);
+  }
+}
diff --git a/src/main/java/com/android/tools/metalava/AnnotationsDiffer.kt b/src/main/java/com/android/tools/metalava/AnnotationsDiffer.kt
index 8147ef8..0bd7d00 100644
--- a/src/main/java/com/android/tools/metalava/AnnotationsDiffer.kt
+++ b/src/main/java/com/android/tools/metalava/AnnotationsDiffer.kt
@@ -19,6 +19,7 @@
 import com.android.tools.metalava.doclava1.ApiPredicate
 import com.android.tools.metalava.doclava1.Errors
 import com.android.tools.metalava.doclava1.FilterPredicate
+import com.android.tools.metalava.doclava1.TextCodebase
 import com.android.tools.metalava.model.Codebase
 import com.android.tools.metalava.model.Item
 import java.io.File
@@ -57,7 +58,7 @@
  * file.
  */
 class AnnotationsDiffer(
-    superset: Codebase,
+    private val superset: Codebase,
     private val codebase: Codebase
 ) {
     private val relevant = HashSet<Item>(1000)
@@ -100,10 +101,17 @@
                 }
             }
         }
-        CodebaseComparator().compare(visitor, superset, codebase, ApiPredicate(codebase))
+        val filter =
+            if (codebase.supportsDocumentation()) {
+                ApiPredicate(codebase)
+            } else {
+                Predicate<Item> { true }
+            }
+        CodebaseComparator().compare(visitor, superset, codebase, filter)
     }
 
     fun writeDiffSignature(apiFile: File) {
+        val codebase = superset
         val apiFilter = FilterPredicate(ApiPredicate(codebase))
         val apiReference = ApiPredicate(codebase, ignoreShown = true)
         val apiEmit = apiFilter.and(predicate)
@@ -113,13 +121,13 @@
             val stringWriter = StringWriter()
             val writer = PrintWriter(stringWriter)
             writer.use { printWriter ->
-                val preFiltered = codebase.original != null
+                val preFiltered = codebase.original != null || codebase is TextCodebase
                 val apiWriter = SignatureWriter(printWriter, apiEmit, apiReference, preFiltered)
                 codebase.accept(apiWriter)
             }
 
             // Clean up blank lines
-            var prev: Char = ' '
+            var prev = ' '
             val cleanedUp = stringWriter.toString().filter {
                 if (it == '\n' && prev == '\n')
                     false
diff --git a/src/main/java/com/android/tools/metalava/AnnotationsMerger.kt b/src/main/java/com/android/tools/metalava/AnnotationsMerger.kt
index 11ff5d5..c32c7df 100644
--- a/src/main/java/com/android/tools/metalava/AnnotationsMerger.kt
+++ b/src/main/java/com/android/tools/metalava/AnnotationsMerger.kt
@@ -57,6 +57,7 @@
 import com.android.tools.metalava.model.Item
 import com.android.tools.metalava.model.MethodItem
 import com.android.tools.metalava.model.PackageItem
+import com.android.tools.metalava.model.SUPPORT_TYPE_USE_ANNOTATIONS
 import com.android.tools.metalava.model.psi.PsiAnnotationItem
 import com.android.tools.metalava.model.visitors.ApiVisitor
 import com.android.utils.XmlUtils
@@ -267,7 +268,7 @@
                     null
                 }
                 curr = parameterItem
-            } else if (line.startsWith("type: ")) {
+            } else if (line.startsWith("type: ") && SUPPORT_TYPE_USE_ANNOTATIONS) {
                 val typeAnnotation = line.substring("type: ".length)
                 if (curr != null) {
                     mergeJaifAnnotation(path, curr, typeAnnotation)
@@ -277,7 +278,7 @@
                 if (methodItem != null) {
                     mergeJaifAnnotation(path, methodItem, annotation)
                 }
-            } else if (line.startsWith("inner-type")) {
+            } else if (line.startsWith("inner-type") && SUPPORT_TYPE_USE_ANNOTATIONS) {
                 warning("$path: Skipping inner-type annotations for now ($line)")
             } else if (line.startsWith("int ")) {
                 // warning("Skipping int attribute definitions for annotations now ($line)")
diff --git a/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt b/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt
index 6cf8127..25f1f75 100644
--- a/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt
+++ b/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt
@@ -803,6 +803,22 @@
                 // TODO: Check opposite (doc tag but no annotation)
                 // TODO: Other checks
             }
+
+            override fun visitMethod(method: MethodItem) {
+                // Make sure we don't annotate findViewById & getSystemService as @Nullable.
+                // See for example 68914170.
+                val name = method.name()
+                if ((name == "findViewById" || name == "getSystemService") && method.parameters().size == 1 &&
+                    method.modifiers.hasNullnessInfo()
+                ) {
+                    // In master we generate a warning here; in this branch we won't go in
+                    // and remove the assertions
+                    val annotation = method.modifiers.annotations().find { it.isNullable() }
+                    annotation?.let {
+                        method.mutableModifiers().removeAnnotation(it)
+                    }
+                }
+            }
         })
     }
 
diff --git a/src/main/java/com/android/tools/metalava/Compatibility.kt b/src/main/java/com/android/tools/metalava/Compatibility.kt
index 5c21e38..536f5f5 100644
--- a/src/main/java/com/android/tools/metalava/Compatibility.kt
+++ b/src/main/java/com/android/tools/metalava/Compatibility.kt
@@ -45,6 +45,10 @@
     /** Add in explicit `valueOf` and `values` methods into annotation classes  */
     var defaultAnnotationMethods: Boolean = compat
 
+    /** Whether signature files should contain annotation default values (as is already
+     * done for field default values) */
+    var includeAnnotationDefaults: Boolean = !compat
+
     /** In signature files, refer to enums as "class" instead of "enum" */
     var classForEnums: Boolean = compat
 
diff --git a/src/main/java/com/android/tools/metalava/DocAnalyzer.kt b/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
index 2c91eaa..f040027 100644
--- a/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
+++ b/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
@@ -1,6 +1,7 @@
 package com.android.tools.metalava
 
 import com.android.sdklib.SdkVersionInfo
+import com.android.sdklib.repository.AndroidSdkHandler
 import com.android.tools.lint.LintCliClient
 import com.android.tools.lint.checks.ApiLookup
 import com.android.tools.lint.helpers.DefaultJavaEvaluator
@@ -326,7 +327,18 @@
 
                         val field = value.resolve()
                         if (field is FieldItem)
-                            sb.append("{@link ${field.containingClass().qualifiedName()}#${field.name()}}")
+                            if (filterReference.test(field)) {
+                                sb.append("{@link ${field.containingClass().qualifiedName()}#${field.name()}}")
+                            } else {
+                                // Typdef annotation references field which isn't part of the API: don't
+                                // try to link to it.
+                                reporter.report(
+                                    Errors.MISSING_TYPEDEF_CONSTANT, item,
+                                    "Typedef references constant which isn't part of the API, skipping in documentation: " +
+                                        "${field.containingClass().qualifiedName()}#${field.name()}"
+                                )
+                                sb.append(field.containingClass().qualifiedName() + "." + field.name())
+                            }
                         else {
                             sb.append(value.toSource())
                         }
@@ -500,6 +512,10 @@
                 return super.findResource(relativePath)
             }
 
+            override fun getSdk(): AndroidSdkHandler? {
+                return null
+            }
+
             override fun getCacheDir(name: String?, create: Boolean): File? {
                 val dir = File(System.getProperty("java.io.tmpdir"))
                 if (create) {
diff --git a/src/main/java/com/android/tools/metalava/Driver.kt b/src/main/java/com/android/tools/metalava/Driver.kt
index c538126..ed27efb 100644
--- a/src/main/java/com/android/tools/metalava/Driver.kt
+++ b/src/main/java/com/android/tools/metalava/Driver.kt
@@ -144,6 +144,20 @@
 private fun processFlags() {
     val stopwatch = Stopwatch.createStarted()
 
+    // --copy-annotations?
+    val privateAnnotationsSource = options.privateAnnotationsSource
+    val privateAnnotationsTarget = options.privateAnnotationsTarget
+    if (privateAnnotationsSource != null && privateAnnotationsTarget != null) {
+        val rewrite = RewriteAnnotations()
+        // Support pointing to both stub-annotations and stub-annotations/src/main/java
+        val src = File(privateAnnotationsSource, "src${File.separator}main${File.separator}java")
+        val source = if (src.isDirectory) src else privateAnnotationsSource
+        rewrite.modifyAnnotationSources(source, privateAnnotationsTarget)
+    }
+
+    // --rewrite-annotations?
+    options.rewriteAnnotations?.let { RewriteAnnotations().rewriteAnnotations(it) }
+
     val codebase =
         if (options.sources.size == 1 && options.sources[0].path.endsWith(SdkConstants.DOT_TXT)) {
             loadFromSignatureFiles(
@@ -154,8 +168,10 @@
             loadFromJarFile(options.apiJar!!)
         } else if (options.sources.size == 1 && options.sources[0].path.endsWith(SdkConstants.DOT_JAR)) {
             loadFromJarFile(options.sources[0])
-        } else {
+        } else if (options.sources.isNotEmpty() || options.sourcePath.isNotEmpty()) {
             loadFromSources()
+        } else {
+            return
         }
     options.manifest?.let { codebase.manifest = it }
 
@@ -323,7 +339,18 @@
             it, codebase, docStubs = false,
             writeStubList = options.stubsSourceList != null
         )
+
+        val stubAnnotations = options.copyStubAnnotationsFrom
+        if (stubAnnotations != null) {
+            // Support pointing to both stub-annotations and stub-annotations/src/main/java
+            val src = File(stubAnnotations, "src${File.separator}main${File.separator}java")
+            val source = if (src.isDirectory) src else stubAnnotations
+            source.listFiles()?.forEach { file ->
+                RewriteAnnotations().copyAnnotations(file, File(it, file.name))
+            }
+        }
     }
+
     if (options.docStubsDir == null && options.stubsDir == null) {
         val writeStubsFile: (File) -> Unit = { file ->
             val root = File("").absoluteFile
@@ -375,8 +402,8 @@
     if (args.isNotEmpty()) {
         if (!options.quiet) {
             options.stdout.println(
-                "Invoking external documentation tool ${args[0]} with arguments ${
-                args.slice(1 until args.size).joinToString { it }}"
+                "Invoking external documentation tool ${args[0]} with arguments\n\"${
+                args.slice(1 until args.size).joinToString(separator = "\",\n\"") { it }}\""
             )
             options.stdout.flush()
         }
diff --git a/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt b/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt
index dd3fb67..e065f58 100644
--- a/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt
+++ b/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt
@@ -30,6 +30,8 @@
 import com.android.tools.metalava.model.MethodItem
 import com.android.tools.metalava.model.PackageItem
 import com.android.tools.metalava.model.ParameterItem
+import com.android.tools.metalava.model.canonicalizeFloatingPointString
+import com.android.tools.metalava.model.javaEscapeString
 import com.android.tools.metalava.model.psi.PsiAnnotationItem
 import com.android.tools.metalava.model.psi.PsiClassItem
 import com.android.tools.metalava.model.visitors.ApiVisitor
@@ -37,10 +39,16 @@
 import com.google.common.base.Charsets
 import com.google.common.xml.XmlEscapers
 import com.intellij.psi.PsiAnnotation
+import com.intellij.psi.PsiAnnotationMemberValue
+import com.intellij.psi.PsiArrayInitializerMemberValue
 import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiClassObjectAccessExpression
 import com.intellij.psi.PsiElement
 import com.intellij.psi.PsiField
+import com.intellij.psi.PsiLiteral
 import com.intellij.psi.PsiNameValuePair
+import com.intellij.psi.PsiReference
+import com.intellij.psi.PsiTypeCastExpression
 import org.jetbrains.uast.UAnnotation
 import org.jetbrains.uast.UBinaryExpressionWithType
 import org.jetbrains.uast.UCallExpression
@@ -101,25 +109,35 @@
 
                     val pairs = packageToAnnotationPairs[pkg] ?: continue
 
+                    // Ensure stable output
+                    if (pairs.size > 1) {
+                        pairs.sortBy { it.first.getExternalAnnotationSignature() }
+                    }
+
                     StringPrintWriter.create().use { writer ->
                         writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>")
 
+                        var open = false
                         var prev: Item? = null
                         for ((item, annotation) in pairs) {
-                            // that we only do analysis for IntDef/LongDef
-                            assert(item != prev) // should be only one annotation per element now
+                            if (item != prev) {
+                                if (open) {
+                                    writer.print("  </item>")
+                                    writer.println()
+                                }
+                                writer.print("  <item name=\"")
+                                writer.print(item.getExternalAnnotationSignature())
+                                writer.println("\">")
+                                open = true
+                            }
                             prev = item
 
-                            writer.print("  <item name=\"")
-                            writer.print(item.getExternalAnnotationSignature())
-                            writer.println("\">")
-
                             writeAnnotation(writer, item, annotation)
-
+                        }
+                        if (open) {
                             writer.print("  </item>")
                             writer.println()
                         }
-
                         writer.println("</root>\n")
                         writer.close()
                         val bytes = writer.contents.toByteArray(Charsets.UTF_8)
@@ -131,15 +149,7 @@
         }
     }
 
-    /** For a given item, extract the relevant annotations for that item.
-     *
-     * Currently, we're only extracting typedef annotations. Everything else
-     * has class retention.
-     */
-    private fun checkItem(item: Item) {
-        // field, method or parameter
-        val typedef = findTypeDef(item) ?: return
-
+    private fun addItem(item: Item, annotation: AnnotationHolder) {
         val pkg = when (item) {
             is MemberItem -> item.containingClass().containingPackage()
             is ParameterItem -> item.containingMethod().containingClass().containingPackage()
@@ -152,7 +162,7 @@
             packageToAnnotationPairs[pkg] = new
             new
         }
-        list.add(Pair(item, typedef))
+        list.add(Pair(item, annotation))
     }
 
     override fun visitField(field: FieldItem) {
@@ -167,7 +177,8 @@
         checkItem(parameter)
     }
 
-    private fun findTypeDef(item: Item): AnnotationHolder? {
+    /** For a given item, extract the relevant annotations for that item */
+    private fun checkItem(item: Item) {
         for (annotation in item.modifiers.annotations()) {
             val qualifiedName = annotation.qualifiedName() ?: continue
             if (qualifiedName.startsWith(JAVA_LANG_PREFIX) ||
@@ -177,7 +188,11 @@
             ) {
                 if (annotation.isTypeDefAnnotation()) {
                     // Imported typedef
-                    return AnnotationHolder(null, annotation, null)
+                    addItem(item, AnnotationHolder(null, annotation, null))
+                } else if (annotation.isSignificantInStubs() && !annotation.hasClassRetention() &&
+                    !options.includeSourceRetentionAnnotations
+                ) {
+                    addItem(item, AnnotationHolder(null, annotation, null))
                 }
 
                 continue
@@ -188,7 +203,8 @@
             if (typeDefClass.isAnnotationType()) {
                 val cached = classToAnnotationHolder[className]
                 if (cached != null) {
-                    return cached
+                    addItem(item, cached)
+                    continue
                 }
 
                 val typeDefAnnotation = typeDefClass.modifiers.annotations().firstOrNull {
@@ -220,12 +236,12 @@
                             )
                         )
                         classToAnnotationHolder[className] = result
-                        return result
+                        addItem(item, result)
+                        continue
                     }
                 }
             }
         }
-        return null
     }
 
     private fun hasSourceRetention(annotationClass: ClassItem): Boolean {
@@ -374,112 +390,115 @@
         annotationHolder: AnnotationHolder
     ) {
         val annotationItem = annotationHolder.annotationItem
+        val uAnnotation = annotationHolder.uAnnotation
+            ?: if (annotationItem is PsiAnnotationItem) {
+                // Imported annotation
+                JavaUAnnotation.wrap(annotationItem.psiAnnotation)
+            } else {
+                return
+            }
         val qualifiedName = annotationItem.qualifiedName()
 
         writer.mark()
         writer.print("    <annotation name=\"")
         writer.print(qualifiedName)
 
+        var attributes = uAnnotation.attributeValues
+        if (attributes.isEmpty()) {
+            writer.print("\"/>")
+            writer.println()
+            return
+        }
+
         writer.print("\">")
         writer.println()
 
-        val uAnnotation = annotationHolder.uAnnotation
-            ?: if (annotationItem is PsiAnnotationItem) {
-                // Imported annotation
-                JavaUAnnotation.wrap(annotationItem.psiAnnotation)
-            } else {
-                null
-            }
-        if (uAnnotation != null) {
-            var attributes = uAnnotation.attributeValues
+        // noinspection PointlessBooleanExpression,ConstantConditions
+        if (attributes.size > 1 && sortAnnotations) {
+            // Ensure mutable
+            attributes = ArrayList(attributes)
 
-            // noinspection PointlessBooleanExpression,ConstantConditions
-            if (attributes.size > 1 && sortAnnotations) {
-                // Ensure mutable
-                attributes = ArrayList(attributes)
+            // Ensure that the value attribute is written first
+            attributes.sortedWith(object : Comparator<UNamedExpression> {
+                private fun getName(pair: UNamedExpression): String {
+                    val name = pair.name
+                    return name ?: SdkConstants.ATTR_VALUE
+                }
 
-                // Ensure that the value attribute is written first
-                attributes.sortedWith(object : Comparator<UNamedExpression> {
-                    private fun getName(pair: UNamedExpression): String {
-                        val name = pair.name
-                        return name ?: SdkConstants.ATTR_VALUE
-                    }
+                private fun rank(pair: UNamedExpression): Int {
+                    return if (SdkConstants.ATTR_VALUE == getName(pair)) -1 else 0
+                }
 
-                    private fun rank(pair: UNamedExpression): Int {
-                        return if (SdkConstants.ATTR_VALUE == getName(pair)) -1 else 0
-                    }
+                override fun compare(o1: UNamedExpression, o2: UNamedExpression): Int {
+                    val r1 = rank(o1)
+                    val r2 = rank(o2)
+                    val delta = r1 - r2
+                    return if (delta != 0) {
+                        delta
+                    } else getName(o1).compareTo(getName(o2))
+                }
+            })
+        }
 
-                    override fun compare(o1: UNamedExpression, o2: UNamedExpression): Int {
-                        val r1 = rank(o1)
-                        val r2 = rank(o2)
-                        val delta = r1 - r2
-                        return if (delta != 0) {
-                            delta
-                        } else getName(o1).compareTo(getName(o2))
-                    }
-                })
-            }
-
-            if (attributes.size == 1 && Extractor.REQUIRES_PERMISSION.isPrefix(qualifiedName, true)) {
-                val expression = attributes[0].expression
-                if (expression is UAnnotation) {
-                    // The external annotations format does not allow for nested/complex annotations.
-                    // However, these special annotations (@RequiresPermission.Read,
-                    // @RequiresPermission.Write, etc) are known to only be simple containers with a
-                    // single permission child, so instead we "inline" the content:
-                    //  @Read(@RequiresPermission(allOf={P1,P2},conditional=true)
-                    //     =>
-                    //      @RequiresPermission.Read(allOf({P1,P2},conditional=true)
-                    // That's setting attributes that don't actually exist on the container permission,
-                    // but we'll counteract that on the read-annotations side.
-                    val annotation = expression as UAnnotation
+        if (attributes.size == 1 && Extractor.REQUIRES_PERMISSION.isPrefix(qualifiedName, true)) {
+            val expression = attributes[0].expression
+            if (expression is UAnnotation) {
+                // The external annotations format does not allow for nested/complex annotations.
+                // However, these special annotations (@RequiresPermission.Read,
+                // @RequiresPermission.Write, etc) are known to only be simple containers with a
+                // single permission child, so instead we "inline" the content:
+                //  @Read(@RequiresPermission(allOf={P1,P2},conditional=true)
+                //     =>
+                //      @RequiresPermission.Read(allOf({P1,P2},conditional=true)
+                // That's setting attributes that don't actually exist on the container permission,
+                // but we'll counteract that on the read-annotations side.
+                val annotation = expression as UAnnotation
+                attributes = annotation.attributeValues
+            } else if (expression is JavaUAnnotationCallExpression) {
+                val annotation = expression.uAnnotation
+                attributes = annotation.attributeValues
+            } else if (expression is UastEmptyExpression && attributes[0].sourcePsi is PsiNameValuePair) {
+                val memberValue = (attributes[0].sourcePsi as PsiNameValuePair).value
+                if (memberValue is PsiAnnotation) {
+                    val annotation = JavaUAnnotation.wrap(memberValue)
                     attributes = annotation.attributeValues
-                } else if (expression is JavaUAnnotationCallExpression) {
-                    val annotation = expression.uAnnotation
-                    attributes = annotation.attributeValues
-                } else if (expression is UastEmptyExpression && attributes[0].sourcePsi is PsiNameValuePair) {
-                    val memberValue = (attributes[0].sourcePsi as PsiNameValuePair).value
-                    if (memberValue is PsiAnnotation) {
-                        val annotation = JavaUAnnotation.wrap(memberValue)
-                        attributes = annotation.attributeValues
-                    }
                 }
             }
+        }
 
-            val inlineConstants = isInlinedConstant(annotationItem)
-            var empty = true
-            for (pair in attributes) {
-                val expression = pair.expression
-                val value = attributeString(expression, inlineConstants) ?: continue
-                empty = false
-                var name = pair.name
-                if (name == null) {
-                    name = SdkConstants.ATTR_VALUE // default name
-                }
-
-                // Platform typedef annotations now declare a prefix attribute for
-                // documentation generation purposes; this should not be part of the
-                // extracted metadata.
-                if (("prefix" == name || "suffix" == name) && annotationItem.isTypeDefAnnotation()) {
-                    reporter.report(
-                        Errors.SUPERFLUOUS_PREFIX, item,
-                        "Superfluous $name attribute on typedef"
-                    )
-                    continue
-                }
-
-                writer.print("      <val name=\"")
-                writer.print(name)
-                writer.print("\" val=\"")
-                writer.print(escapeXml(value))
-                writer.println("\" />")
+        val inlineConstants = isInlinedConstant(annotationItem)
+        var empty = true
+        for (pair in attributes) {
+            val expression = pair.expression
+            val value = attributeString(expression, inlineConstants) ?: continue
+            empty = false
+            var name = pair.name
+            if (name == null) {
+                name = SdkConstants.ATTR_VALUE // default name
             }
 
-            if (empty) {
-                // All items were filtered out: don't write the annotation at all
-                writer.reset()
-                return
+            // Platform typedef annotations now declare a prefix attribute for
+            // documentation generation purposes; this should not be part of the
+            // extracted metadata.
+            if (("prefix" == name || "suffix" == name) && annotationItem.isTypeDefAnnotation()) {
+                reporter.report(
+                    Errors.SUPERFLUOUS_PREFIX, item,
+                    "Superfluous $name attribute on typedef"
+                )
+                continue
             }
+
+            writer.print("      <val name=\"")
+            writer.print(name)
+            writer.print("\" val=\"")
+            writer.print(escapeXml(value))
+            writer.println("\" />")
+        }
+
+        if (empty && attributes.isNotEmpty()) {
+            // All items were filtered out: don't write the annotation at all
+            writer.reset()
+            return
         }
 
         writer.println("    </annotation>")
@@ -621,4 +640,133 @@
     private fun error(string: String) {
         reporter.report(Severity.WARNING, null as PsiElement?, string, Errors.ANNOTATION_EXTRACTION)
     }
+
+    companion object {
+        /** Given an annotation member value, returns the corresponding Java source expression */
+        fun toSourceExpression(value: PsiAnnotationMemberValue, owner: Item): String {
+            val sb = StringBuilder()
+            appendSourceExpression(value, sb, owner)
+            return sb.toString()
+        }
+
+        private fun appendSourceExpression(value: PsiAnnotationMemberValue, sb: StringBuilder, owner: Item): Boolean {
+            if (value is PsiReference) {
+                val resolved = value.resolve()
+                if (resolved is PsiField) {
+                    sb.append(resolved.containingClass?.qualifiedName).append('.').append(resolved.name)
+                    return true
+                }
+            } else if (value is PsiLiteral) {
+                return appendSourceLiteral(value.value, sb, owner)
+            } else if (value is PsiClassObjectAccessExpression) {
+                sb.append(value.operand.type.canonicalText).append(".class")
+                return true
+            } else if (value is PsiArrayInitializerMemberValue) {
+                sb.append('{')
+                var first = true
+                val initialLength = sb.length
+                for (e in value.initializers) {
+                    val length = sb.length
+                    if (first) {
+                        first = false
+                    } else {
+                        sb.append(", ")
+                    }
+                    val appended = appendSourceExpression(e, sb, owner)
+                    if (!appended) {
+                        // trunk off comma if it bailed for some reason (e.g. constant
+                        // filtered out by API etc)
+                        sb.setLength(length)
+                        if (length == initialLength) {
+                            first = true
+                        }
+                    }
+                }
+                sb.append('}')
+                return true
+            } else if (value is PsiAnnotation) {
+                sb.append('@').append(value.qualifiedName)
+                return true
+            } else {
+                if (value is PsiTypeCastExpression) {
+                    val type = value.castType?.type
+                    val operand = value.operand
+                    if (type != null && operand is PsiAnnotationMemberValue) {
+                        sb.append('(')
+                        sb.append(type.canonicalText)
+                        sb.append(')')
+                        return appendSourceExpression(operand, sb, owner)
+                    }
+                }
+                val constant = ConstantEvaluator.evaluate(null, value)
+                if (constant != null) {
+                    return appendSourceLiteral(constant, sb, owner)
+                }
+            }
+            reporter.report(Errors.INTERNAL_ERROR, owner, "Unexpected annotation default value $value")
+            return false
+        }
+
+        private fun appendSourceLiteral(v: Any?, sb: StringBuilder, owner: Item): Boolean {
+            if (v == null) {
+                sb.append("null")
+                return true
+            }
+            when (v) {
+                is Int, is Long, is Boolean, is Byte, is Short -> {
+                    sb.append(v.toString())
+                    return true
+                }
+                is String -> {
+                    sb.append('"').append(javaEscapeString(v)).append('"')
+                    return true
+                }
+                is Float -> {
+                    return when (v) {
+                        Float.POSITIVE_INFINITY -> {
+                            // This convention (displaying fractions) is inherited from doclava
+                            sb.append("(1.0f/0.0f)"); true
+                        }
+                        Float.NEGATIVE_INFINITY -> {
+                            sb.append("(-1.0f/0.0f)"); true
+                        }
+                        Float.NaN -> {
+                            sb.append("(0.0f/0.0f)"); true
+                        }
+                        else -> {
+                            sb.append(canonicalizeFloatingPointString(v.toString()) + "f")
+                            true
+                        }
+                    }
+                }
+                is Double -> {
+                    return when (v) {
+                        Double.POSITIVE_INFINITY -> {
+                            // This convention (displaying fractions) is inherited from doclava
+                            sb.append("(1.0/0.0)"); true
+                        }
+                        Double.NEGATIVE_INFINITY -> {
+                            sb.append("(-1.0/0.0)"); true
+                        }
+                        Double.NaN -> {
+                            sb.append("(0.0/0.0)"); true
+                        }
+                        else -> {
+                            sb.append(canonicalizeFloatingPointString(v.toString()))
+                            true
+                        }
+                    }
+                }
+                is Char -> {
+                    sb.append('\'').append(javaEscapeString(v.toString())).append('\'')
+                    return true
+                }
+                else -> {
+                    reporter.report(Errors.INTERNAL_ERROR, owner, "Unexpected literal value $v")
+                }
+            }
+
+            return false
+        }
+    }
 }
diff --git a/src/main/java/com/android/tools/metalava/Options.kt b/src/main/java/com/android/tools/metalava/Options.kt
index b2c1c68..5bd8415 100644
--- a/src/main/java/com/android/tools/metalava/Options.kt
+++ b/src/main/java/com/android/tools/metalava/Options.kt
@@ -107,6 +107,10 @@
 private const val ARG_GENERATE_DOCUMENTATION = "--generate-documentation"
 private const val ARG_JAVA_SOURCE = "--java-source"
 private const val ARG_REGISTER_ARTIFACT = "--register-artifact"
+private const val ARG_COPY_ANNOTATIONS = "--copy-annotations"
+private const val ARG_INCLUDE_ANNOTATION_CLASSES = "--include-annotation-classes"
+private const val ARG_REWRITE_ANNOTATIONS = "--rewrite-annotations"
+private const val ARG_INCLUDE_SOURCE_RETENTION = "--include-source-retention"
 
 class Options(
     args: Array<String>,
@@ -258,6 +262,28 @@
     /** If set, a file to write extracted annotations to. Corresponds to the --extract-annotations flag. */
     var externalAnnotations: File? = null
 
+    /** For [ARG_COPY_ANNOTATIONS], the source directory to read stub annotations from */
+    var privateAnnotationsSource: File? = null
+
+    /** For [ARG_COPY_ANNOTATIONS], the target directory to write converted stub annotations from */
+    var privateAnnotationsTarget: File? = null
+
+    /**
+     * For [ARG_INCLUDE_ANNOTATION_CLASSES], the directory to copy stub annotation source files into the
+     * stubs folder from
+     */
+    var copyStubAnnotationsFrom: File? = null
+
+    /**
+     * For [ARG_INCLUDE_SOURCE_RETENTION], true if we want to include source-retention annotations
+     * both in the set of files emitted by [ARG_INCLUDE_ANNOTATION_CLASSES] and into the stubs
+     * themselves
+     */
+    var includeSourceRetentionAnnotations = false
+
+    /** For [ARG_REWRITE_ANNOTATIONS], the jar or bytecode folder to rewrite annotations in */
+    var rewriteAnnotations: List<File>? = null
+
     /** A manifest file to read to for example look up available permissions */
     var manifest: File? = null
 
@@ -523,6 +549,13 @@
                 ARG_INPUT_API_JAR -> apiJar = stringToExistingFile(getValue(args, ++index))
 
                 ARG_EXTRACT_ANNOTATIONS -> externalAnnotations = stringToNewFile(getValue(args, ++index))
+                ARG_COPY_ANNOTATIONS -> {
+                    privateAnnotationsSource = stringToExistingDir(getValue(args, ++index))
+                    privateAnnotationsTarget = stringToNewDir(getValue(args, ++index))
+                }
+                ARG_REWRITE_ANNOTATIONS -> rewriteAnnotations = stringToExistingDirsOrJars(getValue(args, ++index))
+                ARG_INCLUDE_ANNOTATION_CLASSES -> copyStubAnnotationsFrom = stringToExistingDir(getValue(args, ++index))
+                ARG_INCLUDE_SOURCE_RETENTION -> includeSourceRetentionAnnotations = true
 
                 ARG_PREVIOUS_API -> previousApi = stringToExistingFile(getValue(args, ++index))
                 ARG_CURRENT_API -> currentApi = stringToExistingFile(getValue(args, ++index))
@@ -556,12 +589,12 @@
                 "-werror" -> {
                     // Temporarily disabled; this is used in various builds but is pretty much
                     // never what we want.
-                    //warningsAreErrors = true
+                    // warningsAreErrors = true
                 }
                 "-lerror" -> {
                     // Temporarily disabled; this is used in various builds but is pretty much
                     // never what we want.
-                    //lintsAreErrors = true
+                    // lintsAreErrors = true
                 }
 
                 ARG_CHECK_KOTLIN_INTEROP -> checkKotlinInterop = true
@@ -620,19 +653,33 @@
                 ARG_GENERATE_DOCUMENTATION -> {
                     // Digest all the remaining arguments.
                     // Allow "STUBS_DIR" to reference the stubs directory.
+                    var prev = ""
                     invokeDocumentationToolArguments = args.slice(++index until args.size).mapNotNull {
-                        if (it == "STUBS_DIR" && docStubsDir != null) {
-                            docStubsDir?.path
-                        } else if (it == "STUBS_DIR" && stubsDir != null) {
+                        var argument = it
+                        // When generating documentation, use the doc stubs directory rather than the
+                        // original source path
+                        val docStubsDir = docStubsDir
+                        if (docStubsDir != null && (prev == ARG_SOURCE_PATH || prev == "-sourcepath") &&
+                            !argument.contains(docStubsDir.path)) {
+                            // Insert the doc stubs as the default place to look for sources
+                            argument = docStubsDir.path // + File.pathSeparatorChar + argument
+                        }
+                        prev = it
+
+                        if (argument == "STUBS_DIR" && docStubsDir != null) {
+                            docStubsDir.path
+                        } else if (argument == "STUBS_DIR" && stubsDir != null) {
                             stubsDir?.path
-                        } else if (it == "DOC_STUBS_SOURCE_LIST" && docStubsSourceList != null) {
+                        } else if (argument == "DOCS_STUBS_DIR" && docStubsDir != null) {
+                            docStubsDir.path
+                        } else if (argument == "DOC_STUBS_SOURCE_LIST" && docStubsSourceList != null) {
                             "@${docStubsSourceList?.path}"
-                        } else if (it == "STUBS_SOURCE_LIST" && stubsSourceList != null) {
+                        } else if (argument == "STUBS_SOURCE_LIST" && stubsSourceList != null) {
                             "@${stubsSourceList?.path}"
-                        } else if (it == "STUBS_SOURCE_LIST" && docStubsSourceList != null) {
+                        } else if (argument == "STUBS_SOURCE_LIST" && docStubsSourceList != null) {
                             "@${docStubsSourceList?.path}"
                         } else {
-                            it
+                            argument
                         }
                     }.toTypedArray()
 
@@ -1271,7 +1318,17 @@
             "", "\nExtracting Annotations:",
             "$ARG_EXTRACT_ANNOTATIONS <zipfile>", "Extracts source annotations from the source files and writes " +
                 "them into the given zip file",
+            "$ARG_INCLUDE_ANNOTATION_CLASSES <dir>", "Copies the given stub annotation source files into the " +
+                "generated stub sources; <dir> is typically $PROGRAM_NAME/stub-annotations/src/main/java/.",
 
+// Soon to be removed; not documented:
+//            "$ARG_COPY_ANNOTATIONS <source> <dest>", "For a source folder full of annotation " +
+//                "sources, generates corresponding package private versions of the same annotations.",
+            "$ARG_REWRITE_ANNOTATIONS <dir/jar>", "For a bytecode folder or output jar, rewrites the " +
+                "androidx annotations to be package private",
+            ARG_INCLUDE_SOURCE_RETENTION, "If true, include source-retention annotations in the stub files. Does " +
+                "not apply to signature files. Source retention annotations are extracted into the external " +
+                "annotations files instead.",
             "", "\nInjecting API Levels:",
             "$ARG_APPLY_API_LEVELS <api-versions.xml>", "Reads an XML file containing API level descriptions " +
                 "and merges the information into the documentation",
diff --git a/src/main/java/com/android/tools/metalava/RewriteAnnotations.kt b/src/main/java/com/android/tools/metalava/RewriteAnnotations.kt
new file mode 100644
index 0000000..78117c1
--- /dev/null
+++ b/src/main/java/com/android/tools/metalava/RewriteAnnotations.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.metalava
+
+import com.android.SdkConstants
+import com.android.SdkConstants.DOT_CLASS
+import com.android.SdkConstants.DOT_JAR
+import com.android.tools.metalava.model.AnnotationItem
+import com.google.common.io.Closer
+import org.objectweb.asm.ClassReader
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.ClassWriter
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.Opcodes.ASM6
+import java.io.BufferedInputStream
+import java.io.BufferedOutputStream
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileOutputStream
+import java.io.IOException
+import java.nio.file.attribute.FileTime
+import java.util.jar.JarEntry
+import java.util.zip.ZipInputStream
+import java.util.zip.ZipOutputStream
+
+/**
+ * Converts public stub annotation sources into package private annotation sources.
+ * This is needed for the stub sources, where we want to reference annotations that aren't
+ * public, but (a) they need to be public during compilation, and (b) they need to be
+ * package private when compiled and packaged on their own such that annotation processors
+ * can find them. See b/110532131 for details.
+ */
+
+class RewriteAnnotations {
+    /** Copies annotation source files from [source] to [target] */
+    fun copyAnnotations(source: File, target: File, pkg: String = "") {
+        val fileName = source.name
+        if (fileName.endsWith(SdkConstants.DOT_JAVA)) {
+            if (!options.includeSourceRetentionAnnotations) {
+                // Only copy non-source retention annotation classes
+                val qualifiedName = pkg + "." + fileName.substring(0, fileName.indexOf('.'))
+                if (!AnnotationItem.hasClassRetention(qualifiedName)) {
+                    return
+                }
+            }
+
+            // Copy and convert
+            target.parentFile.mkdirs()
+            source.copyTo(target)
+        } else if (source.isDirectory) {
+            val newPackage = if (pkg.isEmpty()) fileName else "$pkg.$fileName"
+            source.listFiles()?.forEach {
+                copyAnnotations(it, File(target, it.name), newPackage)
+            }
+        }
+    }
+
+    /** Modifies annotation source files such that they are package private */
+    fun modifyAnnotationSources(source: File, target: File) {
+        if (source.name.endsWith(SdkConstants.DOT_JAVA)) {
+            // Copy and convert
+            target.parentFile.mkdirs()
+            target.writeText(
+                source.readText(Charsets.UTF_8).replace(
+                    "\npublic @interface",
+                    "\n@interface"
+                )
+            )
+        } else if (source.isDirectory) {
+            source.listFiles()?.forEach {
+                modifyAnnotationSources(it, File(target, it.name))
+            }
+        }
+    }
+
+    /** Writes the bytecode for the compiled annotations in the given file list such that they are package private */
+    fun rewriteAnnotations(files: List<File>) {
+        for (file in files) {
+            // Jump directly into androidx/annotation if it appears we were invoked at the top level
+            if (file.isDirectory) {
+                val annotations = File(file, "androidx${File.separator}annotation/")
+                if (annotations.isDirectory) {
+                    rewriteAnnotations(annotations)
+                    continue
+                }
+            }
+
+            rewriteAnnotations(file)
+        }
+    }
+
+    /** Writes the bytecode for the compiled annotations in the given file such that they are package private */
+    private fun rewriteAnnotations(file: File) {
+        when {
+            file.isDirectory -> file.listFiles()?.forEach { rewriteAnnotations(it) }
+            file.path.endsWith(DOT_CLASS) -> rewriteClassFile(file)
+            file.path.endsWith(DOT_JAR) -> rewriteJar(file)
+        }
+    }
+
+    private fun rewriteClassFile(file: File) {
+        if (file.name.contains("$")) {
+            return // Not worrying about inner classes
+        }
+        val bytes = file.readBytes()
+        val rewritten = rewriteClass(bytes, file.path) ?: return
+        file.writeBytes(rewritten)
+    }
+
+    private fun rewriteClass(bytes: ByteArray, path: String): ByteArray? {
+        return try {
+            val reader = ClassReader(bytes)
+            rewriteOuterClass(reader)
+        } catch (ioe: IOException) {
+            error("Could not process " + path + ": " + ioe.localizedMessage)
+        }
+    }
+
+    private fun rewriteOuterClass(reader: ClassReader): ByteArray? {
+        val classWriter = ClassWriter(ASM6)
+        var skip = true
+        val classVisitor = object : ClassVisitor(ASM6, classWriter) {
+            override fun visit(
+                version: Int,
+                access: Int,
+                name: String,
+                signature: String?,
+                superName: String?,
+                interfaces: Array<out String>?
+            ) {
+                // Only process public annotations in androidx.annotation
+                if (access and Opcodes.ACC_PUBLIC != 0 &&
+                    access and Opcodes.ACC_ANNOTATION != 0 &&
+                    name.startsWith("androidx/annotation/")
+                ) {
+                    skip = false
+                    val flagsWithoutPublic = access and Opcodes.ACC_PUBLIC.inv()
+                    super.visit(version, flagsWithoutPublic, name, signature, superName, interfaces)
+                }
+            }
+        }
+
+        reader.accept(classVisitor, 0)
+        return if (skip) {
+            null
+        } else {
+            classWriter.toByteArray()
+        }
+    }
+
+    private fun rewriteJar(file: File) {
+        val temp = File(file.name + ".temp-$PROGRAM_NAME")
+        rewriteJar(file, temp)
+        file.delete()
+        temp.renameTo(file)
+    }
+
+    private val zeroTime = FileTime.fromMillis(0)
+
+    private fun rewriteJar(from: File, to: File/*, filter: Predicate<String>?*/) {
+        Closer.create().use { closer ->
+            val fos = closer.register(FileOutputStream(to))
+            val bos = closer.register(BufferedOutputStream(fos))
+            val zos = closer.register(ZipOutputStream(bos))
+
+            val fis = closer.register(FileInputStream(from))
+            val bis = closer.register(BufferedInputStream(fis))
+            val zis = closer.register(ZipInputStream(bis))
+
+            while (true) {
+                val entry = zis.nextEntry ?: break
+                val name = entry.name
+                val newEntry: JarEntry
+
+                // Preserve the STORED method of the input entry.
+                newEntry = if (entry.method == JarEntry.STORED) {
+                    val jarEntry = JarEntry(entry)
+                    jarEntry.size = entry.size
+                    jarEntry.compressedSize = entry.compressedSize
+                    jarEntry.crc = entry.crc
+                    jarEntry
+                } else {
+                    // Create a new entry so that the compressed len is recomputed.
+                    JarEntry(name)
+                }
+
+                newEntry.lastAccessTime = zeroTime
+                newEntry.creationTime = zeroTime
+                newEntry.lastModifiedTime = entry.lastModifiedTime
+
+                // add the entry to the jar archive
+                zos.putNextEntry(newEntry)
+
+                // read the content of the entry from the input stream, and write it into the archive.
+                if (name.endsWith(DOT_CLASS) &&
+                    name.startsWith("androidx/annotation/") &&
+                    name.indexOf("$") == -1 &&
+                    !entry.isDirectory
+                ) {
+                    val bytes = zis.readBytes(entry.size.toInt())
+                    val rewritten = rewriteClass(bytes, name)
+                    if (rewritten != null) {
+                        zos.write(rewritten)
+                    } else {
+                        zos.write(bytes)
+                    }
+                } else {
+                    zis.copyTo(zos)
+                }
+
+                zos.closeEntry()
+                zis.closeEntry()
+            }
+        }
+    }
+}
diff --git a/src/main/java/com/android/tools/metalava/SignatureWriter.kt b/src/main/java/com/android/tools/metalava/SignatureWriter.kt
index 7fca3d8..5d7be95 100644
--- a/src/main/java/com/android/tools/metalava/SignatureWriter.kt
+++ b/src/main/java/com/android/tools/metalava/SignatureWriter.kt
@@ -98,6 +98,17 @@
         writer.print(method.name())
         writeParameterList(method)
         writeThrowsList(method)
+
+        if (compatibility.includeAnnotationDefaults) {
+            if (method.containingClass().isAnnotationType()) {
+                val default = method.defaultValue()
+                if (default.isNotEmpty()) {
+                    writer.print(" default ")
+                    writer.print(default)
+                }
+            }
+        }
+
         writer.print(";\n")
     }
 
@@ -150,7 +161,9 @@
             includeAnnotations = compatibility.annotationsInSignatures,
             skipNullnessAnnotations = options.outputKotlinStyleNulls,
             omitCommonPackages = options.omitCommonPackages,
-            onlyIncludeSignatureAnnotations = true
+            onlyIncludeSignatureAnnotations = true,
+            onlyIncludeStubAnnotations = false,
+            onlyIncludeClassRetentionAnnotations = false
         )
     }
 
@@ -199,9 +212,20 @@
         }
 
         if (all.any()) {
-            val label = if (isInterface && !compatibility.extendsForInterfaceSuperClass) " extends" else " implements"
+            val label =
+                if (isInterface && !compatibility.extendsForInterfaceSuperClass) {
+                    val superInterface = cls.filteredSuperclass(filterReference)
+                    if (superInterface != null && !superInterface.isJavaLangObject()) {
+                        // For interfaces we've already listed "extends <super interface>"; we don't
+                        // want to repeat "extends " here
+                        ""
+                    } else {
+                        " extends"
+                    }
+                } else {
+                    " implements"
+                }
             writer.print(label)
-
             all.sortedWith(TypeItem.comparator).forEach { item ->
                 writer.print(" ")
                 writer.print(item.toTypeString(erased = compatibility.omitTypeParametersInInterfaces))
diff --git a/src/main/java/com/android/tools/metalava/StubWriter.kt b/src/main/java/com/android/tools/metalava/StubWriter.kt
index 40a6a5a..de41742 100644
--- a/src/main/java/com/android/tools/metalava/StubWriter.kt
+++ b/src/main/java/com/android/tools/metalava/StubWriter.kt
@@ -140,7 +140,9 @@
                 // Some bug in UAST triggers duplicate nullability annotations
                 // here; make sure the are filtered out
                 filterDuplicates = true,
-                onlyIncludeSignatureAnnotations = true,
+                onlyIncludeSignatureAnnotations = false,
+                onlyIncludeStubAnnotations = true,
+                onlyIncludeClassRetentionAnnotations = true,
                 writer = writer
             )
             writer.println("package ${pkg.qualifiedName()};")
@@ -302,7 +304,9 @@
         ModifierList.write(
             writer, modifiers, item, removeAbstract = removeAbstract, removeFinal = removeFinal,
             addPublic = addPublic, includeAnnotations = generateAnnotations,
-            onlyIncludeSignatureAnnotations = true
+            onlyIncludeSignatureAnnotations = false,
+            onlyIncludeStubAnnotations = true,
+            onlyIncludeClassRetentionAnnotations = true
         )
     }
 
@@ -499,6 +503,14 @@
         generateParameterList(method)
         generateThrowsList(method)
 
+        if (isAnnotation) {
+            val default = method.defaultValue()
+            if (default.isNotEmpty()) {
+                writer.print(" default ")
+                writer.print(default)
+            }
+        }
+
         if (modifiers.isAbstract() && !removeAbstract && !isEnum || isAnnotation || modifiers.isNative()) {
             writer.println(";")
         } else {
diff --git a/src/main/java/com/android/tools/metalava/doclava1/ApiFile.java b/src/main/java/com/android/tools/metalava/doclava1/ApiFile.java
index fca21ff..5456d75 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/ApiFile.java
+++ b/src/main/java/com/android/tools/metalava/doclava1/ApiFile.java
@@ -31,6 +31,7 @@
 import com.google.common.base.Charsets;
 import com.google.common.io.Files;
 import kotlin.Pair;
+import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
 import java.io.IOException;
@@ -80,7 +81,7 @@
             if ("package".equals(token)) {
                 parsePackage(api, tokenizer);
             } else {
-                throw new ApiParseException("expected package got " + token, tokenizer.getLine());
+                throw new ApiParseException("expected package got " + token, tokenizer);
             }
         }
 
@@ -101,7 +102,7 @@
         pkg = new TextPackageItem(api, name, tokenizer.pos());
         token = tokenizer.requireToken();
         if (!"{".equals(token)) {
-            throw new ApiParseException("expected '{' got " + token, tokenizer.getLine());
+            throw new ApiParseException("expected '{' got " + token, tokenizer);
         }
         while (true) {
             token = tokenizer.requireToken();
@@ -201,7 +202,7 @@
             ext = JAVA_LANG_ENUM;
             token = tokenizer.requireToken();
         } else {
-            throw new ApiParseException("missing class or interface. got: " + token, tokenizer.getLine());
+            throw new ApiParseException("missing class or interface. got: " + token, tokenizer);
         }
         assertIdent(tokenizer, token);
         name = token;
@@ -232,7 +233,11 @@
         }
         // Resolve superclass after done parsing
         api.mapClassToSuper(cl, ext);
-        if ("implements".equals(token)) {
+        if ("implements".equals(token) || "extends".equals(token) ||
+                isInterface && ext != null && !token.equals("{")) {
+            if (!token.equals("implements") && !token.equals("extends")) {
+                api.mapClassToInterface(cl, token);
+            }
             while (true) {
                 token = tokenizer.requireToken();
                 if ("{".equals(token)) {
@@ -253,7 +258,7 @@
             cl.setIsAnnotationType(true);
         }
         if (!"{".equals(token)) {
-            throw new ApiParseException("expected {", tokenizer.getLine());
+            throw new ApiParseException("expected {, was " + token, tokenizer);
         }
         token = tokenizer.requireToken();
         while (true) {
@@ -272,31 +277,31 @@
                 token = tokenizer.requireToken();
                 parseField(api, tokenizer, cl, token, true);
             } else {
-                throw new ApiParseException("expected ctor, enum_constant, field or method", tokenizer.getLine());
+                throw new ApiParseException("expected ctor, enum_constant, field or method", tokenizer);
             }
             token = tokenizer.requireToken();
         }
         pkg.addClass(cl);
     }
 
-    private static Pair<String, List<String>> processKotlinTypeSuffix(TextCodebase api, String token, List<String> annotations) throws ApiParseException {
+    private static Pair<String, List<String>> processKotlinTypeSuffix(TextCodebase api, String type, List<String> annotations) throws ApiParseException {
         if (api.getKotlinStyleNulls()) {
-            if (token.endsWith("?")) {
-                token = token.substring(0, token.length() - 1);
+            if (type.endsWith("?")) {
+                type = type.substring(0, type.length() - 1);
                 annotations = mergeAnnotations(annotations, ANDROIDX_NULLABLE);
-            } else if (token.endsWith("!")) {
-                token = token.substring(0, token.length() - 1);
-            } else if (!token.endsWith("!")) {
-                if (!TextTypeItem.Companion.isPrimitive(token)) { // Don't add nullness on primitive types like void
+            } else if (type.endsWith("!")) {
+                type = type.substring(0, type.length() - 1);
+            } else if (!type.endsWith("!")) {
+                if (!TextTypeItem.Companion.isPrimitive(type)) { // Don't add nullness on primitive types like void
                     annotations = mergeAnnotations(annotations, ANDROIDX_NOTNULL);
                 }
             }
-        } else if (token.endsWith("?") || token.endsWith("!")) {
+        } else if (type.endsWith("?") || type.endsWith("!")) {
             throw new ApiParseException("Did you forget to supply --input-kotlin-nulls? Found Kotlin-style null type suffix when parser was not configured " +
-                "to interpret signature file that way: " + token);
+                "to interpret signature file that way: " + type);
         }
         //noinspection unchecked
-        return new Pair<>(token, annotations);
+        return new Pair<>(type, annotations);
     }
 
     private static Pair<String, List<String>> getAnnotations(Tokenizer tokenizer, String token) throws ApiParseException {
@@ -387,7 +392,7 @@
         name = token.substring(token.lastIndexOf('.') + 1); // For inner classes, strip outer classes from name
         token = tokenizer.requireToken();
         if (!"(".equals(token)) {
-            throw new ApiParseException("expected (", tokenizer.getLine());
+            throw new ApiParseException("expected (", tokenizer);
         }
         method = new TextConstructorItem(api, /*typeParameters*/
             name, /*signature*/ cl, isPublic, isProtected, isPrivate, isInternal, false/*isFinal*/,
@@ -397,14 +402,13 @@
             /*overriddenMethod*/ cl.asTypeInfo(),
             /*thrownExceptions*/ tokenizer.pos(), annotations);
         method.setDeprecated(isDeprecated);
-        token = tokenizer.requireToken();
-        parseParameterList(api, tokenizer, method, /*new HashSet<String>(),*/ token);
+        parseParameterList(api, tokenizer, method);
         token = tokenizer.requireToken();
         if ("throws".equals(token)) {
             token = parseThrows(tokenizer, method);
         }
         if (!";".equals(token)) {
-            throw new ApiParseException("expected ; found " + token, tokenizer.getLine());
+            throw new ApiParseException("expected ; found " + token, tokenizer);
         }
         cl.addConstructor(method);
     }
@@ -424,6 +428,8 @@
         boolean isInfix = false;
         boolean isOperator = false;
         boolean isInline = false;
+        boolean isNative = false;
+        boolean isStrictFp = false;
         TextTypeItem returnType;
         String name;
         TextMethodItem method;
@@ -483,6 +489,14 @@
                     isSynchronized = true;
                     token = tokenizer.requireToken();
                     break;
+                case "native":
+                    isNative = true;
+                    token = tokenizer.requireToken();
+                    break;
+                case "strictfp":
+                    isStrictFp = true;
+                    token = tokenizer.requireToken();
+                    break;
                 case "infix":
                     isInfix = true;
                     token = tokenizer.requireToken();
@@ -509,30 +523,56 @@
         Pair<String, List<String>> kotlinTypeSuffix = processKotlinTypeSuffix(api, token, annotations);
         token = kotlinTypeSuffix.getFirst();
         annotations = kotlinTypeSuffix.getSecond();
-        returnType = api.obtainTypeFromString(token, cl, typeParameterList);
+        String returnTypeString = token;
 
         token = tokenizer.requireToken();
+
+        if (returnTypeString.contains("@") && (returnTypeString.indexOf('<') == -1 ||
+                returnTypeString.indexOf('@') < returnTypeString.indexOf('<'))) {
+            //noinspection StringConcatenationInLoop
+            returnTypeString += " " + token;
+            token = tokenizer.requireToken();
+        }
+        while (true) {
+            if (token.contains("@") && (token.indexOf('<') == -1 ||
+                   token.indexOf('@') < token.indexOf('<'))) {
+                // Type-use annotations in type; keep accumulating
+                returnTypeString += " " + token;
+                token = tokenizer.requireToken();
+                if (token.startsWith("[")) { // TODO: This isn't general purpose; make requireToken smarter!
+                    returnTypeString += " " + token;
+                    token = tokenizer.requireToken();
+                }
+            } else {
+                break;
+            }
+        }
+
+        returnType = api.obtainTypeFromString(returnTypeString, cl, typeParameterList);
+
         assertIdent(tokenizer, token);
         name = token;
         method = new TextMethodItem(
             api, name, /*signature*/ cl,
-            isPublic, isProtected, isPrivate, isInternal, isFinal, isStatic, isAbstract/*isAbstract*/,
-            isSynchronized, false/*isNative*/, isDefault/*isDefault*/, isInfix, isOperator, isInline,
+            isPublic, isProtected, isPrivate, isInternal, isFinal, isStatic, isAbstract,
+            isSynchronized, isNative, isDefault, isStrictFp, isInfix, isOperator, isInline,
             returnType, tokenizer.pos(), annotations);
         method.setDeprecated(isDeprecated);
         method.setTypeParameterList(typeParameterList);
         token = tokenizer.requireToken();
         if (!"(".equals(token)) {
-            throw new ApiParseException("expected (", tokenizer.getLine());
+            throw new ApiParseException("expected (, was " + token, tokenizer);
         }
-        token = tokenizer.requireToken();
-        parseParameterList(api, tokenizer, method, /*typeVariableNames,*/ token);
+        parseParameterList(api, tokenizer, method);
         token = tokenizer.requireToken();
         if ("throws".equals(token)) {
             token = parseThrows(tokenizer, method);
         }
+        if ("default".equals(token)) {
+            token = parseDefault(tokenizer, method);
+        }
         if (!";".equals(token)) {
-            throw new ApiParseException("expected ; found " + token, tokenizer.getLine());
+            throw new ApiParseException("expected ; found " + token, tokenizer);
         }
         cl.addMethod(method);
     }
@@ -637,7 +677,7 @@
             token = tokenizer.requireToken();
         }
         if (!";".equals(token)) {
-            throw new ApiParseException("expected ; found " + token, tokenizer.getLine());
+            throw new ApiParseException("expected ; found " + token, tokenizer);
         }
         try {
             v = parseValue(type, val);
@@ -728,14 +768,18 @@
         }
     }
 
-    private static void parseParameterList(TextCodebase api, Tokenizer tokenizer, TextMethodItem method,
-                                           String token) throws ApiParseException {
+    private static void parseParameterList(TextCodebase api, Tokenizer tokenizer, TextMethodItem method)
+                                           throws ApiParseException {
+        String token = tokenizer.requireToken();
         int index = 0;
         while (true) {
             if (")".equals(token)) {
                 return;
             }
 
+            // Each item can be
+            // annotations optional-modifiers type-with-use-annotations-and-generics optional-name optional-equals-default-value
+
             // Metalava: including annotations in file now
             List<String> annotations = null;
             Pair<String, List<String>> result = getAnnotations(tokenizer, token);
@@ -744,20 +788,31 @@
                 annotations = result.component2();
             }
 
-            Pair<String, List<String>> kotlinTypeSuffix = processKotlinTypeSuffix(api, token, annotations);
-            token = kotlinTypeSuffix.getFirst();
-            annotations = kotlinTypeSuffix.getSecond();
-            String type = token;
-            TextTypeItem typeInfo = api.obtainTypeFromString(token);
-
             boolean vararg = false;
-            token = tokenizer.requireToken();
-
             if ("vararg".equals(token)) {
                 vararg = true;
                 token = tokenizer.requireToken();
             }
 
+            // Token should now represent the type
+            String type = token;
+            token = tokenizer.requireToken();
+            if (token.startsWith("@")) {
+                // Type use annotations within the type, which broke up the tokenizer;
+                // put it back together
+                type += " " + token;
+                token = tokenizer.requireToken();
+                if (token.startsWith("[")) { // TODO: This isn't general purpose; make requireToken smarter!
+                    type += " " + token;
+                    token = tokenizer.requireToken();
+                }
+            }
+
+            Pair<String, List<String>> kotlinTypeSuffix = processKotlinTypeSuffix(api, type, annotations);
+            String typeString = kotlinTypeSuffix.getFirst();
+            annotations = kotlinTypeSuffix.getSecond();
+            TextTypeItem typeInfo = api.obtainTypeFromString(typeString);
+
             String name;
             String publicName;
             if (isIdent(token) && !token.equals("=")) {
@@ -785,21 +840,35 @@
                 token = tokenizer.requireToken();
             } else if (")".equals(token)) {
             } else {
-                throw new ApiParseException("expected , found " + token, tokenizer.getLine());
+                throw new ApiParseException("expected , or ), found " + token, tokenizer);
             }
 
-            method.addParameter(new TextParameterItem(api, method, name, publicName, defaultValue, index, type,
+            method.addParameter(new TextParameterItem(api, method, name, publicName, defaultValue, index, typeString,
                 typeInfo,
-                vararg || type.endsWith("..."),
+                vararg || typeString.endsWith("..."),
                 tokenizer.pos(),
                 annotations));
-            if (type.endsWith("...")) {
+            if (typeString.endsWith("...")) {
                 method.setVarargs(true);
             }
             index++;
         }
     }
 
+    private static String parseDefault(Tokenizer tokenizer, TextMethodItem method)
+        throws ApiParseException {
+        StringBuilder sb = new StringBuilder();
+        while (true) {
+            String token = tokenizer.requireToken();
+            if (";".equals(token)) {
+                method.setAnnotationDefault(sb.toString());
+                return token;
+            } else {
+                sb.append(token);
+            }
+        }
+    }
+
     private static String parseThrows(Tokenizer tokenizer, TextMethodItem method)
         throws ApiParseException {
         String token = tokenizer.requireToken();
@@ -809,12 +878,12 @@
                 return token;
             } else if (",".equals(token)) {
                 if (comma) {
-                    throw new ApiParseException("Expected exception, got ','", tokenizer.getLine());
+                    throw new ApiParseException("Expected exception, got ','", tokenizer);
                 }
                 comma = true;
             } else {
                 if (!comma) {
-                    throw new ApiParseException("Expected ',' or ';' got " + token, tokenizer.getLine());
+                    throw new ApiParseException("Expected ',' or ';' got " + token, tokenizer);
                 }
                 comma = false;
                 method.addException(token);
@@ -833,7 +902,7 @@
 
     private static void assertIdent(Tokenizer tokenizer, String token) throws ApiParseException {
         if (!isIdent(token.charAt(0))) {
-            throw new ApiParseException("Expected identifier: " + token, tokenizer.getLine());
+            throw new ApiParseException("Expected identifier: " + token, tokenizer);
         }
     }
 
@@ -930,7 +999,7 @@
                     }
                     final char k = mBuf[mPos];
                     if (k == '\n' || k == '\r') {
-                        throw new ApiParseException("Unexpected newline for \" starting at " + line, mLine);
+                        throw new ApiParseException("Unexpected newline for \" starting at " + line + " in " + mFilename, mLine);
                     }
                     mPos++;
                     switch (state) {
@@ -953,7 +1022,24 @@
             } else {
                 int genericDepth = 0;
                 do {
-                    while (mPos < mBuf.length && !isSpace(mBuf[mPos]) && !isSeparator(mBuf[mPos], parenIsSep)) {
+                    while (mPos < mBuf.length) {
+                        char d = mBuf[mPos];
+                        if (isSpace(d) || isSeparator(d, parenIsSep)) {
+                            break;
+                        } else if (d == '"') {
+                            // String literal in token: skip the full thing
+                            mPos++;
+                            while (mPos < mBuf.length) {
+                                if (mBuf[mPos] == '"') {
+                                    mPos++;
+                                    break;
+                                } else if (mBuf[mPos] == '\\') {
+                                    mPos++;
+                                }
+                                mPos++;
+                            }
+                            continue;
+                        }
                         mPos++;
                     }
                     if (mPos < mBuf.length) {
@@ -975,6 +1061,11 @@
                 return new String(mBuf, start, mPos - start);
             }
         }
+
+        @Nullable
+        public String getFileName() {
+            return mFilename;
+        }
     }
 
     static boolean isSpace(char c) {
diff --git a/src/main/java/com/android/tools/metalava/doclava1/ApiParseException.java b/src/main/java/com/android/tools/metalava/doclava1/ApiParseException.java
index 6711f8c..23bd38e 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/ApiParseException.java
+++ b/src/main/java/com/android/tools/metalava/doclava1/ApiParseException.java
@@ -16,6 +16,9 @@
 
 package com.android.tools.metalava.doclava1;
 
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
 //
 // Copied from doclava1, but adapted to metalava's code model
 //
@@ -23,27 +26,44 @@
     public String file;
     public int line;
 
-    public ApiParseException(String message) {
+    ApiParseException(@NotNull String message) {
         super(message);
     }
 
-    public ApiParseException(String message, Exception cause) {
+    ApiParseException(@NotNull String message, Exception cause) {
         super(message, cause);
         if (cause instanceof ApiParseException) {
+            this.file = ((ApiParseException) cause).file;
             this.line = ((ApiParseException) cause).line;
         }
     }
 
-    public ApiParseException(String message, int line) {
+    ApiParseException(@NotNull String message, @NotNull ApiFile.Tokenizer tokenizer) {
+        this(message, tokenizer.getFileName(), tokenizer.getLine());
+    }
+
+    private ApiParseException(@NotNull String message, @Nullable String file, int line) {
         super(message);
+        this.file = file;
         this.line = line;
     }
 
+    ApiParseException(@NotNull String message, int line) {
+        this(message, null, line);
+    }
+
     public String getMessage() {
-        if (line > 0) {
-            return super.getMessage() + " line " + line;
-        } else {
-            return super.getMessage();
+        StringBuilder sb = new StringBuilder();
+        if (file != null) {
+            sb.append(file).append(':');
         }
+        if (line > 0) {
+            sb.append(Integer.toString(line)).append(':');
+        }
+        if (sb.length() > 0) {
+            sb.append(' ');
+        }
+        sb.append(super.getMessage());
+        return sb.toString();
     }
 }
diff --git a/src/main/java/com/android/tools/metalava/doclava1/Errors.java b/src/main/java/com/android/tools/metalava/doclava1/Errors.java
index 93ceee1..4f48174 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/Errors.java
+++ b/src/main/java/com/android/tools/metalava/doclava1/Errors.java
@@ -197,6 +197,8 @@
     public static final Error ANNOTATION_EXTRACTION = new Error(146, ERROR);
     public static final Error SUPERFLUOUS_PREFIX = new Error(147, WARNING);
     public static final Error HIDDEN_TYPEDEF_CONSTANT = new Error(148, ERROR);
+    public static final Error MISSING_TYPEDEF_CONSTANT = new Error(149, LINT);
+    public static final Error INTERNAL_ERROR = new Error(150, ERROR);
 
     static {
         // Attempt to initialize error names based on the field names
diff --git a/src/main/java/com/android/tools/metalava/model/AnnotationItem.kt b/src/main/java/com/android/tools/metalava/model/AnnotationItem.kt
index f87833f..a3d9647 100644
--- a/src/main/java/com/android/tools/metalava/model/AnnotationItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/AnnotationItem.kt
@@ -52,11 +52,24 @@
     /** Generates source code for this annotation (using fully qualified names) */
     fun toSource(): String
 
-    /** Whether this annotation is significant and should be included in signature files, stubs, etc */
-    fun isSignificant(): Boolean {
+    /** Whether this annotation is significant and should be included in signature files */
+    fun isSignificantInSignatures(): Boolean {
         return includeInSignatures(qualifiedName() ?: return false)
     }
 
+    /** Whether this annotation is significant and should be included in stub files etc */
+    fun isSignificantInStubs(): Boolean {
+        return includeInStubs(qualifiedName() ?: return false)
+    }
+
+    /**
+     * Whether this annotation has class retention. Only class retention annotations are
+     * inserted into the stubs, the rest are extracted into the separate external annotations file.
+     */
+    fun hasClassRetention(): Boolean {
+        return hasClassRetention(qualifiedName())
+    }
+
     /** Attributes of the annotation (may be empty) */
     fun attributes(): List<AnnotationAttribute>
 
@@ -131,6 +144,33 @@
             return false
         }
 
+        /** Whether the given annotation name is "significant", e.g. should be included in signature files */
+        fun includeInStubs(qualifiedName: String?): Boolean {
+            qualifiedName ?: return false
+            if (includeInSignatures(qualifiedName)) {
+                return true
+            }
+
+            // These are the significant annotations that should be included in the stubs.
+            // This is a hardcoded list here to minimize risk in the P release branch;
+            // in master the check is more general (we keep only runtime retention annotations
+            // that match the API filter, plus the retention one)
+            return when (qualifiedName) {
+                "android.view.ViewDebug.ExportedProperty",
+                "android.widget.RemoteViews.RemoteView",
+                "android.view.ViewDebug.CapturedViewProperty",
+
+                "java.lang.FunctionalInterface",
+                "java.lang.SafeVarargs",
+                "java.lang.annotation.Documented",
+                "java.lang.annotation.Inherited",
+                "java.lang.annotation.Repeatable",
+                "java.lang.annotation.Retention",
+                "java.lang.annotation.Target" -> true
+                else -> false
+            }
+        }
+
         /** The simple name of an annotation, which is the annotation name (not qualified name) prefixed by @ */
         fun simpleName(item: AnnotationItem): String {
             val qualifiedName = item.qualifiedName() ?: return ""
@@ -250,6 +290,8 @@
                 "android.annotation.CheckResult" -> return "androidx.annotation.CheckResult"
                 "android.support.annotation.RequiresPermission",
                 "android.annotation.RequiresPermission" -> return "androidx.annotation.RequiresPermission"
+                "android.annotation.RequiresPermission.Read" -> return "androidx.annotation.RequiresPermission.Read"
+                "android.annotation.RequiresPermission.Write" -> return "androidx.annotation.RequiresPermission.Write"
 
             // These aren't support annotations, but could/should be:
                 "android.annotation.CurrentTimeMillisLong",
@@ -388,6 +430,30 @@
                 }
             }
         }
+
+        fun hasClassRetention(qualifiedName: String?): Boolean {
+            // For now, we treat everything except the recently nullable annotations
+            // as source retention; this works around the bug that we don't want to
+            // reference (from the .class files) annotations that aren't part of the SDK
+            // except for those that we include with the stubs
+
+            qualifiedName ?: return false
+
+            return when (qualifiedName) {
+                // Hardcoded list for now; in master, this is generalized
+                "android.view.ViewDebug.ExportedProperty",
+                "android.widget.RemoteViews.RemoteView",
+                "android.view.ViewDebug.CapturedViewProperty",
+
+                "androidx.annotation.RecentlyNullable",
+                "androidx.annotation.RecentlyNonNull" -> return true
+
+                else -> qualifiedName.startsWith("java.") ||
+                    qualifiedName.startsWith("javax.") ||
+                    qualifiedName.startsWith("kotlin.") ||
+                    qualifiedName.startsWith("kotlinx.")
+            }
+        }
     }
 }
 
@@ -465,40 +531,74 @@
         }
 
         fun createList(source: String): List<AnnotationAttribute> {
-            val list = mutableListOf<AnnotationAttribute>()
-            if (source.contains("{")) {
-                assert(
-                    source.indexOf('{', source.indexOf('{', source.indexOf('{') + 1) + 1) != -1
-                ) { "Multiple arrays not supported: $source" }
-                val split = source.indexOf('=')
-                val name: String
-                val value: String
-                if (split == -1) {
-                    name = "value"
-                    value = source.substring(source.indexOf('{'))
-                } else {
-                    name = source.substring(0, split).trim()
-                    value = source.substring(split + 1).trim()
+            val list = mutableListOf<AnnotationAttribute>() // TODO: default size = 2
+            var begin = 0
+            var index = 0
+            val length = source.length
+            while (index < length) {
+                val c = source[index]
+                if (c == '{') {
+                    index = findEnd(source, index + 1, length, '}')
+                } else if (c == '"') {
+                    index = findEnd(source, index + 1, length, '"')
+                } else if (c == ',') {
+                    addAttribute(list, source, begin, index)
+                    index++
+                    begin = index
+                    continue
+                } else if (c == ' ' && index == begin) {
+                    begin++
                 }
-                list.add(DefaultAnnotationAttribute.create(name, value))
-                return list
+
+                index++
             }
 
-            source.split(",").forEach { declaration ->
-                val split = declaration.indexOf('=')
-                val name: String
-                val value: String
-                if (split == -1) {
-                    name = "value"
-                    value = declaration.trim()
-                } else {
-                    name = declaration.substring(0, split).trim()
-                    value = declaration.substring(split + 1).trim()
-                }
-                list.add(DefaultAnnotationAttribute.create(name, value))
+            if (begin < length) {
+                addAttribute(list, source, begin, length)
             }
+
             return list
         }
+
+        private fun findEnd(source: String, from: Int, to: Int, sentinel: Char): Int {
+            var i = from
+            while (i < to) {
+                val c = source[i]
+                if (c == '\\') {
+                    i++
+                } else if (c == sentinel) {
+                    return i
+                }
+                i++
+            }
+            return to
+        }
+
+        private fun addAttribute(list: MutableList<AnnotationAttribute>, source: String, from: Int, to: Int) {
+            var split = source.indexOf('=', from)
+            if (split >= to) {
+                split = -1
+            }
+            val name: String
+            val value: String
+            val valueBegin: Int
+            val valueEnd: Int
+            if (split == -1) {
+                valueBegin = split + 1
+                valueEnd = to
+                name = "value"
+            } else {
+                name = source.substring(from, split).trim()
+                valueBegin = split + 1
+                valueEnd = to
+            }
+            value = source.substring(valueBegin, valueEnd).trim()
+            list.add(DefaultAnnotationAttribute.create(name, value))
+        }
+    }
+
+    override fun toString(): String {
+        return "DefaultAnnotationAttribute(name='$name', value=$value)"
     }
 }
 
diff --git a/src/main/java/com/android/tools/metalava/model/Codebase.kt b/src/main/java/com/android/tools/metalava/model/Codebase.kt
index 41ce549..3c86e61 100644
--- a/src/main/java/com/android/tools/metalava/model/Codebase.kt
+++ b/src/main/java/com/android/tools/metalava/model/Codebase.kt
@@ -155,7 +155,7 @@
     override var manifest: File? = null
     private var permissions: Map<String, String>? = null
     override var original: Codebase? = null
-    override var supportsStagedNullability: Boolean = false
+    override var supportsStagedNullability: Boolean = true
     override var units: List<PsiFile> = emptyList()
     override var apiLevel: Int = -1
 
diff --git a/src/main/java/com/android/tools/metalava/model/MethodItem.kt b/src/main/java/com/android/tools/metalava/model/MethodItem.kt
index 03eb387..a3836c0 100644
--- a/src/main/java/com/android/tools/metalava/model/MethodItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/MethodItem.kt
@@ -406,6 +406,9 @@
      * declared in the signature) */
     fun findThrownExceptions(): Set<ClassItem> = codebase.unsupported()
 
+    /** If annotation method, returns the default value as a source expression */
+    fun defaultValue(): String = ""
+
     /**
      * Returns true if this method is a signature match for the given method (e.g. can
      * be overriding). This checks that the name and parameter lists match, but ignores
diff --git a/src/main/java/com/android/tools/metalava/model/ModifierList.kt b/src/main/java/com/android/tools/metalava/model/ModifierList.kt
index 435baf8..a6c1b9f 100644
--- a/src/main/java/com/android/tools/metalava/model/ModifierList.kt
+++ b/src/main/java/com/android/tools/metalava/model/ModifierList.kt
@@ -184,8 +184,9 @@
             removeAbstract: Boolean = false,
             removeFinal: Boolean = false,
             addPublic: Boolean = false,
-            onlyIncludeSignatureAnnotations: Boolean = true
-
+            onlyIncludeSignatureAnnotations: Boolean = true,
+            onlyIncludeStubAnnotations: Boolean = false,
+            onlyIncludeClassRetentionAnnotations: Boolean = false
         ) {
 
             val list = if (removeAbstract || removeFinal || addPublic) {
@@ -214,7 +215,9 @@
                     omitCommonPackages = omitCommonPackages,
                     separateLines = false,
                     writer = writer,
-                    onlyIncludeSignatureAnnotations = onlyIncludeSignatureAnnotations
+                    onlyIncludeSignatureAnnotations = onlyIncludeSignatureAnnotations,
+                    onlyIncludeStubAnnotations = onlyIncludeStubAnnotations,
+                    onlyIncludeClassRetentionAnnotations = onlyIncludeClassRetentionAnnotations
                 )
             }
 
@@ -387,19 +390,27 @@
             separateLines: Boolean = false,
             filterDuplicates: Boolean = false,
             writer: Writer,
-            onlyIncludeSignatureAnnotations: Boolean = true
+            onlyIncludeSignatureAnnotations: Boolean = true,
+            onlyIncludeStubAnnotations: Boolean = true,
+            onlyIncludeClassRetentionAnnotations: Boolean = false
         ) {
             val annotations = list.annotations()
             if (annotations.isNotEmpty()) {
                 var index = -1
                 for (annotation in annotations) {
                     index++
-                    if ((annotation.isNonNull() || annotation.isNullable())) {
+                    if (onlyIncludeSignatureAnnotations && !annotation.isSignificantInSignatures()) {
+                        continue
+                    } else if (onlyIncludeStubAnnotations && !annotation.isSignificantInStubs()) {
+                        continue
+                    } else if (onlyIncludeClassRetentionAnnotations && !annotation.hasClassRetention() &&
+                        !options.includeSourceRetentionAnnotations
+                    ) {
+                        continue
+                    } else if ((annotation.isNonNull() || annotation.isNullable())) {
                         if (skipNullnessAnnotations) {
                             continue
                         }
-                    } else if (onlyIncludeSignatureAnnotations && !annotation.isSignificant()) {
-                        continue
                     }
 
                     // Optionally filter out duplicates
diff --git a/src/main/java/com/android/tools/metalava/model/TypeItem.kt b/src/main/java/com/android/tools/metalava/model/TypeItem.kt
index 5d1eaa8..b1ac351 100644
--- a/src/main/java/com/android/tools/metalava/model/TypeItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/TypeItem.kt
@@ -23,6 +23,14 @@
 import com.android.tools.metalava.options
 import java.util.function.Predicate
 
+/**
+ * Whether metalava supports type use annotations.
+ * Note that you can't just turn this flag back on; you have to
+ * also add TYPE_USE back to the handful of nullness
+ * annotations in stub-annotations/src/main/java/.
+ */
+const val SUPPORT_TYPE_USE_ANNOTATIONS = false
+
 /** Represents a type */
 interface TypeItem {
     /**
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiAnnotationItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiAnnotationItem.kt
index 4d78346..1aaca8e 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiAnnotationItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiAnnotationItem.kt
@@ -51,14 +51,20 @@
     override fun toString(): String = toSource()
 
     override fun toSource(): String {
-        val qualifiedName = qualifiedName() ?: return ""
+        val sb = StringBuilder(60)
+        appendAnnotation(sb, psiAnnotation)
+        return sb.toString()
+    }
+
+    private fun appendAnnotation(sb: StringBuilder, psiAnnotation: PsiAnnotation) {
+        val qualifiedName = AnnotationItem.mapName(codebase, psiAnnotation.qualifiedName) ?: return
 
         val attributes = psiAnnotation.parameterList.attributes
         if (attributes.isEmpty()) {
-            return "@$qualifiedName"
+            sb.append("@$qualifiedName")
+            return
         }
 
-        val sb = StringBuilder(30)
         sb.append("@")
         sb.append(qualifiedName)
         sb.append("(")
@@ -79,8 +85,6 @@
             }
         }
         sb.append(")")
-
-        return sb.toString()
     }
 
     override fun resolve(): ClassItem? {
@@ -150,6 +154,9 @@
                 }
                 sb.append('}')
             }
+            is PsiAnnotation -> {
+                appendAnnotation(sb, value)
+            }
             else -> {
                 if (value is PsiExpression) {
                     val source = getConstantSource(value)
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiMethodItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiMethodItem.kt
index a54dc24..2f557be 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiMethodItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiMethodItem.kt
@@ -16,6 +16,7 @@
 
 package com.android.tools.metalava.model.psi
 
+import com.android.tools.metalava.ExtractAnnotations
 import com.android.tools.metalava.compatibility
 import com.android.tools.metalava.model.ClassItem
 import com.android.tools.metalava.model.MethodItem
@@ -23,6 +24,7 @@
 import com.android.tools.metalava.model.ParameterItem
 import com.android.tools.metalava.model.TypeItem
 import com.android.tools.metalava.model.TypeParameterList
+import com.intellij.psi.PsiAnnotationMethod
 import com.intellij.psi.PsiClass
 import com.intellij.psi.PsiMethod
 import com.intellij.psi.util.PsiTypesUtil
@@ -211,6 +213,17 @@
         return exceptions
     }
 
+    override fun defaultValue(): String {
+        if (psiMethod is PsiAnnotationMethod) {
+            val value = psiMethod.defaultValue
+            if (value != null) {
+                return ExtractAnnotations.toSourceExpression(value, this)
+            }
+        }
+
+        return super.defaultValue()
+    }
+
     override fun duplicate(targetContainingClass: ClassItem): PsiMethodItem {
         val duplicated = create(codebase, targetContainingClass as PsiClassItem, psiMethod)
 
@@ -250,7 +263,9 @@
         ModifierList.write(
             modifierString, method.modifiers, method, removeAbstract = false,
             removeFinal = false, addPublic = true,
-            onlyIncludeSignatureAnnotations = true
+            onlyIncludeSignatureAnnotations = false,
+            onlyIncludeStubAnnotations = true,
+            onlyIncludeClassRetentionAnnotations = true
         )
         sb.append(modifierString.toString())
 
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiTypeItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiTypeItem.kt
index 248d047..be0d36c 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiTypeItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiTypeItem.kt
@@ -24,6 +24,7 @@
 import com.android.tools.metalava.model.Codebase
 import com.android.tools.metalava.model.Item
 import com.android.tools.metalava.model.MemberItem
+import com.android.tools.metalava.model.SUPPORT_TYPE_USE_ANNOTATIONS
 import com.android.tools.metalava.model.TypeItem
 import com.android.tools.metalava.model.TypeParameterItem
 import com.android.tools.metalava.model.text.TextTypeItem
@@ -73,7 +74,7 @@
         assert(innerAnnotations || !outerAnnotations) // Can't supply outer=true,inner=false
 
         return if (erased) {
-            if (innerAnnotations || outerAnnotations) {
+            if (SUPPORT_TYPE_USE_ANNOTATIONS && (innerAnnotations || outerAnnotations)) {
                 // Not cached: Not common
                 toTypeString(codebase, psiType, outerAnnotations, innerAnnotations, erased)
             } else {
@@ -84,7 +85,7 @@
             }
         } else {
             when {
-                outerAnnotations -> {
+                SUPPORT_TYPE_USE_ANNOTATIONS && outerAnnotations -> {
                     if (toAnnotatedString == null) {
                         toAnnotatedString = TypeItem.formatType(
                             toTypeString(
@@ -98,7 +99,7 @@
                     }
                     toAnnotatedString!!
                 }
-                innerAnnotations -> {
+                SUPPORT_TYPE_USE_ANNOTATIONS && innerAnnotations -> {
                     if (toInnerAnnotatedString == null) {
                         toInnerAnnotatedString = TypeItem.formatType(
                             toTypeString(
@@ -339,7 +340,7 @@
                 )
             }
 
-            if (outerAnnotations || innerAnnotations) {
+            if (SUPPORT_TYPE_USE_ANNOTATIONS && (innerAnnotations || outerAnnotations)) {
                 val typeString = mapAnnotations(codebase, getCanonicalText(type, true))
                 if (!outerAnnotations && typeString.contains("@")) {
                     // Temporary hack: should use PSI type visitor instead
@@ -404,8 +405,8 @@
         }
 
         private fun getCanonicalText(type: PsiType, annotated: Boolean): String {
-            val typeString = type.getCanonicalText(annotated)
-            if (!annotated) {
+            val typeString = type.getCanonicalText(annotated && SUPPORT_TYPE_USE_ANNOTATIONS)
+            if (!annotated || !SUPPORT_TYPE_USE_ANNOTATIONS) {
                 return typeString
             }
 
@@ -764,4 +765,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/android/tools/metalava/model/text/TextConstructorItem.kt b/src/main/java/com/android/tools/metalava/model/text/TextConstructorItem.kt
index 4262188..2b1e1d7 100644
--- a/src/main/java/com/android/tools/metalava/model/text/TextConstructorItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/text/TextConstructorItem.kt
@@ -39,7 +39,7 @@
     annotations: List<String>?
 ) : TextMethodItem(
     codebase, name, containingClass, isPublic, isProtected, isPrivate, isInternal,
-    isFinal, isStatic, isAbstract, isSynchronized, isNative, isDefault, false, false, false,
+    isFinal, isStatic, isAbstract, isSynchronized, isNative, isDefault, false, false, false, false,
     returnType, position, annotations
 ),
     ConstructorItem {
diff --git a/src/main/java/com/android/tools/metalava/model/text/TextFieldItem.kt b/src/main/java/com/android/tools/metalava/model/text/TextFieldItem.kt
index 50acde8..fba5169 100644
--- a/src/main/java/com/android/tools/metalava/model/text/TextFieldItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/text/TextFieldItem.kt
@@ -26,30 +26,41 @@
     codebase: TextCodebase,
     name: String,
     containingClass: TextClassItem,
-    isPublic: Boolean,
-    isProtected: Boolean,
-    isPrivate: Boolean,
-    isInternal: Boolean,
-    isFinal: Boolean,
-    isStatic: Boolean,
-    isTransient: Boolean,
-    isVolatile: Boolean,
+    modifiers: TextModifiers,
     private val type: TextTypeItem,
     private val constantValue: Any?,
-    position: SourcePositionInfo,
-    annotations: List<String>?
-) : TextMemberItem(
-    codebase, name, containingClass, position,
-    TextModifiers(
-        codebase = codebase,
-        annotationStrings = annotations,
-        public = isPublic, protected = isProtected, private = isPrivate, internal = isInternal,
-        static = isStatic, final = isFinal, transient = isTransient, volatile = isVolatile
-    )
-), FieldItem {
+    position: SourcePositionInfo
+) : TextMemberItem(codebase, name, containingClass, position, modifiers), FieldItem {
+    constructor(
+        codebase: TextCodebase,
+        name: String,
+        containingClass: TextClassItem,
+        isPublic: Boolean,
+        isProtected: Boolean,
+        isPrivate: Boolean,
+        isInternal: Boolean,
+        isFinal: Boolean,
+        isStatic: Boolean,
+        isTransient: Boolean,
+        isVolatile: Boolean,
+        type: TextTypeItem,
+        constantValue: Any?,
+        position: SourcePositionInfo,
+        annotations: List<String>?
+    ) :
+        this(
+            codebase, name, containingClass,
+            TextModifiers(
+                codebase = codebase,
+                annotationStrings = annotations,
+                public = isPublic, protected = isProtected, private = isPrivate, internal = isInternal,
+                static = isStatic, final = isFinal, transient = isTransient, volatile = isVolatile
+            ),
+            type, constantValue, position
+        )
 
     init {
-        (modifiers as TextModifiers).owner = this
+        modifiers.owner = this
     }
 
     override fun equals(other: Any?): Boolean {
@@ -71,7 +82,26 @@
 
     override fun toString(): String = "Field ${containingClass().fullName()}.${name()}"
 
-    override fun duplicate(targetContainingClass: ClassItem): FieldItem = codebase.unsupported()
+    override fun duplicate(targetContainingClass: ClassItem): TextFieldItem {
+        val m = modifiers as TextModifiers
+        val duplicated = TextFieldItem(
+            codebase, name(), targetContainingClass as TextClassItem,
+            m.duplicate(), type, constantValue, position
+        )
+
+        // Preserve flags that may have been inherited (propagated) fro surrounding packages
+        if (targetContainingClass.hidden) {
+            duplicated.hidden = true
+        }
+        if (targetContainingClass.removed) {
+            duplicated.removed = true
+        }
+        if (targetContainingClass.docOnly) {
+            duplicated.docOnly = true
+        }
+
+        return duplicated
+    }
 
     private var isEnumConstant = false
     override fun isEnumConstant(): Boolean = isEnumConstant
diff --git a/src/main/java/com/android/tools/metalava/model/text/TextMethodItem.kt b/src/main/java/com/android/tools/metalava/model/text/TextMethodItem.kt
index d187adc..ec76fff 100644
--- a/src/main/java/com/android/tools/metalava/model/text/TextMethodItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/text/TextMethodItem.kt
@@ -40,6 +40,7 @@
     isSynchronized: Boolean,
     isNative: Boolean,
     isDefault: Boolean,
+    isStrictFp: Boolean,
     isInfix: Boolean,
     isOperator: Boolean,
     isInline: Boolean,
@@ -54,7 +55,7 @@
         codebase = codebase,
         annotationStrings = annotations, public = isPublic, protected = isProtected, internal = isInternal,
         private = isPrivate, static = isStatic, final = isFinal, abstract = isAbstract,
-        synchronized = isSynchronized, native = isNative, default = isDefault,
+        synchronized = isSynchronized, native = isNative, default = isDefault, strictfp = isStrictFp,
         infix = isInfix, operator = isOperator, inline = isInline
     )
 ), MethodItem {
@@ -189,4 +190,14 @@
         "${if (isConstructor()) "Constructor" else "Method"} ${containingClass().qualifiedName()}.${name()}(${parameters().joinToString {
             it.type().toSimpleType()
         }})"
+
+    private var annotationDefault = ""
+
+    fun setAnnotationDefault(default: String) {
+        annotationDefault = default
+    }
+
+    override fun defaultValue(): String {
+        return annotationDefault
+    }
 }
diff --git a/src/main/java/com/android/tools/metalava/model/text/TextModifiers.kt b/src/main/java/com/android/tools/metalava/model/text/TextModifiers.kt
index a627199..5038b3b 100644
--- a/src/main/java/com/android/tools/metalava/model/text/TextModifiers.kt
+++ b/src/main/java/com/android/tools/metalava/model/text/TextModifiers.kt
@@ -27,7 +27,7 @@
 
 class TextModifiers(
     override val codebase: Codebase,
-    annotationStrings: List<String>? = null,
+    private val annotationStrings: List<String>? = null,
     private var public: Boolean = false,
     private var protected: Boolean = false,
     private var private: Boolean = false,
@@ -49,6 +49,33 @@
 ) : MutableModifierList {
     private var annotations: MutableList<AnnotationItem> = mutableListOf()
 
+    fun duplicate(): TextModifiers {
+        val new = TextModifiers(
+            codebase,
+            null,
+            public,
+            protected,
+            private,
+            internal,
+            static,
+            abstract,
+            final,
+            native,
+            synchronized,
+            strictfp,
+            transient,
+            volatile,
+            default,
+            infix,
+            operator,
+            inline,
+            sealed,
+            vararg
+        )
+        new.annotations.addAll(annotations) // these are immutable; sharing copies is fine
+        return new
+    }
+
     init {
         annotationStrings?.forEach { source ->
             val index = source.indexOf('(')
@@ -89,6 +116,7 @@
     override fun isDefault(): Boolean = default
     override fun isSealed(): Boolean = sealed
     override fun isInfix(): Boolean = infix
+    override fun isInline(): Boolean = inline
     override fun isOperator(): Boolean = operator
     override fun isVarArg(): Boolean = vararg
 
diff --git a/src/main/java/com/android/tools/metalava/model/visitors/ApiVisitor.kt b/src/main/java/com/android/tools/metalava/model/visitors/ApiVisitor.kt
index 56d8375..ce054c4 100644
--- a/src/main/java/com/android/tools/metalava/model/visitors/ApiVisitor.kt
+++ b/src/main/java/com/android/tools/metalava/model/visitors/ApiVisitor.kt
@@ -78,7 +78,6 @@
         nestInnerClasses: Boolean = false,
 
         /** Whether to ignore APIs with annotations in the --show-annotations list */
-//        ignoreShown: Boolean = options.showUnannotated,
         ignoreShown: Boolean = true,
 
         /** Whether to match APIs marked for removal instead of the normal API */
diff --git a/src/main/resources/version.properties b/src/main/resources/version.properties
index dd2d971..ab0e374 100644
--- a/src/main/resources/version.properties
+++ b/src/main/resources/version.properties
@@ -1,4 +1,4 @@
 # Version definition
 # This file is read by gradle build scripts, but also packaged with metalava
 # as a resource for the Version classes to read.
-metalavaVersion=0.9.12
+metalavaVersion=1.0.0
diff --git a/src/test/java/com/android/tools/metalava/AnnotationStatisticsTest.kt b/src/test/java/com/android/tools/metalava/AnnotationStatisticsTest.kt
index f62c805..4a1cf39 100644
--- a/src/test/java/com/android/tools/metalava/AnnotationStatisticsTest.kt
+++ b/src/test/java/com/android/tools/metalava/AnnotationStatisticsTest.kt
@@ -163,8 +163,8 @@
                     }
                     """
                 ),
-                supportNonNullSource,
-                supportNullableSource
+                androidxNonNullSource,
+                androidxNullableSource
             ),
             expectedOutput = """
                 6 methods and fields were missing nullness annotations out of 8 total API references.
diff --git a/src/test/java/com/android/tools/metalava/AnnotationsDifferTest.kt b/src/test/java/com/android/tools/metalava/AnnotationsDifferTest.kt
index 0d367d1..daf8c20 100644
--- a/src/test/java/com/android/tools/metalava/AnnotationsDifferTest.kt
+++ b/src/test/java/com/android/tools/metalava/AnnotationsDifferTest.kt
@@ -52,6 +52,8 @@
         """.trimIndent(), false, false)
 
         val apiFile = temporaryFolder.newFile("diff.txt")
+        compatibility = Compatibility(true)
+        options = Options(emptyArray())
         AnnotationsDiffer(codebase, codebase2).writeDiffSignature(apiFile)
         assertTrue(apiFile.exists())
         val actual = apiFile.readText(Charsets.UTF_8)
diff --git a/src/test/java/com/android/tools/metalava/AnnotationsMergerTest.kt b/src/test/java/com/android/tools/metalava/AnnotationsMergerTest.kt
index 654ed1a..003e7ba 100644
--- a/src/test/java/com/android/tools/metalava/AnnotationsMergerTest.kt
+++ b/src/test/java/com/android/tools/metalava/AnnotationsMergerTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.tools.metalava
 
+import com.android.tools.metalava.model.SUPPORT_TYPE_USE_ANNOTATIONS
 import org.junit.Test
 
 class AnnotationsMergerTest : DriverTest() {
@@ -50,8 +51,8 @@
                 ),
                 uiThreadSource,
                 intRangeAnnotationSource,
-                supportNonNullSource,
-                supportNullableSource
+                androidxNonNullSource,
+                androidxNullableSource
             ),
             // Skip the annotations themselves from the output
             extraArguments = arrayOf(
@@ -162,14 +163,25 @@
                         // Is expected to return self
                         return: @libcore.util.NonNull
                 """,
-            api = """
-                package test.pkg {
-                  public interface Appendable {
-                    method @androidx.annotation.NonNull public test.pkg.Appendable append(@androidx.annotation.Nullable java.lang.CharSequence);
-                    method public java.lang.String reverse(java.lang.String);
-                  }
-                }
+            api = if (SUPPORT_TYPE_USE_ANNOTATIONS) {
                 """
+                    package test.pkg {
+                      public interface Appendable {
+                        method @androidx.annotation.NonNull public test.pkg.Appendable append(@androidx.annotation.Nullable java.lang.CharSequence);
+                        method public java.lang.String reverse(java.lang.String);
+                      }
+                    }
+                   """
+            } else {
+                """
+                    package test.pkg {
+                      public interface Appendable {
+                        method @androidx.annotation.NonNull public test.pkg.Appendable append(java.lang.CharSequence);
+                        method public java.lang.String reverse(java.lang.String);
+                      }
+                    }
+                   """
+            }
         )
     }
 
diff --git a/src/test/java/com/android/tools/metalava/ApiFileTest.kt b/src/test/java/com/android/tools/metalava/ApiFileTest.kt
index abd3c1d..387c24e 100644
--- a/src/test/java/com/android/tools/metalava/ApiFileTest.kt
+++ b/src/test/java/com/android/tools/metalava/ApiFileTest.kt
@@ -157,7 +157,7 @@
                     package test.pkg
 
                     class Foo {
-                        fun error(int: Int = 42, int2: Int? = null, byte: Int = 42) { }
+                        fun error(int: Int = 42, int2: Int? = null, byte: Int = 42, vararg args: String) { }
                     }
                     """
                 )
@@ -166,7 +166,7 @@
                 package test.pkg {
                   public final class Foo {
                     ctor public Foo();
-                    method public void error(int p = "42", Integer? int2 = "null", int p1 = "42");
+                    method public void error(int p = "42", Integer? int2 = "null", int p1 = "42", java.lang.String... args);
                   }
                 }
                 """,
@@ -381,8 +381,8 @@
                     inline operator fun <F, S> PlatformJavaPair<F, S>.component1() = first
                     """
                 ),
-                supportNonNullSource,
-                supportNullableSource
+                androidxNonNullSource,
+                androidxNullableSource
             ),
             api = """
                 package androidx.util {
@@ -971,6 +971,42 @@
     }
 
     @Test
+    fun `Warn about findViewById`() {
+        // Include as many modifiers as possible to see which ones are included
+        // in the signature files, and the expected sorting order.
+        // Note that the signature files treat "deprecated" as a fake modifier.
+        // Note also how the "protected" modifier on the interface method gets
+        // promoted to public.
+        check(
+            checkDoclava1 = true,
+            compatibilityMode = false,
+            outputKotlinStyleNulls = false,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    import android.annotation.Nullable;
+
+                    @SuppressWarnings("ALL")
+                    public abstract class Foo {
+                        @Nullable public String findViewById(int id) { return ""; }
+                    }
+                    """
+                ),
+                nullableSource
+            ),
+            api = """
+                package test.pkg {
+                  public abstract class Foo {
+                    ctor public Foo();
+                    method public String findViewById(int);
+                  }
+                }
+                """
+        )
+    }
+
+    @Test
     fun `Check all modifiers`() {
         // Include as many modifiers as possible to see which ones are included
         // in the signature files, and the expected sorting order.
diff --git a/src/test/java/com/android/tools/metalava/ApiFromTextTest.kt b/src/test/java/com/android/tools/metalava/ApiFromTextTest.kt
index 7e9dcbd..70d8020 100644
--- a/src/test/java/com/android/tools/metalava/ApiFromTextTest.kt
+++ b/src/test/java/com/android/tools/metalava/ApiFromTextTest.kt
@@ -43,6 +43,111 @@
     }
 
     @Test
+    fun `Annotation signatures requiring more complicated token matching`() {
+        val source = """
+                package test {
+                  public class MyTest {
+                    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean addAccountExplicitly(android.accounts.Account, String, android.os.Bundle);
+                    method @CheckResult(suggest="#enforceCallingOrSelfPermission(String,\"foo\",String)") public abstract int checkCallingOrSelfPermission(@NonNull String);
+                    method @RequiresPermission(anyOf={"android.permission.MANAGE_ACCOUNTS", "android.permission.USE_CREDENTIALS"}, apis="..22") public void invalidateAuthToken(String, String);
+                  }
+                }
+                """
+        check(
+            compatibilityMode = false,
+            outputKotlinStyleNulls = false,
+            signatureSource = source,
+            api = source
+        )
+    }
+
+    @Test
+    fun `Multiple extends`() {
+        val source = """
+                package test {
+                  public static interface PickConstructors extends test.pkg.PickConstructors.AutoCloseable {
+                  }
+                  public interface XmlResourceParser extends org.xmlpull.v1.XmlPullParser android.util.AttributeSet java.lang.AutoCloseable {
+                    method public void close();
+                  }
+                }
+                """
+        check(
+            compatibilityMode = false,
+            outputKotlinStyleNulls = false,
+            signatureSource = source,
+            api = source
+        )
+    }
+
+    @Test
+    fun `Native and strictfp keywords`() {
+        val source = """
+                package test.pkg {
+                  public class MyTest {
+                    method public native float dotWithNormal(float, float, float);
+                    method public static strictfp double toDegrees(double);
+                  }
+                }
+                """
+        check(
+            compatibilityMode = false,
+            outputKotlinStyleNulls = false,
+            signatureSource = source,
+            api = source
+        )
+    }
+
+    @Test
+    fun `Type use annotations`() {
+        check(
+            compatibilityMode = false,
+            outputKotlinStyleNulls = false,
+            signatureSource = """
+                package test.pkg {
+                  public class MyTest {
+                    method public static int codePointAt(char @NonNull [], int);
+                    method @NonNull public java.util.Set<java.util.Map.@NonNull Entry<K,V>> entrySet();
+                    method @NonNull public java.lang.annotation.@NonNull Annotation @NonNull [] getAnnotations();
+                    method @NonNull public abstract java.lang.annotation.@NonNull Annotation @NonNull [] @NonNull [] getParameterAnnotations();
+                    method @NonNull public @NonNull String @NonNull [] split(@NonNull String, int);
+                    method public static char @NonNull [] toChars(int);
+                  }
+                }
+                """,
+            api = """
+                package test.pkg {
+                  public class MyTest {
+                    method public static int codePointAt(char @NonNull [], int);
+                    method @NonNull public java.util.Set<java.util.Map.@NonNull Entry<K,V>> entrySet();
+                    method @NonNull public java.lang.annotation.Annotation @NonNull [] getAnnotations();
+                    method @NonNull public abstract java.lang.annotation.Annotation @NonNull [] @NonNull [] getParameterAnnotations();
+                    method @NonNull public String @NonNull [] split(@NonNull String, int);
+                    method public static char @NonNull [] toChars(int);
+                  }
+                }
+            """
+        )
+    }
+
+    @Test
+    fun `Vararg modifier`() {
+        val source = """
+                package test.pkg {
+                  public final class Foo {
+                    ctor public Foo();
+                    method public void error(int p = "42", Integer int2 = "null", int p1 = "42", vararg String args);
+                  }
+                }
+                """
+        check(
+            compatibilityMode = false,
+            outputKotlinStyleNulls = false,
+            signatureSource = source
+        )
+    }
+
+    @Test
     fun `Infer fully qualified names from shorter names`() {
         check(
             compatibilityMode = true,
@@ -354,4 +459,25 @@
             api = source
         )
     }
+
+    @Test
+    fun `Signatures with default annotation method values`() {
+        val source = """
+                package libcore.util {
+                  public @interface NonNull {
+                    method public abstract int from() default java.lang.Integer.MIN_VALUE;
+                    method public abstract double fromWithCast() default (double)java.lang.Float.NEGATIVE_INFINITY;
+                    method public abstract String! myString() default "This is a \"string\"";
+                    method public abstract int to() default java.lang.Integer.MAX_VALUE;
+                  }
+                }
+                """
+
+        check(
+            inputKotlinStyleNulls = true,
+            compatibilityMode = false,
+            signatureSource = source,
+            api = source
+        )
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/metalava/DocAnalyzerTest.kt b/src/test/java/com/android/tools/metalava/DocAnalyzerTest.kt
index f8ad6ec..0b5b239 100644
--- a/src/test/java/com/android/tools/metalava/DocAnalyzerTest.kt
+++ b/src/test/java/com/android/tools/metalava/DocAnalyzerTest.kt
@@ -102,7 +102,7 @@
                  * to be a String resource reference (e.g.&nbsp;{@code android.R.string.ok}).
                  */
                 @SuppressWarnings({"unchecked", "deprecation", "all"})
-                public @interface StringRes {
+                @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.LOCAL_VARIABLE}) public @interface StringRes {
                 }
                 """
             )
diff --git a/src/test/java/com/android/tools/metalava/DriverTest.kt b/src/test/java/com/android/tools/metalava/DriverTest.kt
index 13ad8cd..1449791 100644
--- a/src/test/java/com/android/tools/metalava/DriverTest.kt
+++ b/src/test/java/com/android/tools/metalava/DriverTest.kt
@@ -219,7 +219,12 @@
         /** Map from artifact id to artifact descriptor */
         artifacts: Map<String, String>? = null,
         /** Extract annotations and check that the given packages contain the given extracted XML files */
-        extractAnnotations: Map<String, String>? = null
+        extractAnnotations: Map<String, String>? = null,
+        /**
+         * Whether to include source retention annotations in the stubs (in that case they do not
+         * go into the extracted annotations zip file)
+         */
+        includeSourceRetentionAnnotations: Boolean = true
     ) {
         System.setProperty("METALAVA_TESTS_RUNNING", VALUE_TRUE)
 
@@ -407,7 +412,14 @@
             if (showUnannotated) {
                 arrayOf("--show-unannotated")
             } else {
-                emptyArray<String>()
+                emptyArray()
+            }
+
+        val includeSourceRetentionAnnotationArgs =
+            if (includeSourceRetentionAnnotations) {
+                arrayOf("--include-source-retention")
+            } else {
+                emptyArray()
             }
 
         var removedApiFile: File? = null
@@ -606,6 +618,7 @@
             *applyApiLevelsXmlArgs,
             *showAnnotationArguments,
             *showUnannotatedArgs,
+            *includeSourceRetentionAnnotationArgs,
             *sdkFilesArgs,
             *importedPackageArgs.toTypedArray(),
             *skipEmitPackagesArgs.toTypedArray(),
@@ -1310,8 +1323,16 @@
         String[] allOf() default {};
         String[] anyOf() default {};
         boolean conditional() default false;
+        @Target({FIELD, METHOD, PARAMETER})
+        @interface Read {
+            RequiresPermission value() default @RequiresPermission;
+        }
+        @Target({FIELD, METHOD, PARAMETER})
+        @interface Write {
+            RequiresPermission value() default @RequiresPermission;
+        }
     }
-                    """
+    """
 ).indented()
 
 val requiresFeatureSource: TestFile = java(
@@ -1325,7 +1346,7 @@
     public @interface RequiresFeature {
         String value();
     }
-            """
+    """
 ).indented()
 
 val requiresApiSource: TestFile = java(
@@ -1340,7 +1361,7 @@
         int value() default 1;
         int api() default 1;
     }
-            """
+    """
 ).indented()
 
 val sdkConstantSource: TestFile = java(
@@ -1355,23 +1376,23 @@
         }
         SdkConstantType value();
     }
-        """
+    """
 ).indented()
 
 val broadcastBehaviorSource: TestFile = java(
     """
-        package android.annotation;
-        import java.lang.annotation.*;
-        /** @hide */
-        @Target({ ElementType.FIELD })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface BroadcastBehavior {
-            boolean explicitOnly() default false;
-            boolean registeredOnly() default false;
-            boolean includeBackground() default false;
-            boolean protectedBroadcast() default false;
-        }
-        """
+    package android.annotation;
+    import java.lang.annotation.*;
+    /** @hide */
+    @Target({ ElementType.FIELD })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BroadcastBehavior {
+        boolean explicitOnly() default false;
+        boolean registeredOnly() default false;
+        boolean includeBackground() default false;
+        boolean protectedBroadcast() default false;
+    }
+    """
 ).indented()
 
 val nullableSource: TestFile = java(
@@ -1396,7 +1417,7 @@
 
 val supportNonNullSource: TestFile = java(
     """
-    package androidx.annotation;
+    package android.support.annotation;
     import java.lang.annotation.*;
     import static java.lang.annotation.ElementType.*;
     import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -1410,17 +1431,17 @@
 
 val supportNullableSource: TestFile = java(
     """
-package androidx.annotation;
-import java.lang.annotation.*;
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-@SuppressWarnings("WeakerAccess")
-@Retention(SOURCE)
-@Target({METHOD, PARAMETER, FIELD, TYPE_USE})
-public @interface Nullable {
-}
-                """
-)
+    package android.support.annotation;
+    import java.lang.annotation.*;
+    import static java.lang.annotation.ElementType.*;
+    import static java.lang.annotation.RetentionPolicy.SOURCE;
+    @SuppressWarnings("WeakerAccess")
+    @Retention(SOURCE)
+    @Target({METHOD, PARAMETER, FIELD, TYPE_USE})
+    public @interface Nullable {
+    }
+    """
+).indented()
 
 val androidxNonNullSource: TestFile = java(
     """
@@ -1438,17 +1459,45 @@
 
 val androidxNullableSource: TestFile = java(
     """
-package androidx.annotation;
-import java.lang.annotation.*;
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-@SuppressWarnings("WeakerAccess")
-@Retention(SOURCE)
-@Target({METHOD, PARAMETER, FIELD, TYPE_USE})
-public @interface Nullable {
-}
-                """
-)
+    package androidx.annotation;
+    import java.lang.annotation.*;
+    import static java.lang.annotation.ElementType.*;
+    import static java.lang.annotation.RetentionPolicy.SOURCE;
+    @SuppressWarnings("WeakerAccess")
+    @Retention(SOURCE)
+    @Target({METHOD, PARAMETER, FIELD, TYPE_USE})
+    public @interface Nullable {
+    }
+    """
+).indented()
+
+val recentlyNonNullSource: TestFile = java(
+    """
+    package androidx.annotation;
+    import java.lang.annotation.*;
+    import static java.lang.annotation.ElementType.*;
+    import static java.lang.annotation.RetentionPolicy.SOURCE;
+    @SuppressWarnings("WeakerAccess")
+    @Retention(SOURCE)
+    @Target({METHOD, PARAMETER, FIELD, TYPE_USE})
+    public @interface RecentlyNonNull {
+    }
+    """
+).indented()
+
+val recentlyNullableSource: TestFile = java(
+    """
+    package androidx.annotation;
+    import java.lang.annotation.*;
+    import static java.lang.annotation.ElementType.*;
+    import static java.lang.annotation.RetentionPolicy.SOURCE;
+    @SuppressWarnings("WeakerAccess")
+    @Retention(SOURCE)
+    @Target({METHOD, PARAMETER, FIELD, TYPE_USE})
+    public @interface RecentlyNullable {
+    }
+    """
+).indented()
 
 val supportParameterName: TestFile = java(
     """
@@ -1527,17 +1576,17 @@
 
 val suppressLintSource: TestFile = java(
     """
-package android.annotation;
+    package android.annotation;
 
-import static java.lang.annotation.ElementType.*;
-import java.lang.annotation.*;
-@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
-@Retention(RetentionPolicy.CLASS)
-public @interface SuppressLint {
-    String[] value();
-}
-                """
-)
+    import static java.lang.annotation.ElementType.*;
+    import java.lang.annotation.*;
+    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+    @Retention(RetentionPolicy.CLASS)
+    public @interface SuppressLint {
+        String[] value();
+    }
+    """
+).indented()
 
 val systemServiceSource: TestFile = java(
     """
diff --git a/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt b/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt
index 427e41d..5a8ee6f 100644
--- a/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt
+++ b/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt
@@ -25,9 +25,10 @@
     @Test
     fun `Check java typedef extraction and warning about non-source retention of typedefs`() {
         check(
+            includeSourceRetentionAnnotations = false,
             sourceFiles = *arrayOf(
                 java(
-            """
+                    """
                     package test.pkg;
 
                     import android.annotation.IntDef;
@@ -75,7 +76,8 @@
                 intRangeAnnotationSource
             ),
             warnings = "src/test/pkg/IntDefTest.java:11: error: This typedef annotation class should have @Retention(RetentionPolicy.SOURCE) [AnnotationExtraction:146]",
-            extractAnnotations = mapOf("test.pkg" to """
+            extractAnnotations = mapOf(
+                "test.pkg" to """
                 <?xml version="1.0" encoding="UTF-8"?>
                 <root>
                   <item name="test.pkg.IntDefTest void setFlags(java.lang.Object, int) 1">
@@ -104,6 +106,7 @@
     @Test
     fun `Check Kotlin and referencing hidden constants from typedef`() {
         check(
+            includeSourceRetentionAnnotations = false,
             sourceFiles = *arrayOf(
                 kotlin(
                     """
@@ -151,24 +154,187 @@
                 longDefAnnotationSource
             ),
             warnings = "src/test/pkg/LongDefTest.kt:12: error: Typedef class references hidden field field LongDefTestKt.HIDDEN: removed from typedef metadata [HiddenTypedefConstant:148]",
-            extractAnnotations = mapOf("test.pkg" to """
+            extractAnnotations = mapOf(
+                "test.pkg" to """
+                    <?xml version="1.0" encoding="UTF-8"?>
+                    <root>
+                      <item name="test.pkg.LongDefTest void setFlags(java.lang.Object, int) 0">
+                        <annotation name="androidx.annotation.NonNull"/>
+                      </item>
+                      <item name="test.pkg.LongDefTest void setFlags(java.lang.Object, int) 1">
+                        <annotation name="androidx.annotation.LongDef">
+                          <val name="flag" val="true" />
+                          <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT, 3, 4}" />
+                        </annotation>
+                      </item>
+                      <item name="test.pkg.LongDefTest void setStyle(int, int) 0">
+                        <annotation name="androidx.annotation.LongDef">
+                          <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT}" />
+                        </annotation>
+                      </item>
+                      <item name="test.pkg.LongDefTest.Inner boolean isNull(java.lang.String) 0">
+                        <annotation name="androidx.annotation.Nullable"/>
+                      </item>
+                      <item name="test.pkg.LongDefTest.Inner void setInner(int) 0">
+                        <annotation name="androidx.annotation.LongDef">
+                          <val name="flag" val="true" />
+                          <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT, 3, 4}" />
+                        </annotation>
+                      </item>
+                      <item name="test.pkg.LongDefTestKt TYPE_1">
+                        <annotation name="androidx.annotation.NonNull"/>
+                      </item>
+                      <item name="test.pkg.LongDefTestKt TYPE_2">
+                        <annotation name="androidx.annotation.NonNull"/>
+                      </item>
+                      <item name="test.pkg.LongDefTestKt UNRELATED_TYPE">
+                        <annotation name="androidx.annotation.NonNull"/>
+                      </item>
+                    </root>
+                """
+            )
+        )
+    }
+
+    @Test
+    fun `Check including only class retention annotations other than typedefs`() {
+        check(
+            includeSourceRetentionAnnotations = true,
+            sourceFiles = *arrayOf(
+                kotlin(
+                    """
+                    @file:Suppress("unused", "UseExpressionBody")
+
+                    package test.pkg
+
+                    import android.annotation.LongDef
+
+                    const val STYLE_NORMAL = 0L
+                    const val STYLE_NO_TITLE = 1L
+                    const val STYLE_NO_FRAME = 2L
+                    const val STYLE_NO_INPUT = 3L
+                    const val UNRELATED = 3L
+                    private const val HIDDEN = 4
+
+                    const val TYPE_1 = "type1"
+                    const val TYPE_2 = "type2"
+                    const val UNRELATED_TYPE = "other"
+
+                    class LongDefTest {
+
+                        /** @hide */
+                        @LongDef(STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT, HIDDEN)
+                        @Retention(AnnotationRetention.SOURCE)
+                        private annotation class DialogStyle
+
+                        fun setStyle(@DialogStyle style: Int, theme: Int) {}
+
+                        fun testLongDef(arg: Int) {
+                        }
+
+                        @LongDef(STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT, 3L, 3L + 1L, flag = true)
+                        @Retention(AnnotationRetention.SOURCE)
+                        private annotation class DialogFlags
+
+                        fun setFlags(first: Any, @DialogFlags flags: Int) {}
+
+                        class Inner {
+                            fun setInner(@DialogFlags flags: Int) {}
+                            fun isNull(value: String?): Boolean
+                        }
+                    }"""
+                ).indented(),
+                longDefAnnotationSource
+            ),
+            warnings = "src/test/pkg/LongDefTest.kt:12: error: Typedef class references hidden field field LongDefTestKt.HIDDEN: removed from typedef metadata [HiddenTypedefConstant:148]",
+            extractAnnotations = mapOf(
+                "test.pkg" to """
+                    <?xml version="1.0" encoding="UTF-8"?>
+                    <root>
+                      <item name="test.pkg.LongDefTest void setFlags(java.lang.Object, int) 1">
+                        <annotation name="androidx.annotation.LongDef">
+                          <val name="flag" val="true" />
+                          <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT, 3, 4}" />
+                        </annotation>
+                      </item>
+                      <item name="test.pkg.LongDefTest void setStyle(int, int) 0">
+                        <annotation name="androidx.annotation.LongDef">
+                          <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT}" />
+                        </annotation>
+                      </item>
+                      <item name="test.pkg.LongDefTest.Inner void setInner(int) 0">
+                        <annotation name="androidx.annotation.LongDef">
+                          <val name="flag" val="true" />
+                          <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT, 3, 4}" />
+                        </annotation>
+                      </item>
+                    </root>
+                """
+            )
+        )
+    }
+
+    @Test
+    fun `Extract permission annotations`() {
+        check(
+            includeSourceRetentionAnnotations = false,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+
+                    import android.annotation.RequiresPermission;
+
+                    public class PermissionsTest {
+                        @RequiresPermission(Manifest.permission.MY_PERMISSION)
+                        public void myMethod() {
+                        }
+                        @RequiresPermission(anyOf={Manifest.permission.MY_PERMISSION,Manifest.permission.MY_PERMISSION2})
+                        public void myMethod2() {
+                        }
+
+                        @RequiresPermission.Read(@RequiresPermission(Manifest.permission.MY_READ_PERMISSION))
+                        @RequiresPermission.Write(@RequiresPermission(Manifest.permission.MY_WRITE_PERMISSION))
+                        public static final String CONTENT_URI = "";
+                    }
+                    """
+                ).indented(),
+                java(
+                    """
+                    package test.pkg;
+
+                    public class Manifest {
+                        public static final class permission {
+                            public static final String MY_PERMISSION = "android.permission.MY_PERMISSION_STRING";
+                            public static final String MY_PERMISSION2 = "android.permission.MY_PERMISSION_STRING2";
+                            public static final String MY_READ_PERMISSION = "android.permission.MY_READ_PERMISSION_STRING";
+                            public static final String MY_WRITE_PERMISSION = "android.permission.MY_WRITE_PERMISSION_STRING";
+                        }
+                    }
+                    """
+                ).indented(),
+                requiresPermissionSource
+            ),
+            extractAnnotations = mapOf(
+                "test.pkg" to """
                 <?xml version="1.0" encoding="UTF-8"?>
                 <root>
-                  <item name="test.pkg.LongDefTest void setFlags(java.lang.Object, int) 1">
-                    <annotation name="androidx.annotation.LongDef">
-                      <val name="flag" val="true" />
-                      <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT, 3, 4}" />
+                  <item name="test.pkg.PermissionsTest CONTENT_URI">
+                    <annotation name="androidx.annotation.RequiresPermission.Read">
+                      <val name="value" val="&quot;android.permission.MY_READ_PERMISSION_STRING&quot;" />
+                    </annotation>
+                    <annotation name="androidx.annotation.RequiresPermission.Write">
+                      <val name="value" val="&quot;android.permission.MY_WRITE_PERMISSION_STRING&quot;" />
                     </annotation>
                   </item>
-                  <item name="test.pkg.LongDefTest void setStyle(int, int) 0">
-                    <annotation name="androidx.annotation.LongDef">
-                      <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT}" />
+                  <item name="test.pkg.PermissionsTest void myMethod()">
+                    <annotation name="androidx.annotation.RequiresPermission">
+                      <val name="value" val="&quot;android.permission.MY_PERMISSION_STRING&quot;" />
                     </annotation>
                   </item>
-                  <item name="test.pkg.LongDefTest.Inner void setInner(int) 0">
-                    <annotation name="androidx.annotation.LongDef">
-                      <val name="flag" val="true" />
-                      <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT, 3, 4}" />
+                  <item name="test.pkg.PermissionsTest void myMethod2()">
+                    <annotation name="androidx.annotation.RequiresPermission">
+                      <val name="anyOf" val="{&quot;android.permission.MY_PERMISSION_STRING&quot;, &quot;android.permission.MY_PERMISSION_STRING2&quot;}" />
                     </annotation>
                   </item>
                 </root>
@@ -181,6 +347,7 @@
     @Test
     fun `Include merged annotations in exported source annotations`() {
         check(
+            includeSourceRetentionAnnotations = true,
             compatibilityMode = false,
             outputKotlinStyleNulls = false,
             includeSystemApiAnnotations = false,
@@ -205,7 +372,8 @@
                   </item>
                 </root>
                 """,
-            extractAnnotations = mapOf("test.pkg" to """
+            extractAnnotations = mapOf(
+                "test.pkg" to """
                 <?xml version="1.0" encoding="UTF-8"?>
                 <root>
                   <item name="test.pkg.MyTest void test(int) 0">
@@ -218,4 +386,43 @@
             )
         )
     }
+
+    @Test
+    fun `Only including class retention annotations in stubs`() {
+        check(
+            includeSourceRetentionAnnotations = false,
+            compatibilityMode = false,
+            outputKotlinStyleNulls = false,
+            includeSystemApiAnnotations = false,
+            omitCommonPackages = false,
+            sourceFiles =
+            *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    import android.annotation.IntRange;
+                    import androidx.annotation.RecentlyNullable;
+                    public class Test {
+                        @RecentlyNullable
+                        public static String sayHello(@IntRange(from = 10) int value) { return "hello " + value; }
+                    }
+                    """
+                ),
+                intRangeAnnotationSource,
+                recentlyNullableSource
+            ),
+            extractAnnotations = mapOf(
+                "test.pkg" to """
+                    <?xml version="1.0" encoding="UTF-8"?>
+                    <root>
+                      <item name="test.pkg.Test java.lang.String sayHello(int) 0">
+                        <annotation name="androidx.annotation.IntRange">
+                          <val name="from" val="10" />
+                        </annotation>
+                      </item>
+                    </root>
+                """
+            )
+        )
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/metalava/NullnessMigrationTest.kt b/src/test/java/com/android/tools/metalava/NullnessMigrationTest.kt
index 0557168..6c1e2ef 100644
--- a/src/test/java/com/android/tools/metalava/NullnessMigrationTest.kt
+++ b/src/test/java/com/android/tools/metalava/NullnessMigrationTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.tools.metalava
 
+import com.android.tools.metalava.model.SUPPORT_TYPE_USE_ANNOTATIONS
 import org.junit.Test
 
 class NullnessMigrationTest : DriverTest() {
@@ -237,8 +238,8 @@
             api = """
                     package libcore.util {
                       public @interface NonNull {
-                        method public abstract int from();
-                        method public abstract int to();
+                        method public abstract int from() default java.lang.Integer.MIN_VALUE;
+                        method public abstract int to() default java.lang.Integer.MAX_VALUE;
                       }
                     }
                     package test.pkg {
@@ -273,11 +274,12 @@
                     }
                     """
                 ),
-                supportNonNullSource,
-                supportNullableSource
+                androidxNonNullSource,
+                androidxNullableSource
             ),
             extraArguments = arrayOf("--hide-package", "androidx.annotation"),
-            api = """
+            api = if (SUPPORT_TYPE_USE_ANNOTATIONS) {
+                """
                 package test.pkg {
                   public class Test {
                     ctor public Test();
@@ -286,6 +288,17 @@
                   }
                 }
                 """
+            } else {
+                """
+                package test.pkg {
+                  public class Test {
+                    ctor public Test();
+                    method @Nullable public Integer compute1(@Nullable java.util.List<java.lang.String>);
+                    method @Nullable public Integer compute2(@Nullable java.util.List<java.util.List<?>>);
+                  }
+                }
+                """
+            }
         )
     }
 
@@ -315,7 +328,8 @@
                 androidxNullableSource
             ),
             extraArguments = arrayOf("--hide-package", "androidx.annotation"),
-            api = """
+            api = if (SUPPORT_TYPE_USE_ANNOTATIONS) {
+                """
                 package test.pkg {
                   public class Test {
                     ctor public Test();
@@ -324,6 +338,17 @@
                   }
                 }
                 """
+            } else {
+                """
+                package test.pkg {
+                  public class Test {
+                    ctor public Test();
+                    method @Nullable public Integer compute1(@Nullable java.util.List<java.lang.String>);
+                    method @Nullable public Integer compute2(@NonNull java.util.List<java.util.List<?>>);
+                  }
+                }
+                """
+            }
         )
     }
 
@@ -362,18 +387,33 @@
                   }
                 }
                 """,
-            stubs = arrayOf(
-                """
-                package test.pkg;
-                @SuppressWarnings({"unchecked", "deprecation", "all"})
-                public class Foo {
-                public Foo() { throw new RuntimeException("Stub!"); }
-                public static char @androidx.annotation.RecentlyNonNull [] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
-                public static int codePointAt(char @androidx.annotation.RecentlyNonNull [] a, int index) { throw new RuntimeException("Stub!"); }
-                public <T> T @androidx.annotation.RecentlyNonNull [] toArray(T @androidx.annotation.RecentlyNonNull [] a) { throw new RuntimeException("Stub!"); }
-                }
-                """
-            )
+            stubs = if (SUPPORT_TYPE_USE_ANNOTATIONS) {
+                arrayOf(
+                    """
+                    package test.pkg;
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class Foo {
+                    public Foo() { throw new RuntimeException("Stub!"); }
+                    public static char @androidx.annotation.RecentlyNonNull [] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
+                    public static int codePointAt(char @androidx.annotation.RecentlyNonNull [] a, int index) { throw new RuntimeException("Stub!"); }
+                    public <T> T @androidx.annotation.RecentlyNonNull [] toArray(T @androidx.annotation.RecentlyNonNull [] a) { throw new RuntimeException("Stub!"); }
+                    }
+                    """
+                )
+            } else {
+                arrayOf(
+                    """
+                    package test.pkg;
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class Foo {
+                    public Foo() { throw new RuntimeException("Stub!"); }
+                    public static char[] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
+                    public static int codePointAt(char[] a, int index) { throw new RuntimeException("Stub!"); }
+                    public <T> T[] toArray(T[] a) { throw new RuntimeException("Stub!"); }
+                    }
+                    """
+                )
+            }
         )
     }
 
@@ -412,18 +452,33 @@
                   }
                 }
                 """,
-            stubs = arrayOf(
-                """
-                package test.pkg;
-                @SuppressWarnings({"unchecked", "deprecation", "all"})
-                public class Foo {
-                public Foo() { throw new RuntimeException("Stub!"); }
-                public static char @androidx.annotation.RecentlyNonNull [] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
-                public static int codePointAt(char @androidx.annotation.RecentlyNonNull [] a, int index) { throw new RuntimeException("Stub!"); }
-                public <T> T @androidx.annotation.RecentlyNonNull [] toArray(T @androidx.annotation.RecentlyNonNull [] a) { throw new RuntimeException("Stub!"); }
-                }
-                """
-            )
+            stubs = if (SUPPORT_TYPE_USE_ANNOTATIONS) {
+                arrayOf(
+                    """
+                    package test.pkg;
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class Foo {
+                    public Foo() { throw new RuntimeException("Stub!"); }
+                    public static char @androidx.annotation.RecentlyNonNull [] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
+                    public static int codePointAt(char @androidx.annotation.RecentlyNonNull [] a, int index) { throw new RuntimeException("Stub!"); }
+                    public <T> T @androidx.annotation.RecentlyNonNull [] toArray(T @androidx.annotation.RecentlyNonNull [] a) { throw new RuntimeException("Stub!"); }
+                    }
+                    """
+                )
+            } else {
+                arrayOf(
+                    """
+                    package test.pkg;
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class Foo {
+                    public Foo() { throw new RuntimeException("Stub!"); }
+                    public static char[] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
+                    public static int codePointAt(char[] a, int index) { throw new RuntimeException("Stub!"); }
+                    public <T> T[] toArray(T[] a) { throw new RuntimeException("Stub!"); }
+                    }
+                    """
+                )
+            }
         )
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/metalava/OptionsTest.kt b/src/test/java/com/android/tools/metalava/OptionsTest.kt
index 7c79caa..5497e8a 100644
--- a/src/test/java/com/android/tools/metalava/OptionsTest.kt
+++ b/src/test/java/com/android/tools/metalava/OptionsTest.kt
@@ -176,6 +176,15 @@
 Extracting Annotations:
 --extract-annotations <zipfile>        Extracts source annotations from the source files
                                        and writes them into the given zip file
+--include-annotation-classes <dir>     Copies the given stub annotation source files into
+                                       the generated stub sources; <dir> is typically
+                                       metalava/stub-annotations/src/main/java/.
+--rewrite-annotations <dir/jar>        For a bytecode folder or output jar, rewrites the
+                                       androidx annotations to be package private
+--include-source-retention             If true, include source-retention annotations in
+                                       the stub files. Does not apply to signature files.
+                                       Source retention annotations are extracted into the
+                                       external annotations files instead.
 
 Injecting API Levels:
 --apply-api-levels <api-versions.xml>  Reads an XML file containing API level descriptions
diff --git a/src/test/java/com/android/tools/metalava/RewriteAnnotationsTest.kt b/src/test/java/com/android/tools/metalava/RewriteAnnotationsTest.kt
new file mode 100644
index 0000000..1f96736
--- /dev/null
+++ b/src/test/java/com/android/tools/metalava/RewriteAnnotationsTest.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.metalava
+
+import com.android.tools.lint.checks.infrastructure.TestFiles.base64gzip
+import com.android.tools.lint.checks.infrastructure.TestFiles.jar
+import com.android.tools.lint.checks.infrastructure.TestFiles.xml
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import java.io.File
+import java.lang.reflect.Modifier
+import java.net.URLClassLoader
+
+class RewriteAnnotationsTest : DriverTest() {
+    @Test
+    fun `Test copying private annotations from one of the stubs`() {
+        val source = File("stub-annotations/src/main/java/androidx/annotation".replace('/', File.separatorChar))
+        assertTrue(source.path, source.isDirectory)
+        val target = temporaryFolder.newFolder()
+        runDriver(
+            "--no-color",
+            "--no-banner",
+
+            "--copy-annotations",
+            source.path,
+            target.path
+        )
+
+        val converted = File(target, "CallSuper.java")
+        assertTrue("${converted.path} doesn't exist", converted.isFile)
+        assertEquals(
+            """
+            /*
+             * Copyright (C) 2015 The Android Open Source Project
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *      http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+            package androidx.annotation;
+
+            import static java.lang.annotation.ElementType.METHOD;
+            import static java.lang.annotation.RetentionPolicy.CLASS;
+
+            import java.lang.annotation.Retention;
+            import java.lang.annotation.Target;
+
+            /** Stub only annotation. Do not use directly. */
+            @Retention(CLASS)
+            @Target({METHOD})
+            @interface CallSuper {}
+        """.trimIndent().trim(), converted.readText(Charsets.UTF_8).trim().replace("\r\n", "\n")
+        )
+    }
+
+    @Test
+    fun `Test rewriting the bytecode for one of the public annotations`() {
+        val bytecode = base64gzip(
+            "androidx/annotation/CallSuper.class", "" +
+                "H4sIAAAAAAAAAIWPsU4CQRRF70NhEQWxJMZoLCjdxs6KIMYCA2E3NlbD8kKG" +
+                "DDNkmSXwaxZ+gB9FfGMBFps4yczc5J53kve9//wC8IirCK0IlxHahEbiijzj" +
+                "F22Y0OorY5JixfnDQm0UoTMprNdLftdrPTXcs9Z55bWza8LdMDCxUXYeq0MR" +
+                "T9izDemJUN0oU4i3+w86dkZnuzDQH/aShHBTPpCqfM5euPvyfmB4KcZ0t2KB" +
+                "am+D9HX0LDZlZ7nTs+1f9rAqoX2UjaYLzjzhttR/3L9LIFTkniCcCk5/3ypq" +
+                "8l9LiqSrM87QwHmIHyDGBZo/ObYRQoUBAAA="
+        )
+
+        val compiledStubs = temporaryFolder.newFolder("compiled-stubs")
+        bytecode.createFile(compiledStubs)
+
+        runDriver(
+            "--no-color",
+            "--no-banner",
+
+            "--rewrite-annotations",
+            compiledStubs.path
+        )
+
+        // Load the class to make sure it's legit
+        val url = compiledStubs.toURI().toURL()
+        val loader = URLClassLoader(arrayOf(url), null)
+        val annotationClass = loader.loadClass("androidx.annotation.CallSuper")
+        val modifiers = annotationClass.modifiers
+        assertEquals(0, modifiers and Modifier.PUBLIC)
+        assertTrue(annotationClass.isAnnotation)
+    }
+
+    @Test
+    fun `Test rewriting the bytecode for one of the public annotations in a jar file`() {
+        val bytecode = base64gzip(
+            "androidx/annotation/CallSuper.class", "" +
+                "H4sIAAAAAAAAAIWPsU4CQRRF70NhEQWxJMZoLCjdxs6KIMYCA2E3NlbD8kKG" +
+                "DDNkmSXwaxZ+gB9FfGMBFps4yczc5J53kve9//wC8IirCK0IlxHahEbiijzj" +
+                "F22Y0OorY5JixfnDQm0UoTMprNdLftdrPTXcs9Z55bWza8LdMDCxUXYeq0MR" +
+                "T9izDemJUN0oU4i3+w86dkZnuzDQH/aShHBTPpCqfM5euPvyfmB4KcZ0t2KB" +
+                "am+D9HX0LDZlZ7nTs+1f9rAqoX2UjaYLzjzhttR/3L9LIFTkniCcCk5/3ypq" +
+                "8l9LiqSrM87QwHmIHyDGBZo/ObYRQoUBAAA="
+        )
+
+        val jarDesc = jar(
+            "myjar.jar",
+            bytecode,
+            xml("foo/bar/baz.xml", "<hello-world/>")
+        )
+
+        val jarFile = jarDesc.createFile(temporaryFolder.root)
+
+        runDriver(
+            "--no-color",
+            "--no-banner",
+
+            "--rewrite-annotations",
+            jarFile.path
+        )
+
+        // Load the class to make sure it's legit
+        val url = jarFile.toURI().toURL()
+        val loader = URLClassLoader(arrayOf(url), null)
+        val annotationClass = loader.loadClass("androidx.annotation.CallSuper")
+        val modifiers = annotationClass.modifiers
+        assertEquals(0, modifiers and Modifier.PUBLIC)
+        assertTrue(annotationClass.isAnnotation)
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/metalava/StubsTest.kt b/src/test/java/com/android/tools/metalava/StubsTest.kt
index 5d7f7df..1edcbbf 100644
--- a/src/test/java/com/android/tools/metalava/StubsTest.kt
+++ b/src/test/java/com/android/tools/metalava/StubsTest.kt
@@ -19,6 +19,7 @@
 package com.android.tools.metalava
 
 import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.metalava.model.SUPPORT_TYPE_USE_ANNOTATIONS
 import org.intellij.lang.annotations.Language
 import org.junit.Test
 
@@ -36,6 +37,8 @@
         extraArguments: Array<String> = emptyArray(),
         docStubs: Boolean = false,
         showAnnotations: Array<String> = emptyArray(),
+        includeSourceRetentionAnnotations: Boolean = true,
+        skipEmitPackages: List<String> = listOf("java.lang", "java.util", "java.io"),
         vararg sourceFiles: TestFile
     ) {
         check(
@@ -48,7 +51,9 @@
             checkCompilation = true,
             api = api,
             extraArguments = extraArguments,
-            docStubs = docStubs
+            docStubs = docStubs,
+            includeSourceRetentionAnnotations = includeSourceRetentionAnnotations,
+            skipEmitPackages = skipEmitPackages
         )
     }
 
@@ -304,7 +309,7 @@
             source = """
                 package test.pkg;
                 @SuppressWarnings({"unchecked", "deprecation", "all"})
-                public @interface Foo {
+                @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface Foo {
                 public java.lang.String value();
                 }
                 """
@@ -1345,16 +1350,28 @@
                     """
                 )
             ),
-            api = """
+            api = if (SUPPORT_TYPE_USE_ANNOTATIONS) {
+                """
                 package test.pkg {
                   public class Foo {
                     ctor public Foo();
                     method public void foo(int, java.util.Map<java.lang.String, java.lang.String>!);
                   }
                 }
-                """,
+                """
+            } else {
+                """
+                package test.pkg {
+                  public class Foo {
+                    ctor public Foo();
+                    method public void foo(int, java.util.Map<java.lang.String,java.lang.String>!);
+                  }
+                }
+                """
+            },
 
-            source = """
+            source = if (SUPPORT_TYPE_USE_ANNOTATIONS) {
+                """
                 package test.pkg;
                 @SuppressWarnings({"unchecked", "deprecation", "all"})
                 public class Foo {
@@ -1362,6 +1379,16 @@
                 public void foo(int p1, java.util.Map<java.lang.String, java.lang.String> p2) { throw new RuntimeException("Stub!"); }
                 }
                 """
+            } else {
+                """
+                package test.pkg;
+                @SuppressWarnings({"unchecked", "deprecation", "all"})
+                public class Foo {
+                public Foo() { throw new RuntimeException("Stub!"); }
+                public void foo(int p1, java.util.Map<java.lang.String,java.lang.String> p2) { throw new RuntimeException("Stub!"); }
+                }
+                """
+            }
         )
     }
 
@@ -1764,15 +1791,27 @@
                       }
                     }
                     """,
-            stubs = arrayOf(
-                """
-                package my.pkg;
-                @SuppressWarnings({"unchecked", "deprecation", "all"})
-                public class String {
-                public String(char @androidx.annotation.NonNull [] value) { throw new RuntimeException("Stub!"); }
-                }
-                """
-            )
+            stubs = if (SUPPORT_TYPE_USE_ANNOTATIONS) {
+                arrayOf(
+                    """
+                    package my.pkg;
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class String {
+                    public String(char @androidx.annotation.NonNull [] value) { throw new RuntimeException("Stub!"); }
+                    }
+                    """
+                )
+            } else {
+                arrayOf(
+                    """
+                    package my.pkg;
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class String {
+                    public String(char[] value) { throw new RuntimeException("Stub!"); }
+                    }
+                    """
+                )
+            }
         )
     }
 
@@ -2013,28 +2052,53 @@
                       }
                     }
                     """,
-            source = """
-                    package test.pkg;
-                    @SuppressWarnings({"unchecked", "deprecation", "all"})
-                    public class Generics {
-                    public Generics() { throw new RuntimeException("Stub!"); }
-                    @SuppressWarnings({"unchecked", "deprecation", "all"})
-                    public class MyClass<X, Y extends java.lang.Number> extends test.pkg.Generics.PublicParent<X,Y> implements test.pkg.Generics.PublicInterface<X,Y> {
-                    public MyClass() { throw new RuntimeException("Stub!"); }
-                    public java.util.List<X> foo() { throw new RuntimeException("Stub!"); }
-                    public java.util.Map<X,java.util.Map<Y,java.lang.String>> createMap(java.util.List<X> list) throws java.io.IOException { throw new RuntimeException("Stub!"); }
-                    }
-                    @SuppressWarnings({"unchecked", "deprecation", "all"})
-                    public static interface PublicInterface<A, B> {
-                    public java.util.Map<A,java.util.Map<B,java.lang.String>> createMap(java.util.List<A> list) throws java.io.IOException;
-                    }
-                    @SuppressWarnings({"unchecked", "deprecation", "all"})
-                    public abstract class PublicParent<A, B extends java.lang.Number> {
-                    public PublicParent() { throw new RuntimeException("Stub!"); }
-                    protected abstract java.util.List<A> foo();
-                    }
-                    }
-                    """
+            source = if (SUPPORT_TYPE_USE_ANNOTATIONS) {
+                """
+            package test.pkg;
+            @SuppressWarnings({"unchecked", "deprecation", "all"})
+            public class Generics {
+            public Generics() { throw new RuntimeException("Stub!"); }
+            @SuppressWarnings({"unchecked", "deprecation", "all"})
+            public class MyClass<X, Y extends java.lang.Number> extends test.pkg.Generics.PublicParent<X,Y> implements test.pkg.Generics.PublicInterface<X,Y> {
+            public MyClass() { throw new RuntimeException("Stub!"); }
+            public java.util.List<X> foo() { throw new RuntimeException("Stub!"); }
+            public java.util.Map<X,java.util.Map<Y,java.lang.String>> createMap(java.util.List<X> list) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+            }
+            @SuppressWarnings({"unchecked", "deprecation", "all"})
+            public static interface PublicInterface<A, B> {
+            public java.util.Map<A,java.util.Map<B,java.lang.String>> createMap(java.util.List<A> list) throws java.io.IOException;
+            }
+            @SuppressWarnings({"unchecked", "deprecation", "all"})
+            public abstract class PublicParent<A, B extends java.lang.Number> {
+            public PublicParent() { throw new RuntimeException("Stub!"); }
+            protected abstract java.util.List<A> foo();
+            }
+            }
+            """
+            } else {
+                """
+            package test.pkg;
+            @SuppressWarnings({"unchecked", "deprecation", "all"})
+            public class Generics {
+            public Generics() { throw new RuntimeException("Stub!"); }
+            @SuppressWarnings({"unchecked", "deprecation", "all"})
+            public class MyClass<X, Y extends java.lang.Number> extends test.pkg.Generics.PublicParent<X,Y> implements test.pkg.Generics.PublicInterface<X,Y> {
+            public MyClass() { throw new RuntimeException("Stub!"); }
+            public java.util.List<X> foo() { throw new RuntimeException("Stub!"); }
+            public java.util.Map<X, java.util.Map<Y, java.lang.String>> createMap(java.util.List<X> list) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+            }
+            @SuppressWarnings({"unchecked", "deprecation", "all"})
+            public static interface PublicInterface<A, B> {
+            public java.util.Map<A, java.util.Map<B, java.lang.String>> createMap(java.util.List<A> list) throws java.io.IOException;
+            }
+            @SuppressWarnings({"unchecked", "deprecation", "all"})
+            public abstract class PublicParent<A, B extends java.lang.Number> {
+            public PublicParent() { throw new RuntimeException("Stub!"); }
+            protected abstract java.util.List<A> foo();
+            }
+            }
+            """
+            }
         )
     }
 
@@ -2292,8 +2356,8 @@
         )
     }
 
-    // TODO: Add a protected constructor too to make sure my code to make non-public constructors package private
-    // don't accidentally demote protected constructors to package private!
+// TODO: Add a protected constructor too to make sure my code to make non-public constructors package private
+// don't accidentally demote protected constructors to package private!
 
     @Test
     fun `Picking Super Constructors`() {
@@ -2959,6 +3023,208 @@
     }
 
     @Test
+    fun `Annotation default values`() {
+        checkStubs(
+            compatibilityMode = false,
+            sourceFiles =
+            *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+
+                    import java.lang.annotation.ElementType;
+                    import java.lang.annotation.Retention;
+                    import java.lang.annotation.RetentionPolicy;
+                    import java.lang.annotation.Target;
+
+                    import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+                    /**
+                     * This annotation can be used to mark fields and methods to be dumped by
+                     * the view server. Only non-void methods with no arguments can be annotated
+                     * by this annotation.
+                     */
+                    @Target({ElementType.FIELD, ElementType.METHOD})
+                    @Retention(RetentionPolicy.RUNTIME)
+                    public @interface ExportedProperty {
+                        /**
+                         * When resolveId is true, and if the annotated field/method return value
+                         * is an int, the value is converted to an Android's resource name.
+                         *
+                         * @return true if the property's value must be transformed into an Android
+                         * resource name, false otherwise
+                         */
+                        boolean resolveId() default false;
+                        String prefix() default "";
+                        String category() default "";
+                        boolean formatToHexString() default false;
+                        boolean hasAdjacentMapping() default false;
+                        Class<? extends Number> myCls() default Integer.class;
+                        char[] letters1() default {};
+                        char[] letters2() default {'a', 'b', 'c'};
+                        double from() default Double.NEGATIVE_INFINITY;
+                        double fromWithCast() default (double)Float.NEGATIVE_INFINITY;
+                        InnerAnnotation value() default @InnerAnnotation;
+                        char letter() default 'a';
+                        int integer() default 1;
+                        long large_integer() default 1L;
+                        float floating() default 1.0f;
+                        double large_floating() default 1.0;
+                        byte small() default 1;
+                        short medium() default 1;
+                        int math() default 1+2*3;
+                        @InnerAnnotation
+                        int unit() default PX;
+                        int DP = 0;
+                        int PX = 1;
+                        int SP = 2;
+                        @Retention(SOURCE)
+                        @interface InnerAnnotation {
+                        }
+                    }
+                    """
+                )
+            ),
+            warnings = "",
+            api = """
+                package test.pkg {
+                  public @interface ExportedProperty {
+                    method public abstract String! category() default "";
+                    method public abstract float floating() default 1.0f;
+                    method public abstract boolean formatToHexString() default false;
+                    method public abstract double from() default java.lang.Double.NEGATIVE_INFINITY;
+                    method public abstract double fromWithCast() default (double)java.lang.Float.NEGATIVE_INFINITY;
+                    method public abstract boolean hasAdjacentMapping() default false;
+                    method public abstract int integer() default 1;
+                    method public abstract double large_floating() default 1.0;
+                    method public abstract long large_integer() default 1;
+                    method public abstract char letter() default 'a';
+                    method public abstract char[]! letters1() default {};
+                    method public abstract char[]! letters2() default {'a', 'b', 'c'};
+                    method public abstract int math() default 7;
+                    method public abstract short medium() default 1;
+                    method public abstract Class<? extends java.lang.Number>! myCls() default java.lang.Integer.class;
+                    method public abstract String! prefix() default "";
+                    method public abstract boolean resolveId() default false;
+                    method public abstract byte small() default 1;
+                    method public abstract int unit() default test.pkg.ExportedProperty.PX;
+                    method public abstract test.pkg.ExportedProperty.InnerAnnotation! value() default @test.pkg.ExportedProperty.InnerAnnotation;
+                    field public static final int DP = 0; // 0x0
+                    field public static final int PX = 1; // 0x1
+                    field public static final int SP = 2; // 0x2
+                  }
+                  public static @interface ExportedProperty.InnerAnnotation {
+                  }
+                }
+            """,
+            source = """
+                package test.pkg;
+                /**
+                 * This annotation can be used to mark fields and methods to be dumped by
+                 * the view server. Only non-void methods with no arguments can be annotated
+                 * by this annotation.
+                 */
+                @SuppressWarnings({"unchecked", "deprecation", "all"})
+                @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface ExportedProperty {
+                /**
+                 * When resolveId is true, and if the annotated field/method return value
+                 * is an int, the value is converted to an Android's resource name.
+                 *
+                 * @return true if the property's value must be transformed into an Android
+                 * resource name, false otherwise
+                 */
+                public boolean resolveId() default false;
+                public java.lang.String prefix() default "";
+                public java.lang.String category() default "";
+                public boolean formatToHexString() default false;
+                public boolean hasAdjacentMapping() default false;
+                public java.lang.Class<? extends java.lang.Number> myCls() default java.lang.Integer.class;
+                public char[] letters1() default {};
+                public char[] letters2() default {'a', 'b', 'c'};
+                public double from() default java.lang.Double.NEGATIVE_INFINITY;
+                public double fromWithCast() default (double)java.lang.Float.NEGATIVE_INFINITY;
+                public test.pkg.ExportedProperty.InnerAnnotation value() default @test.pkg.ExportedProperty.InnerAnnotation;
+                public char letter() default 'a';
+                public int integer() default 1;
+                public long large_integer() default 1;
+                public float floating() default 1.0f;
+                public double large_floating() default 1.0;
+                public byte small() default 1;
+                public short medium() default 1;
+                public int math() default 7;
+                public int unit() default test.pkg.ExportedProperty.PX;
+                public static final int DP = 0; // 0x0
+                public static final int PX = 1; // 0x1
+                public static final int SP = 2; // 0x2
+                @SuppressWarnings({"unchecked", "deprecation", "all"})
+                @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface InnerAnnotation {
+                }
+                }
+                """
+        )
+    }
+
+    @Test
+    fun `Annotation metadata in stubs`() {
+        checkStubs(
+            compatibilityMode = false,
+            includeSourceRetentionAnnotations = false,
+            skipEmitPackages = emptyList(),
+            sourceFiles =
+            *arrayOf(
+                java(
+                    """
+                    package java.lang;
+
+                    import java.lang.annotation.*;
+
+                    @Target(ElementType.METHOD)
+                    @Retention(RetentionPolicy.SOURCE)
+                    public @interface MyAnnotation {
+                    }
+                    """
+                )
+            ),
+            warnings = "",
+            source = """
+                package java.lang;
+                @SuppressWarnings({"unchecked", "deprecation", "all"})
+                @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface MyAnnotation {
+                }
+                """
+        )
+    }
+
+    @Test
+    fun `Functional Interfaces`() {
+        checkStubs(
+            compatibilityMode = false,
+            skipEmitPackages = emptyList(),
+            sourceFiles =
+            *arrayOf(
+                java(
+                    """
+                    package java.lang;
+
+                    @SuppressWarnings("something") @FunctionalInterface
+                    public interface MyInterface {
+                        void run();
+                    }
+                    """
+                )
+            ),
+            warnings = "",
+            source = """
+                package java.lang;
+                @SuppressWarnings({"unchecked", "deprecation", "all"})
+                @java.lang.FunctionalInterface public interface MyInterface {
+                public void run();
+                }
+                """
+        )
+    }
+
+    @Test
     fun `Check writing package info file`() {
         checkStubs(
             sourceFiles =
@@ -2979,7 +3245,7 @@
                     """
                 ),
 
-                supportNullableSource
+                androidxNullableSource
             ),
             warnings = "",
             api = """
@@ -2997,10 +3263,10 @@
         )
     }
 
-    // TODO: Add in some type variables in method signatures and constructors!
-    // TODO: Test what happens when a class extends a hidden extends a public in separate packages,
-    // and the hidden has a @hide constructor so the stub in the leaf class doesn't compile -- I should
-    // check for this and fail build.
+// TODO: Add in some type variables in method signatures and constructors!
+// TODO: Test what happens when a class extends a hidden extends a public in separate packages,
+// and the hidden has a @hide constructor so the stub in the leaf class doesn't compile -- I should
+// check for this and fail build.
 
-    // TODO: Test -stubPackages
+// TODO: Test -stubPackages
 }
\ No newline at end of file
diff --git a/stub-annotations/src/main/java/androidx/annotation/NonNull.java b/stub-annotations/src/main/java/androidx/annotation/NonNull.java
index 3b41cc8..647ee60 100644
--- a/stub-annotations/src/main/java/androidx/annotation/NonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/NonNull.java
@@ -28,5 +28,5 @@
 
 /** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, PACKAGE, TYPE_PARAMETER, TYPE_USE})
+@Target({METHOD, PARAMETER, FIELD, PACKAGE, TYPE_PARAMETER})
 public @interface NonNull {}
diff --git a/stub-annotations/src/main/java/androidx/annotation/Nullable.java b/stub-annotations/src/main/java/androidx/annotation/Nullable.java
index 0e6abce..b9c630f 100644
--- a/stub-annotations/src/main/java/androidx/annotation/Nullable.java
+++ b/stub-annotations/src/main/java/androidx/annotation/Nullable.java
@@ -28,5 +28,5 @@
 
 /** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, PACKAGE, TYPE_PARAMETER, TYPE_USE})
+@Target({METHOD, PARAMETER, FIELD, PACKAGE, TYPE_PARAMETER})
 public @interface Nullable {}
diff --git a/stub-annotations/src/main/java/androidx/annotation/RecentlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/RecentlyNonNull.java
index 575b3eb..9ad4f5e 100644
--- a/stub-annotations/src/main/java/androidx/annotation/RecentlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/RecentlyNonNull.java
@@ -26,5 +26,5 @@
 
 /** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, TYPE_USE})
+@Target({METHOD, PARAMETER, FIELD})
 public @interface RecentlyNonNull {}
diff --git a/stub-annotations/src/main/java/androidx/annotation/RecentlyNullable.java b/stub-annotations/src/main/java/androidx/annotation/RecentlyNullable.java
index 8a9141e..8ad2a2d 100644
--- a/stub-annotations/src/main/java/androidx/annotation/RecentlyNullable.java
+++ b/stub-annotations/src/main/java/androidx/annotation/RecentlyNullable.java
@@ -26,5 +26,5 @@
 
 /** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, TYPE_USE})
+@Target({METHOD, PARAMETER, FIELD})
 public @interface RecentlyNullable {}