Snap for 4829593 from 22e57c4b9f202219d0545e990cc00365cc931e17 to pi-release

Change-Id: Ie269e238ec921b99edc9d8e9e2e4d45637fd8bb2
diff --git a/.gitignore b/.gitignore
index 8ddfee5..2e527fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,5 +3,9 @@
 /.idea/libraries
 /.idea/modules.xml
 /.idea/workspace.xml
+/.idea/runConfigurations
+/.idea/usage.statistics.xml
 /out
+build/
+stub-annotations/out
 .DS_Store
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..7b2b7ad
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,39 @@
+<component name="ProjectCodeStyleConfiguration">
+  <code_scheme name="Project" version="173">
+    <JavaCodeStyleSettings>
+      <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99999" />
+      <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99999" />
+      <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
+        <value />
+      </option>
+    </JavaCodeStyleSettings>
+    <JetCodeStyleSettings>
+      <option name="PACKAGES_TO_USE_STAR_IMPORTS">
+        <value>
+          <package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
+        </value>
+      </option>
+      <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
+      <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
+      <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
+    </JetCodeStyleSettings>
+    <codeStyleSettings language="JAVA">
+      <option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
+      <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+      <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
+      <indentOptions>
+        <option name="CONTINUATION_INDENT_SIZE" value="4" />
+      </indentOptions>
+    </codeStyleSettings>
+    <codeStyleSettings language="kotlin">
+      <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
+      <option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
+      <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+      <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
+      <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+      <indentOptions>
+        <option name="CONTINUATION_INDENT_SIZE" value="4" />
+      </indentOptions>
+    </codeStyleSettings>
+  </code_scheme>
+</component>
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index a55e7a1..79ee123 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,5 +1,5 @@
 <component name="ProjectCodeStyleConfiguration">
   <state>
-    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
+    <option name="USE_PER_PROJECT_SETTINGS" value="true" />
   </state>
 </component>
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 304a161..4eefbdf 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
     <bytecodeTargetLevel>
       <module name="metalava_main" target="1.8" />
       <module name="metalava_test" target="1.8" />
+      <module name="stub-annotations_main" target="1.8" />
+      <module name="stub-annotations_test" target="1.8" />
     </bytecodeTargetLevel>
   </component>
 </project>
\ No newline at end of file
diff --git a/.idea/dictionaries/metalava.xml b/.idea/dictionaries/metalava.xml
index bf8e898..6b14ab5 100644
--- a/.idea/dictionaries/metalava.xml
+++ b/.idea/dictionaries/metalava.xml
@@ -1,6 +1,7 @@
 <component name="ProjectDictionaryState">
   <dictionary name="metalava">
     <words>
+      <w>androidx</w>
       <w>apidocsdir</w>
       <w>argnum</w>
       <w>bootclasspath</w>
@@ -23,6 +24,7 @@
       <w>includeable</w>
       <w>inheritdoc</w>
       <w>interop</w>
+      <w>jaif</w>
       <w>javadocs</w>
       <w>jvmstatic</w>
       <w>knowntags</w>
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 267d99c..8b90e76 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -8,6 +8,7 @@
         <option name="modules">
           <set>
             <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/stub-annotations" />
           </set>
         </option>
         <option name="useAutoImport" value="true" />
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index a78c468..42f9f3a 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -1,6 +1,9 @@
 <component name="InspectionProjectProfileManager">
   <profile version="1.0">
     <option name="myName" value="Project Default" />
+    <inspection_tool class="KotlinUnusedImport" enabled="true" level="ERROR" enabled_by_default="true" />
     <inspection_tool class="LoopToCallChain" enabled="false" level="INFO" enabled_by_default="false" />
+    <inspection_tool class="RedundantSemicolon" enabled="true" level="ERROR" enabled_by_default="true" />
+    <inspection_tool class="UnstableApiUsage" enabled="false" level="WARNING" enabled_by_default="false" />
   </profile>
 </component>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 84da703..f6d5d5f 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,37 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
+  <component name="NullableNotNullManager">
+    <option name="myNullables">
+      <value>
+        <list size="9">
+          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
+          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
+          <item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
+          <item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
+          <item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
+          <item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
+          <item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
+          <item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
+          <item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
+        </list>
+      </value>
+    </option>
+    <option name="myNotNulls">
+      <value>
+        <list size="9">
+          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
+          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
+          <item index="2" class="java.lang.String" itemvalue="javax.validation.constraints.NotNull" />
+          <item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
+          <item index="4" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
+          <item index="5" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
+          <item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
+          <item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
+          <item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
+        </list>
+      </value>
+    </option>
+  </component>
   <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/classes" />
   </component>
diff --git a/build.gradle b/build.gradle
index f9e7119..4456034 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
 buildscript {
-    ext.gradle_version = '3.1.0-beta4'
-    ext.studio_version = '26.1.0-beta4'
-    ext.kotlin_version = '1.2.30'
+    ext.gradle_version = '3.2.0-alpha16'
+    ext.studio_version = '26.2.0-alpha16'
+    ext.kotlin_version = '1.2.41'
     repositories {
         google()
         jcenter()
@@ -12,6 +12,11 @@
     }
 }
 
+repositories {
+    google()
+    jcenter()
+}
+
 apply plugin: 'application'
 apply plugin: 'java'
 apply plugin: 'kotlin'
@@ -42,11 +47,6 @@
     }
 }
 
-repositories {
-    google()
-    jcenter()
-}
-
 dependencies {
     implementation "com.android.tools.external.org-jetbrains:uast:$studio_version"
     implementation "com.android.tools.external.com-intellij:intellij-core:$studio_version"
@@ -54,8 +54,8 @@
     implementation "com.android.tools.lint:lint-checks:$studio_version"
     implementation "com.android.tools.lint:lint-gradle:$studio_version"
     implementation "com.android.tools.lint:lint:$studio_version"
-    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
-    implementation "com.android.tools.lint:lint-tests:$studio_version"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+    testImplementation "com.android.tools.lint:lint-tests:$studio_version"
     testImplementation 'junit:junit:4.11'
 }
 
@@ -101,3 +101,27 @@
     version = "${version}-SNAPSHOT"
 }
 
+// KtLint: https://github.com/shyiko/ktlint
+
+configurations {
+    ktlint
+}
+
+dependencies {
+    ktlint "com.github.shyiko:ktlint:0.23.1"
+}
+
+task ktlint(type: JavaExec, group: "verification") {
+    description = "Check Kotlin code style."
+    main = "com.github.shyiko.ktlint.Main"
+    classpath = configurations.ktlint
+    args "src/**/*.kt"
+}
+check.dependsOn ktlint
+
+task format(type: JavaExec, group: "formatting") {
+    description = "Fix Kotlin code style deviations."
+    main = "com.github.shyiko.ktlint.Main"
+    classpath = configurations.ktlint
+    args "-F", "src/**/*.kt"
+}
diff --git a/manifest.txt b/manifest.txt
new file mode 100644
index 0000000..2128bdd
--- /dev/null
+++ b/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.tools.metalava.Driver
diff --git a/manual/android/util/annotations.xml b/manual/android/util/annotations.xml
new file mode 100644
index 0000000..c4e8392
--- /dev/null
+++ b/manual/android/util/annotations.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<root>
+  <item name="android.util.Log boolean isLoggable(java.lang.String, int) 0">
+    <annotation name="android.support.annotation.Size">
+      <val name="max" val="23" />
+      <val name="apis" val="&quot;..23&quot;" />
+    </annotation>
+  </item>
+</root>
+
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..4be43e7
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':stub-annotations'
diff --git a/src/main/java/com/android/tools/lint/checks/infrastructure/ClassName.kt b/src/main/java/com/android/tools/lint/checks/infrastructure/ClassName.kt
new file mode 100644
index 0000000..a6b79c5
--- /dev/null
+++ b/src/main/java/com/android/tools/lint/checks/infrastructure/ClassName.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2017 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.lint.checks.infrastructure
+
+import java.util.regex.Pattern
+
+// Copy in metalava from lint to avoid compilation dependency directly on lint-tests
+
+/** A pair of package name and class name inferred from Java or Kotlin source code */
+class ClassName(source: String) {
+    val packageName: String?
+    val className: String?
+
+    init {
+        val withoutComments = stripComments(source)
+        packageName = getPackage(withoutComments)
+        className = getClassName(withoutComments)
+    }
+
+    fun packageNameWithDefault() = packageName ?: ""
+}
+
+/**
+ * Strips line and block comments from the given Java or Kotlin source file
+ */
+@Suppress("LocalVariableName")
+fun stripComments(source: String, stripLineComments: Boolean = true): String {
+    val sb = StringBuilder(source.length)
+    var state = 0
+    val INIT = 0
+    val INIT_SLASH = 1
+    val LINE_COMMENT = 2
+    val BLOCK_COMMENT = 3
+    val BLOCK_COMMENT_ASTERISK = 4
+    val IN_STRING = 5
+    val IN_STRING_ESCAPE = 6
+    val IN_CHAR = 7
+    val AFTER_CHAR = 8
+    for (i in 0 until source.length) {
+        val c = source[i]
+        when (state) {
+            INIT -> {
+                when (c) {
+                    '/' -> state = INIT_SLASH
+                    '"' -> {
+                        state = IN_STRING
+                        sb.append(c)
+                    }
+                    '\'' -> {
+                        state = IN_CHAR
+                        sb.append(c)
+                    }
+                    else -> sb.append(c)
+                }
+            }
+            INIT_SLASH -> {
+                when {
+                    c == '*' -> state = BLOCK_COMMENT
+                    c == '/' && stripLineComments -> state = LINE_COMMENT
+                    else -> {
+                        state = INIT
+                        sb.append('/') // because we skipped it in init
+                        sb.append(c)
+                    }
+                }
+            }
+            LINE_COMMENT -> {
+                when (c) {
+                    '\n' -> state = INIT
+                }
+            }
+            BLOCK_COMMENT -> {
+                when (c) {
+                    '*' -> state = BLOCK_COMMENT_ASTERISK
+                }
+            }
+            BLOCK_COMMENT_ASTERISK -> {
+                state = when (c) {
+                    '/' -> INIT
+                    '*' -> BLOCK_COMMENT_ASTERISK
+                    else -> BLOCK_COMMENT
+                }
+            }
+            IN_STRING -> {
+                when (c) {
+                    '\\' -> state = IN_STRING_ESCAPE
+                    '"' -> state = INIT
+                }
+                sb.append(c)
+            }
+            IN_STRING_ESCAPE -> {
+                sb.append(c)
+                state = IN_STRING
+            }
+            IN_CHAR -> {
+                if (c != '\\') {
+                    state = AFTER_CHAR
+                }
+                sb.append(c)
+            }
+            AFTER_CHAR -> {
+                sb.append(c)
+                if (c == '\\') {
+                    state = INIT
+                }
+            }
+        }
+    }
+
+    return sb.toString()
+}
+
+private val PACKAGE_PATTERN = Pattern.compile("""package\s+([\S&&[^;]]*)""")
+
+private val CLASS_PATTERN = Pattern.compile(
+    """(class|interface|enum|object)+?\s*([^\s:(]+)""",
+    Pattern.MULTILINE
+)
+
+fun getPackage(source: String): String? {
+    val matcher = PACKAGE_PATTERN.matcher(source)
+    return if (matcher.find()) {
+        matcher.group(1).trim { it <= ' ' }
+    } else {
+        null
+    }
+}
+
+fun getClassName(source: String): String? {
+    val matcher = CLASS_PATTERN.matcher(source.replace('\n', ' '))
+    var start = 0
+    while (matcher.find(start)) {
+        val cls = matcher.group(2)
+        val groupStart = matcher.start(2)
+
+        // Make sure this "class" reference isn't part of an annotation on the class
+        // referencing a class literal -- Foo.class, or in Kotlin, Foo::class.java)
+        if (groupStart == 0 || source[groupStart - 1] != '.' && source[groupStart - 1] != ':') {
+            val trimmed = cls.trim { it <= ' ' }
+            val typeParameter = trimmed.indexOf('<')
+            return if (typeParameter != -1) {
+                trimmed.substring(0, typeParameter)
+            } else {
+                trimmed
+            }
+        }
+        start = matcher.end(2)
+    }
+
+    return null
+}
diff --git a/src/main/java/com/android/tools/metalava/AndroidApiChecks.kt b/src/main/java/com/android/tools/metalava/AndroidApiChecks.kt
index 7006579..78ad9c7 100644
--- a/src/main/java/com/android/tools/metalava/AndroidApiChecks.kt
+++ b/src/main/java/com/android/tools/metalava/AndroidApiChecks.kt
@@ -134,7 +134,6 @@
                         // found beginning
                         break
                     }
-
                 }
                 begin += tag.length
             }
@@ -152,8 +151,8 @@
             val c = doc[i]
 
             if (c == '@' && (isLinePrefix ||
-                        doc.startsWith("@param", i, true) ||
-                        doc.startsWith("@return", i, true))
+                    doc.startsWith("@param", i, true) ||
+                    doc.startsWith("@return", i, true))
             ) {
                 // Found it
                 end = i
@@ -191,23 +190,23 @@
                 }
 
                 for (value in values) {
-                    //var perm = String.valueOf(value.value())
+                    // var perm = String.valueOf(value.value())
                     var perm = value.toSource()
                     if (perm.indexOf('.') >= 0) perm = perm.substring(perm.lastIndexOf('.') + 1)
                     if (text.contains(perm)) {
                         reporter.report(
                             // Why is that a problem? Sometimes you want to describe
                             // particular use cases.
-                            Errors.REQUIRES_PERMISSION, method, "Method '" + method.name()
-                                    + "' documentation mentions permissions already declared by @RequiresPermission"
+                            Errors.REQUIRES_PERMISSION, method, "Method '" + method.name() +
+                                "' documentation mentions permissions already declared by @RequiresPermission"
                         )
                     }
                 }
             }
         } else if (text.contains("android.Manifest.permission") || text.contains("android.permission.")) {
             reporter.report(
-                Errors.REQUIRES_PERMISSION, method, "Method '" + method.name()
-                        + "' documentation mentions permissions without declaring @RequiresPermission"
+                Errors.REQUIRES_PERMISSION, method, "Method '" + method.name() +
+                    "' documentation mentions permissions without declaring @RequiresPermission"
             )
         }
     }
@@ -234,8 +233,8 @@
             }
             if (!hasSdkConstant) {
                 reporter.report(
-                    Errors.SDK_CONSTANT, field, "Field '" + field.name()
-                            + "' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)"
+                    Errors.SDK_CONSTANT, field, "Field '" + field.name() +
+                        "' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)"
                 )
             }
         }
@@ -243,8 +242,8 @@
         if (text.contains("Activity Action:")) {
             if (!hasSdkConstant) {
                 reporter.report(
-                    Errors.SDK_CONSTANT, field, "Field '" + field.name()
-                            + "' is missing @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)"
+                    Errors.SDK_CONSTANT, field, "Field '" + field.name() +
+                        "' is missing @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)"
                 )
             }
         }
@@ -261,7 +260,10 @@
             var foundTypeDef = false
             for (annotation in item.modifiers.annotations()) {
                 val cls = annotation.resolve() ?: continue
-                if (cls.modifiers.findAnnotation(SdkConstants.INT_DEF_ANNOTATION) != null) {
+                val modifiers = cls.modifiers
+                if (modifiers.findAnnotation(SdkConstants.INT_DEF_ANNOTATION.oldName()) != null ||
+                    modifiers.findAnnotation(SdkConstants.INT_DEF_ANNOTATION.newName()) != null
+                ) {
                     // TODO: Check that all the constants listed in the documentation are included in the
                     // annotation?
                     foundTypeDef = true
@@ -273,7 +275,7 @@
                 reporter.report(
                     Errors.INT_DEF, item,
                     // TODO: Include source code you can paste right into the code?
-                    ident + " documentation mentions constants without declaring an @IntDef"
+                    "$ident documentation mentions constants without declaring an @IntDef"
                 )
             }
         }
@@ -283,7 +285,7 @@
         ) {
             reporter.report(
                 Errors.NULLABLE, item,
-                ident + " documentation mentions 'null' without declaring @NonNull or @Nullable"
+                "$ident documentation mentions 'null' without declaring @NonNull or @Nullable"
             )
         }
     }
@@ -293,4 +295,3 @@
         val nullPattern: Pattern = Pattern.compile("\\bnull\\b")
     }
 }
-
diff --git a/src/main/java/com/android/tools/metalava/AnnotationStatistics.kt b/src/main/java/com/android/tools/metalava/AnnotationStatistics.kt
index 1f2e4aa..c229bca 100644
--- a/src/main/java/com/android/tools/metalava/AnnotationStatistics.kt
+++ b/src/main/java/com/android/tools/metalava/AnnotationStatistics.kt
@@ -35,14 +35,17 @@
 import org.objectweb.asm.tree.FieldInsnNode
 import org.objectweb.asm.tree.MethodInsnNode
 import org.objectweb.asm.tree.MethodNode
+import java.io.BufferedWriter
 import java.io.File
+import java.io.FileWriter
 import java.io.IOException
 import java.io.PrintWriter
 import java.util.zip.ZipFile
 
 const val CLASS_COLUMN_WIDTH = 60
 const val COUNT_COLUMN_WIDTH = 16
-const val USAGE_REPORT_MAX_ROWS = 15
+const val USAGE_REPORT_MAX_ROWS = 3000
+
 /** Sadly gitiles' markdown support doesn't handle tables with top/bottom horizontal edges */
 const val INCLUDE_HORIZONTAL_EDGES = false
 
@@ -74,6 +77,9 @@
             }
 
             override fun visitParameter(parameter: ParameterItem) {
+                if (!parameter.requiresNullnessInfo()) {
+                    return
+                }
                 allParameters++
                 if (parameter.modifiers.annotations().any { it.isNonNull() || it.isNullable() }) {
                     annotatedParameters++
@@ -81,6 +87,9 @@
             }
 
             override fun visitField(field: FieldItem) {
+                if (!field.requiresNullnessInfo()) {
+                    return
+                }
                 allFields++
                 if (field.modifiers.annotations().any { it.isNonNull() || it.isNullable() }) {
                     annotatedFields++
@@ -88,6 +97,9 @@
             }
 
             override fun visitMethod(method: MethodItem) {
+                if (!method.requiresNullnessInfo()) {
+                    return
+                }
                 allMethods++
                 if (method.modifiers.annotations().any { it.isNonNull() || it.isNullable() }) {
                     annotatedMethods++
@@ -111,7 +123,7 @@
 
     private fun percent(numerator: Int, denominator: Int): Int {
         return if (denominator == 0) {
-            0
+            100
         } else {
             numerator * 100 / denominator
         }
@@ -147,7 +159,7 @@
         options.stdout.println()
         options.stdout.println(
             "$missingCount methods and fields were missing nullness annotations out of " +
-                    "$referenceCount total API references."
+                "$referenceCount total API references."
         )
         options.stdout.println("API nullness coverage is ${percent(annotatedCount, referenceCount)}%")
         options.stdout.println()
@@ -227,17 +239,44 @@
     }
 
     private fun printClassTable(classes: List<Item>, classCount: MutableMap<Item, Int>) {
+        val reportFile = options.annotationCoverageClassReport
+        val printer =
+            if (reportFile != null) {
+                reportFile.parentFile?.mkdirs()
+                PrintWriter(BufferedWriter(FileWriter(reportFile)))
+            } else {
+                options.stdout
+            }
+
+        // Top APIs
+        printer.println("\nTop referenced un-annotated classes:\n")
+
         printTable("Qualified Class Name",
             "Usage Count",
             classes,
             { (it as ClassItem).qualifiedName() },
-            { classCount[it]!! })
+            { classCount[it]!! },
+            printer)
+
+        if (reportFile != null) {
+            printer.close()
+            progress("\n$PROGRAM_NAME wrote class annotation coverage report to $reportFile")
+        }
     }
 
     private fun printMemberTable(
-        sorted: List<MemberItem>, used: HashMap<MemberItem, Int>,
-        printer: PrintWriter = options.stdout
+        sorted: List<MemberItem>,
+        used: HashMap<MemberItem, Int>
     ) {
+        val reportFile = options.annotationCoverageMemberReport
+        val printer =
+            if (reportFile != null) {
+                reportFile.parentFile?.mkdirs()
+                PrintWriter(BufferedWriter(FileWriter(reportFile)))
+            } else {
+                options.stdout
+            }
+
         // Top APIs
         printer.println("\nTop referenced un-annotated members:\n")
 
@@ -254,6 +293,11 @@
             { used[it]!! },
             printer
         )
+
+        if (reportFile != null) {
+            printer.close()
+            progress("\n$PROGRAM_NAME wrote member annotation coverage report to $reportFile")
+        }
     }
 
     private fun dashes(printer: PrintWriter, max: Int) {
@@ -302,24 +346,24 @@
     private fun recordUsages(used: MutableMap<MemberItem, Int>, file: File, path: String) {
         when {
             file.name.endsWith(SdkConstants.DOT_JAR) -> try {
-                ZipFile(file).use({ jar ->
+                ZipFile(file).use { jar ->
                     val enumeration = jar.entries()
                     while (enumeration.hasMoreElements()) {
                         val entry = enumeration.nextElement()
                         if (entry.name.endsWith(SdkConstants.DOT_CLASS)) {
                             try {
-                                jar.getInputStream(entry).use({ `is` ->
+                                jar.getInputStream(entry).use { `is` ->
                                     val bytes = ByteStreams.toByteArray(`is`)
                                     if (bytes != null) {
                                         recordUsages(used, bytes, path + ":" + entry.name)
                                     }
-                                })
+                                }
                             } catch (e: Exception) {
                                 options.stdout.println("Could not read jar file entry ${entry.name} from $file: $e")
                             }
                         }
                     }
-                })
+                }
             } catch (e: IOException) {
                 options.stdout.println("Could not read jar file contents from $file: $e")
             }
@@ -392,9 +436,9 @@
 
     private fun isSkippableOwner(owner: String) =
         owner.startsWith("java/") ||
-                owner.startsWith("javax/") ||
-                owner.startsWith("kotlin") ||
-                owner.startsWith("kotlinx/")
+            owner.startsWith("javax/") ||
+            owner.startsWith("kotlin") ||
+            owner.startsWith("kotlinx/")
 
     private fun findField(node: FieldInsnNode): FieldItem? {
         val cls = findClass(node.owner) ?: return null
diff --git a/src/main/java/com/android/tools/metalava/AnnotationsDiffer.kt b/src/main/java/com/android/tools/metalava/AnnotationsDiffer.kt
new file mode 100644
index 0000000..8147ef8
--- /dev/null
+++ b/src/main/java/com/android/tools/metalava/AnnotationsDiffer.kt
@@ -0,0 +1,137 @@
+/*
+ * 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.metalava.doclava1.ApiPredicate
+import com.android.tools.metalava.doclava1.Errors
+import com.android.tools.metalava.doclava1.FilterPredicate
+import com.android.tools.metalava.model.Codebase
+import com.android.tools.metalava.model.Item
+import java.io.File
+import java.io.IOException
+import java.io.PrintWriter
+import java.io.StringWriter
+import java.util.function.Predicate
+
+/**
+ * The [AnnotationsDiffer] can take a codebase with annotations, and subtract
+ * another codebase with annotations, and emit a signature file that contains
+ * *only* the signatures that have annotations that were not present in the
+ * second codebase.
+ *
+ * The usecase for this a scenario like the following:
+ * - A lot of new annotations are added to the master branch
+ * - These annotations also apply to older APIs/branches, but for practical
+ *   reasons we can't cherrypick the CLs that added these annotations to the
+ *   older branches -- sometimes because those branches are under more strict
+ *   access control, sometimes because the changes contain non-annotation
+ *   changes as well, and sometimes because even a pure annotation CL won't
+ *   cleanly apply to older branches since other content around the annotations
+ *   have changed.
+ * - We want to merge these annotations into the older codebase as an external
+ *   annotation file. However, we don't really want to check in the *entire*
+ *   signature file, since it's massive (which will slow down build times in
+ *   that older branch), may leak new APIs etc.
+ * - Solution: We can produce a "diff": create a signature file which contains
+ *   *only* the signatures that have annotations from the new branch where
+ *   (a) the signature is also present in the older codebase, and (b) where
+ *   the annotation is not also present in the older codebase.
+ *
+ * That's what this codebase is used for: "take the master signature files
+ * with annotations, subtract out the signature files from say the P release,
+ * and check that in as the "annotations to import from master into P" delta
+ * file.
+ */
+class AnnotationsDiffer(
+    superset: Codebase,
+    private val codebase: Codebase
+) {
+    private val relevant = HashSet<Item>(1000)
+
+    private val predicate = object : Predicate<Item> {
+        override fun test(item: Item): Boolean {
+            if (relevant.contains(item)) {
+                return true
+            }
+
+            val parent = item.parent() ?: return false
+            return test(parent)
+        }
+    }
+
+    init {
+        // Limit the API to the codebase, and look at the super set codebase
+        // for annotations that are only there (not in the current codebase)
+        // and emit those
+        val visitor = object : ComparisonVisitor() {
+            override fun compare(old: Item, new: Item) {
+                val newModifiers = new.modifiers
+                for (annotation in old.modifiers.annotations()) {
+                    var addAnnotation = false
+                    if (annotation.isNullnessAnnotation()) {
+                        if (!newModifiers.hasNullnessInfo()) {
+                            addAnnotation = true
+                        }
+                    } else {
+                        // TODO: Check for other incompatibilities than nullness?
+                        val qualifiedName = annotation.qualifiedName() ?: continue
+                        if (newModifiers.findAnnotation(qualifiedName) == null) {
+                            addAnnotation = true
+                        }
+                    }
+
+                    if (addAnnotation) {
+                        relevant.add(new)
+                    }
+                }
+            }
+        }
+        CodebaseComparator().compare(visitor, superset, codebase, ApiPredicate(codebase))
+    }
+
+    fun writeDiffSignature(apiFile: File) {
+        val apiFilter = FilterPredicate(ApiPredicate(codebase))
+        val apiReference = ApiPredicate(codebase, ignoreShown = true)
+        val apiEmit = apiFilter.and(predicate)
+
+        progress("\nWriting annotation diff file: ")
+        try {
+            val stringWriter = StringWriter()
+            val writer = PrintWriter(stringWriter)
+            writer.use { printWriter ->
+                val preFiltered = codebase.original != null
+                val apiWriter = SignatureWriter(printWriter, apiEmit, apiReference, preFiltered)
+                codebase.accept(apiWriter)
+            }
+
+            // Clean up blank lines
+            var prev: Char = ' '
+            val cleanedUp = stringWriter.toString().filter {
+                if (it == '\n' && prev == '\n')
+                    false
+                else {
+                    prev = it
+                    true
+                }
+            }
+
+            apiFile.writeText(cleanedUp, Charsets.UTF_8)
+        } catch (e: IOException) {
+            reporter.report(Errors.IO_ERROR, apiFile, "Cannot open file for write.")
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/metalava/AnnotationsMerger.kt b/src/main/java/com/android/tools/metalava/AnnotationsMerger.kt
index cea88d6..11ff5d5 100644
--- a/src/main/java/com/android/tools/metalava/AnnotationsMerger.kt
+++ b/src/main/java/com/android/tools/metalava/AnnotationsMerger.kt
@@ -31,8 +31,6 @@
 import com.android.SdkConstants.TYPE_DEF_FLAG_ATTRIBUTE
 import com.android.SdkConstants.TYPE_DEF_VALUE_ATTRIBUTE
 import com.android.SdkConstants.VALUE_TRUE
-import com.android.annotations.NonNull
-import com.android.tools.lint.annotations.ApiDatabase
 import com.android.tools.lint.annotations.Extractor.ANDROID_INT_DEF
 import com.android.tools.lint.annotations.Extractor.ANDROID_NOTNULL
 import com.android.tools.lint.annotations.Extractor.ANDROID_NULLABLE
@@ -45,7 +43,11 @@
 import com.android.tools.lint.annotations.Extractor.IDEA_NULLABLE
 import com.android.tools.lint.annotations.Extractor.SUPPORT_NOTNULL
 import com.android.tools.lint.annotations.Extractor.SUPPORT_NULLABLE
-import com.android.tools.lint.detector.api.LintUtils.getChildren
+import com.android.tools.lint.checks.AnnotationDetector
+import com.android.tools.lint.detector.api.getChildren
+import com.android.tools.metalava.doclava1.ApiFile
+import com.android.tools.metalava.doclava1.ApiParseException
+import com.android.tools.metalava.doclava1.ApiPredicate
 import com.android.tools.metalava.model.AnnotationAttribute
 import com.android.tools.metalava.model.AnnotationAttributeValue
 import com.android.tools.metalava.model.AnnotationItem
@@ -54,41 +56,34 @@
 import com.android.tools.metalava.model.DefaultAnnotationValue
 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.psi.PsiAnnotationItem
+import com.android.tools.metalava.model.visitors.ApiVisitor
 import com.android.utils.XmlUtils
 import com.google.common.base.Charsets
-import com.google.common.base.Splitter
-import com.google.common.collect.ImmutableSet
 import com.google.common.io.ByteStreams
 import com.google.common.io.Closeables
 import com.google.common.io.Files
-import com.google.common.xml.XmlEscapers
 import org.w3c.dom.Document
 import org.w3c.dom.Element
-import org.w3c.dom.Node
 import org.xml.sax.SAXParseException
 import java.io.File
 import java.io.FileInputStream
 import java.io.IOException
 import java.lang.reflect.Field
-import java.util.ArrayList
-import java.util.HashMap
 import java.util.jar.JarInputStream
 import java.util.regex.Pattern
 import java.util.zip.ZipEntry
-import kotlin.Comparator
 
 /** Merges annotations into classes already registered in the given [Codebase] */
 class AnnotationsMerger(
-    private val codebase: Codebase,
-    private val apiFilter: ApiDatabase?,
-    private val listIgnored: Boolean = true
+    private val codebase: Codebase
 ) {
     fun merge(mergeAnnotations: List<File>) {
         mergeAnnotations.forEach { mergeExisting(it) }
     }
 
-    private fun mergeExisting(@NonNull file: File) {
+    private fun mergeExisting(file: File) {
         if (file.isDirectory) {
             val files = file.listFiles()
             if (files != null) {
@@ -106,12 +101,29 @@
                 } catch (e: IOException) {
                     error("Aborting: I/O problem during transform: " + e.toString())
                 }
-
+            } else if (file.path.endsWith(".jaif")) {
+                try {
+                    val jaif = Files.asCharSource(file, Charsets.UTF_8).read()
+                    mergeAnnotationsJaif(file.path, jaif)
+                } catch (e: IOException) {
+                    error("Aborting: I/O problem during transform: " + e.toString())
+                }
+            } else if (file.path.endsWith(".txt") ||
+                file.path.endsWith(".signatures") ||
+                file.path.endsWith(".api")
+            ) {
+                try {
+                    // .txt: Old style signature files
+                    // Others: new signature files (e.g. kotlin-style nullness info)
+                    mergeAnnotationsSignatureFile(file.path)
+                } catch (e: IOException) {
+                    error("Aborting: I/O problem during transform: " + e.toString())
+                }
             }
         }
     }
 
-    private fun mergeFromJar(@NonNull jar: File) {
+    private fun mergeFromJar(jar: File) {
         // Reads in an existing annotations jar and merges in entries found there
         // with the annotations analyzed from source.
         var zis: JarInputStream? = null
@@ -138,7 +150,7 @@
         }
     }
 
-    private fun mergeAnnotationsXml(@NonNull path: String, @NonNull xml: String) {
+    private fun mergeAnnotationsXml(path: String, xml: String) {
         try {
             val document = XmlUtils.parseDocument(xml, false)
             mergeDocument(document)
@@ -154,23 +166,167 @@
         }
     }
 
+    private fun mergeAnnotationsSignatureFile(path: String) {
+        try {
+            // Old style signature files don't support annotations anyway, so we might as well
+            // accept
+            val kotlinStyleNulls = true
+            val supportsStagedNullability = true
+            val signatureCodebase = ApiFile.parseApi(File(path), kotlinStyleNulls, supportsStagedNullability)
+            signatureCodebase.description = "Signature files for annotation merger: loaded from $path"
+            val visitor = object : ComparisonVisitor() {
+                override fun compare(old: Item, new: Item) {
+                    val newModifiers = new.modifiers
+                    for (annotation in old.modifiers.annotations()) {
+                        var addAnnotation = false
+                        if (annotation.isNullnessAnnotation()) {
+                            if (!newModifiers.hasNullnessInfo()) {
+                                addAnnotation = true
+                            }
+                        } else {
+                            // TODO: Check for other incompatibilities than nullness?
+                            val qualifiedName = annotation.qualifiedName() ?: continue
+                            if (newModifiers.findAnnotation(qualifiedName) == null) {
+                                addAnnotation = true
+                            }
+                        }
+
+                        if (addAnnotation) {
+                            // Don't map annotation names - this would turn newly non null back into non null
+                            new.mutableModifiers().addAnnotation(
+                                new.codebase.createAnnotation(
+                                    annotation.toSource(),
+                                    new,
+                                    mapName = false
+                                )
+                            )
+                        }
+                    }
+                }
+            }
+            CodebaseComparator().compare(visitor, signatureCodebase, codebase, ApiPredicate(signatureCodebase))
+        } catch (ex: ApiParseException) {
+            val message = "Unable to parse signature file $path: ${ex.message}"
+            throw DriverException(message)
+        }
+    }
+
+    private fun mergeAnnotationsJaif(path: String, jaif: String) {
+        var pkgItem: PackageItem? = null
+        var clsItem: ClassItem? = null
+        var methodItem: MethodItem? = null
+        var curr: Item? = null
+
+        for (rawLine in jaif.split("\n")) {
+            val line = rawLine.trim()
+            if (line.isEmpty()) {
+                continue
+            }
+            if (line.startsWith("//")) {
+                continue
+            }
+            if (line.startsWith("package ")) {
+                val pkg = line.substring("package ".length, line.length - 1)
+                pkgItem = codebase.findPackage(pkg)
+                curr = pkgItem
+            } else if (line.startsWith("class ")) {
+                val cls = line.substring("class ".length, line.length - 1)
+                clsItem = if (pkgItem != null)
+                    codebase.findClass(pkgItem.qualifiedName() + "." + cls)
+                else
+                    null
+                curr = clsItem
+            } else if (line.startsWith("annotation ")) {
+                val cls = line.substring("annotation ".length, line.length - 1)
+                clsItem = if (pkgItem != null)
+                    codebase.findClass(pkgItem.qualifiedName() + "." + cls)
+                else
+                    null
+                curr = clsItem
+            } else if (line.startsWith("method ")) {
+                val method = line.substring("method ".length, line.length - 1)
+                methodItem = null
+                if (clsItem != null) {
+                    val index = method.indexOf('(')
+                    if (index != -1) {
+                        val name = method.substring(0, index)
+                        val desc = method.substring(index)
+                        methodItem = clsItem.findMethodByDesc(name, desc, true, true)
+                    }
+                }
+                curr = methodItem
+            } else if (line.startsWith("field ")) {
+                val field = line.substring("field ".length, line.length - 1)
+                val fieldItem = clsItem?.findField(field, true, true)
+                curr = fieldItem
+            } else if (line.startsWith("parameter #")) {
+                val parameterIndex = line.substring("parameter #".length, line.length - 1).toInt()
+                val parameterItem = if (methodItem != null) {
+                    methodItem.parameters()[parameterIndex]
+                } else {
+                    null
+                }
+                curr = parameterItem
+            } else if (line.startsWith("type: ")) {
+                val typeAnnotation = line.substring("type: ".length)
+                if (curr != null) {
+                    mergeJaifAnnotation(path, curr, typeAnnotation)
+                }
+            } else if (line.startsWith("return: ")) {
+                val annotation = line.substring("return: ".length)
+                if (methodItem != null) {
+                    mergeJaifAnnotation(path, methodItem, annotation)
+                }
+            } else if (line.startsWith("inner-type")) {
+                warning("$path: Skipping inner-type annotations for now ($line)")
+            } else if (line.startsWith("int ")) {
+                // warning("Skipping int attribute definitions for annotations now ($line)")
+            }
+        }
+    }
+
+    private fun mergeJaifAnnotation(
+        path: String,
+        item: Item,
+        annotationSource: String
+    ) {
+        if (annotationSource.isEmpty()) {
+            return
+        }
+
+        if (annotationSource.contains("(")) {
+            warning("$path: Can't merge complex annotations from jaif yet: $annotationSource")
+            return
+        }
+        val originalName = annotationSource.substring(1) // remove "@"
+        val qualifiedName = AnnotationItem.mapName(codebase, originalName) ?: originalName
+        if (hasNullnessConflicts(item, qualifiedName)) {
+            return
+        }
+
+        val annotationItem = codebase.createAnnotation("@$qualifiedName")
+        item.mutableModifiers().addAnnotation(annotationItem)
+    }
+
     internal fun error(message: String) {
         // TODO: Integrate with metalava error facility
-        options.stderr.println("Error: " + message)
+        options.stderr.println("Error: $message")
     }
 
     internal fun warning(message: String) {
-        options.stdout.println("Warning: " + message)
+        if (options.verbose) {
+            options.stdout.println("Warning: $message")
+        }
     }
 
     @Suppress("PrivatePropertyName")
     private val XML_SIGNATURE: Pattern = Pattern.compile(
         // Class (FieldName | Type? Name(ArgList) Argnum?)
-        //"(\\S+) (\\S+|(.*)\\s+(\\S+)\\((.*)\\)( \\d+)?)");
+        // "(\\S+) (\\S+|(.*)\\s+(\\S+)\\((.*)\\)( \\d+)?)");
         "(\\S+) (\\S+|((.*)\\s+)?(\\S+)\\((.*)\\)( \\d+)?)"
     )
 
-    private fun mergeDocument(@NonNull document: Document) {
+    private fun mergeDocument(document: Document) {
 
         val root = document.documentElement
         val rootTag = root.tagName
@@ -186,9 +342,9 @@
             if (signature == "java.util.Calendar int get(int)") {
                 // https://youtrack.jetbrains.com/issue/IDEA-137385
                 continue
-            } else if (signature == "java.util.Calendar void set(int, int, int) 1"
-                || signature == "java.util.Calendar void set(int, int, int, int, int) 1"
-                || signature == "java.util.Calendar void set(int, int, int, int, int, int) 1"
+            } else if (signature == "java.util.Calendar void set(int, int, int) 1" ||
+                signature == "java.util.Calendar void set(int, int, int, int, int) 1" ||
+                signature == "java.util.Calendar void set(int, int, int, int, int, int) 1"
             ) {
                 // http://b.android.com/76090
                 continue
@@ -198,23 +354,19 @@
             if (matcher.matches()) {
                 val containingClass = matcher.group(1)
                 if (containingClass == null) {
-                    warning("Could not find class for " + signature)
-                    continue
-                }
-
-                if (apiFilter != null &&
-                    !hasHistoricData(item) &&
-                    !apiFilter.hasClass(containingClass)
-                ) {
-                    if (listIgnored) {
-                        warning("Skipping imported element because it is not part of the API file: $containingClass")
-                    }
+                    warning("Could not find class for $signature")
                     continue
                 }
 
                 val classItem = codebase.findClass(containingClass)
                 if (classItem == null) {
-                    warning("Could not find class $containingClass; omitting annotations merge")
+                    // Well known exceptions from IntelliJ's external annotations
+                    // we won't complain loudly about
+                    if (wellKnownIgnoredImport(containingClass)) {
+                        continue
+                    }
+
+                    warning("Could not find class $containingClass; omitting annotation from merge")
                     continue
                 }
 
@@ -235,29 +387,34 @@
             } else if (signature.indexOf(' ') == -1 && signature.indexOf('.') != -1) {
                 // Must be just a class
                 val containingClass = signature
-                if (apiFilter != null &&
-                    !hasHistoricData(item) &&
-                    !apiFilter.hasClass(containingClass)
-                ) {
-                    if (listIgnored) {
-                        warning("Skipping imported element because it is not part of the API file: $containingClass")
-                    }
-                    continue
-                }
-
                 val classItem = codebase.findClass(containingClass)
                 if (classItem == null) {
-                    warning("Could not find class $containingClass; omitting annotations merge")
+                    if (wellKnownIgnoredImport(containingClass)) {
+                        continue
+                    }
+
+                    warning("Could not find class $containingClass; omitting annotation from merge")
                     continue
                 }
 
                 mergeAnnotations(item, classItem)
             } else {
-                warning("No merge match for signature " + signature)
+                warning("No merge match for signature $signature")
             }
         }
     }
 
+    private fun wellKnownIgnoredImport(containingClass: String): Boolean {
+        if (containingClass.startsWith("javax.swing.") ||
+            containingClass.startsWith("javax.naming.") ||
+            containingClass.startsWith("java.awt.") ||
+            containingClass.startsWith("org.jdom.")
+        ) {
+            return true
+        }
+        return false
+    }
+
     // The parameter declaration used in XML files should not have duplicated spaces,
     // and there should be no space after commas (we can't however strip out all spaces,
     // since for example the spaces around the "extends" keyword needs to be there in
@@ -268,37 +425,31 @@
     }
 
     private fun mergeMethodOrParameter(
-        item: Element, containingClass: String, classItem: ClassItem,
-        methodName: String, parameterIndex: Int,
+        item: Element,
+        containingClass: String,
+        classItem: ClassItem,
+        methodName: String,
+        parameterIndex: Int,
         parameters: String
     ) {
         @Suppress("NAME_SHADOWING")
         val parameters = fixParameterString(parameters)
 
-        if (apiFilter != null &&
-            !hasHistoricData(item) &&
-            !apiFilter.hasMethod(containingClass, methodName, parameters)
-        ) {
-            if (listIgnored) {
-                warning(
-                    "Skipping imported element because it is not part of the API file: "
-                            + containingClass + "#" + methodName + "(" + parameters + ")"
-                )
-            }
-            return
-        }
-
         val methodItem: MethodItem? = classItem.findMethod(methodName, parameters)
         if (methodItem == null) {
-            warning("Could not find class $methodName($parameters) in $containingClass; omitting annotations merge")
+            if (wellKnownIgnoredImport(containingClass)) {
+                return
+            }
+
+            warning("Could not find method $methodName($parameters) in $containingClass; omitting annotation from merge")
             return
         }
 
         if (parameterIndex != -1) {
             val parameterItem = methodItem.parameters()[parameterIndex]
 
-            if ("java.util.Calendar" == containingClass && "set" == methodName
-                && parameterIndex > 0
+            if ("java.util.Calendar" == containingClass && "set" == methodName &&
+                parameterIndex > 0
             ) {
                 // Skip the metadata for Calendar.set(int, int, int+); see
                 // https://code.google.com/p/android/issues/detail?id=73982
@@ -313,25 +464,18 @@
     }
 
     private fun mergeField(item: Element, containingClass: String, classItem: ClassItem, fieldName: String) {
-        if (apiFilter != null &&
-            !hasHistoricData(item) &&
-            !apiFilter.hasField(containingClass, fieldName)
-        ) {
-            if (listIgnored) {
-                warning(
-                    "Skipping imported element because it is not part of the API file: "
-                            + containingClass + "#" + fieldName
-                )
-            }
-        } else {
-            val fieldItem = classItem.findField(fieldName)
-            if (fieldItem == null) {
-                warning("Could not find field $fieldName in $containingClass; omitting annotations merge")
+
+        val fieldItem = classItem.findField(fieldName)
+        if (fieldItem == null) {
+            if (wellKnownIgnoredImport(containingClass)) {
                 return
             }
 
-            mergeAnnotations(item, fieldItem)
+            warning("Could not find field $fieldName in $containingClass; omitting annotation from merge")
+            return
         }
+
+        mergeAnnotations(item, fieldItem)
     }
 
     private fun getAnnotationName(element: Element): String {
@@ -343,53 +487,82 @@
         return qualifiedName
     }
 
-    private fun mergeAnnotations(xmlElement: Element, item: Item): Int {
-        var count = 0
-
+    private fun mergeAnnotations(xmlElement: Element, item: Item) {
         loop@ for (annotationElement in getChildren(xmlElement)) {
-            val qualifiedName = getAnnotationName(annotationElement)
-            if (!AnnotationItem.isSignificantAnnotation(qualifiedName)) {
-                continue
-            }
-            var haveNullable = false
-            var haveNotNull = false
-            for (existing in item.modifiers.annotations()) {
-                val name = existing.qualifiedName() ?: continue
-                if (isNonNull(name)) {
-                    haveNotNull = true
-                }
-                if (isNullable(name)) {
-                    haveNullable = true
-                }
-                if (name == qualifiedName) {
-                    continue@loop
-                }
-            }
-
-            // Make sure we don't have a conflict between nullable and not nullable
-            if (isNonNull(qualifiedName) && haveNullable || isNullable(qualifiedName) && haveNotNull) {
-                warning("Found both @Nullable and @NonNull after import for " + item)
-                continue
+            val originalName = getAnnotationName(annotationElement)
+            val qualifiedName = AnnotationItem.mapName(codebase, originalName) ?: originalName
+            if (hasNullnessConflicts(item, qualifiedName)) {
+                continue@loop
             }
 
             val annotationItem = createAnnotation(annotationElement) ?: continue
             item.mutableModifiers().addAnnotation(annotationItem)
-            count++
+        }
+    }
+
+    private fun hasNullnessConflicts(
+        item: Item,
+        qualifiedName: String
+    ): Boolean {
+        var haveNullable = false
+        var haveNotNull = false
+        for (existing in item.modifiers.annotations()) {
+            val name = existing.qualifiedName() ?: continue
+            if (isNonNull(name)) {
+                haveNotNull = true
+            }
+            if (isNullable(name)) {
+                haveNullable = true
+            }
+            if (name == qualifiedName) {
+                return true
+            }
         }
 
-        return count
+        // Make sure we don't have a conflict between nullable and not nullable
+        if (isNonNull(qualifiedName) && haveNullable || isNullable(qualifiedName) && haveNotNull) {
+            warning("Found both @Nullable and @NonNull after import for $item")
+            return true
+        }
+        return false
     }
 
     /** Reads in annotation data from an XML item (using IntelliJ IDE's external annotations XML format) and
      * creates a corresponding [AnnotationItem], performing some "translations" in the process (e.g. mapping
-     * from IntelliJ annotations like `org.jetbrains.annotations.Nullable` to `android.support.annotation.Nullable`,
-     * as well as dropping constants from typedefs that aren't included according to the [apiFilter]. */
+     * from IntelliJ annotations like `org.jetbrains.annotations.Nullable` to `android.support.annotation.Nullable`. */
     private fun createAnnotation(annotationElement: Element): AnnotationItem? {
         val tagName = annotationElement.tagName
         assert(tagName == "annotation") { tagName }
         val name = annotationElement.getAttribute(ATTR_NAME)
         assert(name != null && !name.isEmpty())
         when {
+            name == "org.jetbrains.annotations.Range" -> {
+                val children = getChildren(annotationElement)
+                assert(children.size == 2) { children.size }
+                val valueElement1 = children[0]
+                val valueElement2 = children[1]
+                val valName1 = valueElement1.getAttribute(ATTR_NAME)
+                val value1 = valueElement1.getAttribute(ATTR_VAL)
+                val valName2 = valueElement2.getAttribute(ATTR_NAME)
+                val value2 = valueElement2.getAttribute(ATTR_VAL)
+                return PsiAnnotationItem.create(
+                    codebase, XmlBackedAnnotationItem(
+                        codebase, AnnotationDetector.INT_RANGE_ANNOTATION.newName(),
+                        listOf(
+                            // Add "L" suffix to ensure that we don't for example interpret "-1" as
+                            // an integer -1 and then end up recording it as "ffffffff" instead of -1L
+                            XmlBackedAnnotationAttribute(
+                                valName1,
+                                value1 + (if (value1.last().isDigit()) "L" else "")
+                            ),
+                            XmlBackedAnnotationAttribute(
+                                valName2,
+                                value2 + (if (value2.last().isDigit()) "L" else "")
+                            )
+                        )
+                    )
+                )
+            }
             name == IDEA_MAGIC -> {
                 val children = getChildren(annotationElement)
                 assert(children.size == 1) { children.size }
@@ -415,66 +588,20 @@
                             // It's mainly used for sorting anyway.
                         }
 
-                        if (apiFilter != null) {
-                            // Search in API database
-                            var fields: Set<String>? = apiFilter.getDeclaredIntFields(clsName)
-                            if ("java.util.zip.ZipEntry" == clsName) {
-                                // The metadata says valuesFromClass ZipEntry, and unfortunately
-                                // that class implements ZipConstants and therefore imports a large
-                                // number of irrelevant constants that aren't valid here. Instead,
-                                // only allow these two:
-                                fields = ImmutableSet.of("STORED", "DEFLATED")
-                            }
-
-                            if (fields != null) {
-                                val sorted = ArrayList(fields)
-                                sorted.sort()
-                                if (reflectionFields != null) {
-                                    val rank = HashMap<String, Int>()
-                                    run {
-                                        var i = 0
-                                        val n = sorted.size
-                                        while (i < n) {
-                                            rank[sorted[i]] = reflectionFields.size + i
-                                            i++
-
-                                        }
-                                    }
-                                    var i = 0
-                                    val n = reflectionFields.size
-                                    while (i < n) {
-                                        rank[reflectionFields[i].name] = i
-                                        i++
-                                    }
-                                    sorted.sortWith(Comparator { o1, o2 ->
-                                        val rank1 = rank[o1]
-                                        val rank2 = rank[o2]
-                                        val delta = rank1!! - rank2!!
-                                        if (delta != 0) {
-                                            return@Comparator delta
-
-                                        }
-                                        o1.compareTo(o2)
-                                    })
-                                }
-                                var first = true
-                                for (field in sorted) {
-                                    if (first) {
-                                        first = false
-                                    } else {
-                                        sb.append(',').append(' ')
-                                    }
-                                    sb.append(clsName).append('.').append(field)
-                                }
-                                found = true
-                            }
-                        }
                         // Attempt to sort in reflection order
-                        if (!found && reflectionFields != null && (apiFilter == null || apiFilter.hasClass(clsName))) {
+                        if (!found && reflectionFields != null) {
+                            val filterEmit = ApiVisitor(codebase).filterEmit
+
                             // Attempt with reflection
                             var first = true
                             for (field in reflectionFields) {
                                 if (field.type == Integer.TYPE || field.type == Int::class.javaPrimitiveType) {
+                                    // Make sure this field is included in our API too
+                                    val fieldItem = codebase.findClass(clsName)?.findField(field.name)
+                                    if (fieldItem == null || !filterEmit.test(fieldItem)) {
+                                        continue
+                                    }
+
                                     if (first) {
                                         first = false
                                     } else {
@@ -496,16 +623,6 @@
                     }
                 }
 
-                if (apiFilter != null) {
-                    value = removeFiltered(value)
-                    while (value.contains(", ,")) {
-                        value = value.replace(", ,", ",")
-                    }
-                    if (value.startsWith(", ")) {
-                        value = value.substring(2)
-                    }
-                }
-
                 val attributes = mutableListOf<XmlBackedAnnotationAttribute>()
                 attributes.add(XmlBackedAnnotationAttribute(TYPE_DEF_VALUE_ATTRIBUTE, value))
                 if (flag) {
@@ -514,15 +631,18 @@
                 return PsiAnnotationItem.create(
                     codebase, XmlBackedAnnotationItem(
                         codebase,
-                        if (valName == "stringValues") STRING_DEF_ANNOTATION else INT_DEF_ANNOTATION, attributes
+                        if (valName == "stringValues") STRING_DEF_ANNOTATION.newName() else INT_DEF_ANNOTATION.newName(),
+                        attributes
                     )
                 )
             }
 
-            name == STRING_DEF_ANNOTATION ||
-                    name == ANDROID_STRING_DEF ||
-                    name == INT_DEF_ANNOTATION ||
-                    name == ANDROID_INT_DEF -> {
+            name == STRING_DEF_ANNOTATION.oldName() ||
+                name == STRING_DEF_ANNOTATION.newName() ||
+                name == ANDROID_STRING_DEF ||
+                name == INT_DEF_ANNOTATION.oldName() ||
+                name == INT_DEF_ANNOTATION.newName() ||
+                name == ANDROID_INT_DEF -> {
                 val children = getChildren(annotationElement)
                 var valueElement = children[0]
                 val valName = valueElement.getAttribute(ATTR_NAME)
@@ -534,7 +654,9 @@
                     assert(TYPE_DEF_FLAG_ATTRIBUTE == valueElement.getAttribute(ATTR_NAME))
                     flag = VALUE_TRUE == valueElement.getAttribute(ATTR_VAL)
                 }
-                val intDef = INT_DEF_ANNOTATION == name || ANDROID_INT_DEF == name
+                val intDef = INT_DEF_ANNOTATION.oldName() == name ||
+                    INT_DEF_ANNOTATION.newName() == name ||
+                    ANDROID_INT_DEF == name
 
                 val attributes = mutableListOf<XmlBackedAnnotationAttribute>()
                 attributes.add(XmlBackedAnnotationAttribute(TYPE_DEF_VALUE_ATTRIBUTE, value))
@@ -544,7 +666,7 @@
                 return PsiAnnotationItem.create(
                     codebase, XmlBackedAnnotationItem(
                         codebase,
-                        if (intDef) INT_DEF_ANNOTATION else STRING_DEF_ANNOTATION, attributes
+                        if (intDef) INT_DEF_ANNOTATION.newName() else STRING_DEF_ANNOTATION.newName(), attributes
                     )
                 )
             }
@@ -574,9 +696,9 @@
                 }
             }
 
-            isNonNull(name) -> return codebase.createAnnotation("@$SUPPORT_NOTNULL")
+            isNonNull(name) -> return codebase.createAnnotation("@$ANDROIDX_NOTNULL")
 
-            isNullable(name) -> return codebase.createAnnotation("@$SUPPORT_NULLABLE")
+            isNullable(name) -> return codebase.createAnnotation("@$ANDROIDX_NULLABLE")
 
             else -> {
                 val children = getChildren(annotationElement)
@@ -597,91 +719,21 @@
         }
     }
 
-    private fun removeFiltered(originalValue: String): String {
-        var value = originalValue
-        assert(apiFilter != null)
-        if (value.startsWith("{")) {
-            value = value.substring(1)
-        }
-        if (value.endsWith("}")) {
-            value = value.substring(0, value.length - 1)
-        }
-        value = value.trim { it <= ' ' }
-        val sb = StringBuilder(value.length)
-        sb.append('{')
-        for (escaped in Splitter.on(',').omitEmptyStrings().trimResults().split(value)) {
-            val fqn = unescapeXml(escaped)
-            if (fqn.startsWith("\"")) {
-                continue
-            }
-            val index = fqn.lastIndexOf('.')
-            val cls = fqn.substring(0, index)
-            val field = fqn.substring(index + 1)
-            if (apiFilter?.hasField(cls, field) != false) {
-                if (sb.length > 1) { // 0: '{'
-                    sb.append(", ")
-                }
-                sb.append(fqn)
-            } else if (listIgnored) {
-                warning("Skipping constant from typedef because it is not part of the SDK: " + fqn)
-            }
-        }
-        sb.append('}')
-        return escapeXml(sb.toString())
-    }
-
     private fun isNonNull(name: String): Boolean {
-        return name == IDEA_NOTNULL
-                || name == ANDROID_NOTNULL
-                || name == SUPPORT_NOTNULL
+        return name == IDEA_NOTNULL ||
+            name == ANDROID_NOTNULL ||
+            name == ANDROIDX_NOTNULL ||
+            name == SUPPORT_NOTNULL
     }
 
     private fun isNullable(name: String): Boolean {
-        return name == IDEA_NULLABLE
-                || name == ANDROID_NULLABLE
-                || name == SUPPORT_NULLABLE
+        return name == IDEA_NULLABLE ||
+            name == ANDROID_NULLABLE ||
+            name == ANDROIDX_NULLABLE ||
+            name == SUPPORT_NULLABLE
     }
 
-    /**
-     * Returns true if this XML entry contains historic metadata, e.g. has
-     * an api attribute which designates that this API may no longer be in the SDK,
-     * but the annotations should be preserved for older API levels
-     */
-    private fun hasHistoricData(@NonNull item: Element): Boolean {
-        var curr: Node? = item.firstChild
-        while (curr != null) {
-            // Example:
-            // <item name="android.provider.Browser BOOKMARKS_URI">
-            //   <annotation name="android.support.annotation.RequiresPermission.Read">
-            //     <val name="value" val="&quot;com.android.browser.permission.READ_HISTORY_BOOKMARKS&quot;" />
-            //     <val name="apis" val="&quot;..22&quot;" />
-            //   </annotation>
-            //   ..
-            if (curr.nodeType == Node.ELEMENT_NODE && "annotation" == curr.nodeName) {
-                var inner: Node? = curr.firstChild
-                while (inner != null) {
-                    if (inner.nodeType == Node.ELEMENT_NODE &&
-                        "val" == inner.nodeName &&
-                        "apis" == (inner as Element).getAttribute("name")
-                    ) {
-                        return true
-                    }
-                    inner = inner.nextSibling
-                }
-            }
-            curr = curr.nextSibling
-        }
-
-        return false
-    }
-
-    @NonNull
-    private fun escapeXml(@NonNull unescaped: String): String {
-        return XmlEscapers.xmlAttributeEscaper().escape(unescaped)
-    }
-
-    @NonNull
-    private fun unescapeXml(@NonNull escaped: String): String {
+    private fun unescapeXml(escaped: String): String {
         var workingString = escaped.replace(QUOT_ENTITY, "\"")
         workingString = workingString.replace(LT_ENTITY, "<")
         workingString = workingString.replace(GT_ENTITY, ">")
@@ -718,7 +770,7 @@
         val qualifiedName = qualifiedName() ?: return ""
 
         if (attributes.isEmpty()) {
-            return "@" + qualifiedName
+            return "@$qualifiedName"
         }
 
         val sb = StringBuilder(30)
diff --git a/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt b/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt
index 810e7e1..6cf8127 100644
--- a/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt
+++ b/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt
@@ -16,6 +16,7 @@
 
 package com.android.tools.metalava
 
+import com.android.tools.metalava.doclava1.ApiPredicate
 import com.android.tools.metalava.doclava1.Errors
 import com.android.tools.metalava.model.AnnotationAttributeValue
 import com.android.tools.metalava.model.ClassItem
@@ -30,7 +31,6 @@
 import com.android.tools.metalava.model.TypeItem
 import com.android.tools.metalava.model.visitors.ApiVisitor
 import com.android.tools.metalava.model.visitors.ItemVisitor
-import com.android.tools.metalava.model.visitors.VisibleItemVisitor
 import java.util.ArrayList
 import java.util.HashMap
 import java.util.HashSet
@@ -183,7 +183,7 @@
                     val superConstructor = constructor.superConstructor
                     if (superConstructor == null ||
                         (superConstructor.containingClass() != superClass &&
-                                superConstructor.containingClass() != cls)
+                            superConstructor.containingClass() != cls)
                     ) {
                         constructor.superConstructor = superDefaultConstructor
                     }
@@ -195,7 +195,7 @@
         if (!isLeaf || cls.hasPrivateConstructor || cls.constructors().isNotEmpty()) {
             val constructors = cls.constructors()
             for (constructor in constructors) {
-                if (constructor.parameters().isEmpty() && constructor.isPublic) {
+                if (constructor.parameters().isEmpty() && constructor.isPublic && !constructor.hidden) {
                     cls.defaultConstructor = constructor
                     return
                 }
@@ -274,7 +274,7 @@
         }
 
         val currentUsesAvailableTypes = !referencesExcludedType(current, filter)
-        val nextUsesAvailableTypes = !referencesExcludedType(current, filter)
+        val nextUsesAvailableTypes = !referencesExcludedType(next, filter)
         if (currentUsesAvailableTypes != nextUsesAvailableTypes) {
             return if (currentUsesAvailableTypes) {
                 current
@@ -295,8 +295,7 @@
             val nextParameterCount = next.parameters().size
             if (currentParameterCount <= nextParameterCount) {
                 current
-            } else
-                next
+            } else next
         }
     }
 
@@ -321,7 +320,6 @@
 
         addInheritedStubsFrom(cls, hiddenSuperClasses, superClasses, filterEmit, filterReference)
         addInheritedInterfacesFrom(cls, hiddenSuperClasses, filterReference)
-
     }
 
     private fun addInheritedInterfacesFrom(
@@ -338,7 +336,7 @@
                     if (interfaceTypes == null) {
                         interfaceTypes = cls.interfaceTypes().toMutableList()
                         interfaceTypeClasses =
-                                interfaceTypes.asSequence().map { it.asClass() }.filterNotNull().toMutableList()
+                            interfaceTypes.asSequence().map { it.asClass() }.filterNotNull().toMutableList()
                         if (cls.isInterface()) {
                             cls.superClass()?.let { interfaceTypeClasses.add(it) }
                         }
@@ -369,7 +367,8 @@
         cls: ClassItem,
         hiddenSuperClasses: Sequence<ClassItem>,
         superClasses: Sequence<ClassItem>,
-        filterEmit: Predicate<Item>, filterReference: Predicate<Item>
+        filterEmit: Predicate<Item>,
+        filterReference: Predicate<Item>
     ) {
 
         // Also generate stubs for any methods we would have inherited from abstract parents
@@ -412,21 +411,19 @@
             }
         }
 
-        if (compatibility.includePublicMethodsFromHiddenSuperClasses) {
-            // Also add in any concrete public methods from hidden super classes
-            for (superClass in hiddenSuperClasses) {
-                for (method in superClass.methods()) {
-                    if (method.modifiers.isAbstract()) {
-                        continue
-                    }
-                    val name = method.name()
-                    val list = interfaceNames[name] ?: run {
-                        val list = ArrayList<MethodItem>()
-                        interfaceNames[name] = list
-                        list
-                    }
-                    list.add(method)
+        // Also add in any concrete public methods from hidden super classes
+        for (superClass in hiddenSuperClasses) {
+            for (method in superClass.methods()) {
+                if (method.modifiers.isAbstract()) {
+                    continue
                 }
+                val name = method.name()
+                val list = interfaceNames[name] ?: run {
+                    val list = ArrayList<MethodItem>()
+                    interfaceNames[name] = list
+                    list
+                }
+                list.add(method)
             }
         }
 
@@ -493,9 +490,7 @@
             method.documentation = "// Inlined stub from hidden parent class ${it.containingClass().qualifiedName()}\n" +
                     method.documentation
              */
-            if (it.containingClass().isInterface()) {
-                method.inheritedInterfaceMethod = true
-            }
+            method.inheritedMethod = true
             cls.addMethod(method)
         }
     }
@@ -521,7 +516,7 @@
     fun mergeExternalAnnotations() {
         val mergeAnnotations = options.mergeAnnotations
         if (!mergeAnnotations.isEmpty()) {
-            AnnotationsMerger(codebase, options.apiFilter).merge(mergeAnnotations)
+            AnnotationsMerger(codebase).merge(mergeAnnotations)
         }
     }
 
@@ -531,15 +526,12 @@
      */
     private fun propagateHiddenRemovedAndDocOnly(includingFields: Boolean) {
         packages.accept(object : ItemVisitor(visitConstructorsAsMethods = true, nestInnerClasses = true) {
-            override fun visitItem(item: Item) {
-                if (item.modifiers.hasShowAnnotation()) {
-                    item.hidden = false
-                } else if (item.modifiers.hasHideAnnotations()) {
-                    item.hidden = true
-                }
-            }
-
             override fun visitPackage(pkg: PackageItem) {
+                if (pkg.modifiers.hasShowAnnotation()) {
+                    pkg.hidden = false
+                } else if (pkg.modifiers.hasHideAnnotations()) {
+                    pkg.hidden = true
+                }
                 val containingPackage = pkg.containingPackage()
                 if (containingPackage != null) {
                     if (containingPackage.hidden) {
@@ -553,7 +545,14 @@
 
             override fun visitClass(cls: ClassItem) {
                 val containingClass = cls.containingClass()
-                if (containingClass != null) {
+                if (cls.modifiers.hasShowAnnotation()) {
+                    cls.hidden = false
+                    // Make containing package non-hidden if it contains a show-annotation
+                    // class. Doclava does this in PackageInfo.isHidden().
+                    cls.containingPackage().hidden = false
+                } else if (cls.modifiers.hasHideAnnotations()) {
+                    cls.hidden = true
+                } else if (containingClass != null) {
                     if (containingClass.hidden) {
                         cls.hidden = true
                     }
@@ -578,74 +577,51 @@
             }
 
             override fun visitMethod(method: MethodItem) {
-                val containingClass = method.containingClass()
-                if (containingClass.hidden) {
+                if (method.modifiers.hasShowAnnotation()) {
+                    method.hidden = false
+                } else if (method.modifiers.hasHideAnnotations()) {
                     method.hidden = true
-                }
-                if (containingClass.docOnly) {
-                    method.docOnly = true
-                }
-                if (containingClass.removed) {
-                    method.removed = true
+                } else {
+                    val containingClass = method.containingClass()
+                    if (containingClass.hidden) {
+                        method.hidden = true
+                    }
+                    if (containingClass.docOnly) {
+                        method.docOnly = true
+                    }
+                    if (containingClass.removed) {
+                        method.removed = true
+                    }
                 }
             }
 
             override fun visitField(field: FieldItem) {
-                val containingClass = field.containingClass()
-                /* We don't always propagate field visibility down to the fields
-                   because we sometimes move fields around, and in that
-                   case we don't want to carry forward the "hidden" attribute
-                   from the field that wasn't marked on the field but its
-                   container interface.
-                */
-                if (includingFields && containingClass.hidden) {
+                if (field.modifiers.hasShowAnnotation()) {
+                    field.hidden = false
+                } else if (field.modifiers.hasHideAnnotations()) {
                     field.hidden = true
-                }
-                if (containingClass.docOnly) {
-                    field.docOnly = true
-                }
-                if (containingClass.removed) {
-                    field.removed = true
+                } else {
+                    val containingClass = field.containingClass()
+                    /* We don't always propagate field visibility down to the fields
+                       because we sometimes move fields around, and in that
+                       case we don't want to carry forward the "hidden" attribute
+                       from the field that wasn't marked on the field but its
+                       container interface.
+                    */
+                    if (includingFields && containingClass.hidden) {
+                        field.hidden = true
+                    }
+                    if (containingClass.docOnly) {
+                        field.docOnly = true
+                    }
+                    if (containingClass.removed) {
+                        field.removed = true
+                    }
                 }
             }
         })
     }
 
-    private fun applyApiFilter() {
-        options.apiFilter?.let { filter ->
-            packages.accept(object : VisibleItemVisitor() {
-
-                override fun visitPackage(pkg: PackageItem) {
-                    if (!filter.hasPackage(pkg.qualifiedName())) {
-                        pkg.included = false
-                    }
-                }
-
-                override fun visitClass(cls: ClassItem) {
-                    if (!filter.hasClass(cls.qualifiedName())) {
-                        cls.included = false
-                    }
-                }
-
-                override fun visitMethod(method: MethodItem) {
-                    if (!filter.hasMethod(
-                            method.containingClass().qualifiedName(), method.name(),
-                            method.formatParameters()
-                        )
-                    ) {
-                        method.included = false
-                    }
-                }
-
-                override fun visitField(field: FieldItem) {
-                    if (!filter.hasField(field.containingClass().qualifiedName(), field.name())) {
-                        field.included = false
-                    }
-                }
-            })
-        }
-    }
-
     private fun checkHiddenTypes() {
         packages.accept(object : ApiVisitor(codebase, visitConstructorsAsMethods = false) {
             override fun visitMethod(method: MethodItem) {
@@ -769,8 +745,8 @@
                         )
                         continue
                     }
-                    if (level.contains("normal") || level.contains("dangerous")
-                        || level.contains("ephemeral")
+                    if (level.contains("normal") || level.contains("dangerous") ||
+                        level.contains("ephemeral")
                     ) {
                         nonSystem.add(perm)
                     } else {
@@ -781,7 +757,7 @@
                     reporter.report(
                         Errors.REMOVED_FIELD, method,
                         "None of the permissions ${missing.joinToString()} are defined by manifest " +
-                                "${codebase.manifest}."
+                            "${codebase.manifest}."
                     )
                 }
 
@@ -789,9 +765,9 @@
                     hasAnnotation = false
                 } else if (any && !nonSystem.isEmpty() || !any && system.isEmpty()) {
                     reporter.report(
-                        Errors.REQUIRES_PERMISSION, method, "Method '" + method.name()
-                                + "' must be protected with a system permission; it currently"
-                                + " allows non-system callers holding " + nonSystem.toString()
+                        Errors.REQUIRES_PERMISSION, method, "Method '" + method.name() +
+                            "' must be protected with a system permission; it currently" +
+                            " allows non-system callers holding " + nonSystem.toString()
                     )
                 }
             }
@@ -799,8 +775,8 @@
 
         if (!hasAnnotation) {
             reporter.report(
-                Errors.REQUIRES_PERMISSION, method, "Method '" + method.name()
-                        + "' must be protected with a system permission."
+                Errors.REQUIRES_PERMISSION, method, "Method '" + method.name() +
+                    "' must be protected with a system permission."
             )
         }
     }
@@ -832,7 +808,7 @@
 
     fun handleStripping() {
         // TODO: Switch to visitor iteration
-        //val stubPackages = options.stubPackages
+        // val stubPackages = options.stubPackages
         val stubImportPackages = options.stubImportPackages
         handleStripping(stubImportPackages)
     }
@@ -840,13 +816,15 @@
     private fun handleStripping(stubImportPackages: Set<String>) {
         val notStrippable = HashSet<ClassItem>(5000)
 
+        val filter = ApiPredicate(codebase, ignoreShown = true)
+
         // If a class is public or protected, not hidden, not imported and marked as included,
         // then we can't strip it
         val allTopLevelClasses = codebase.getPackages().allTopLevelClasses().toList()
         allTopLevelClasses
             .filter { it.checkLevel() && it.emit && !it.hidden() }
             .forEach {
-                cantStripThis(it, notStrippable, stubImportPackages)
+                cantStripThis(it, filter, notStrippable, stubImportPackages)
             }
 
         // complain about anything that looks includeable but is not supposed to
@@ -866,8 +844,8 @@
                         // don't bother reporting deprecated methods
                         // unless they are public
                         reporter.report(
-                            Errors.DEPRECATED, m, "Method " + cl.qualifiedName() + "."
-                                    + m.name() + " is deprecated"
+                            Errors.DEPRECATED, m, "Method " + cl.qualifiedName() + "." +
+                                m.name() + " is deprecated"
                         )
                     }
 
@@ -879,14 +857,14 @@
                             reporter.report(
                                 Errors.UNAVAILABLE_SYMBOL, m,
                                 "Method ${cl.qualifiedName()}.${m.name()} returns unavailable " +
-                                        "type ${hiddenClass.simpleName()}"
+                                    "type ${hiddenClass.simpleName()}"
                             )
                         } else {
                             // Return type contains a generic parameter
                             reporter.report(
                                 Errors.HIDDEN_TYPE_PARAMETER, m,
                                 "Method ${cl.qualifiedName()}.${m.name()} returns unavailable " +
-                                        "type ${hiddenClass.simpleName()} as a type parameter"
+                                    "type ${hiddenClass.simpleName()} as a type parameter"
                             )
                         }
                     }
@@ -916,12 +894,17 @@
             } else if (cl.deprecated) {
                 // not hidden, but deprecated
                 reporter.report(Errors.DEPRECATED, cl, "Class ${cl.qualifiedName()} is deprecated")
+            } else {
+                // Bring this class back
+                cl.hidden = false
+                cl.removed = false
             }
         }
     }
 
     private fun cantStripThis(
         cl: ClassItem,
+        filter: Predicate<Item>,
         notStrippable: MutableSet<ClassItem>,
         stubImportPackages: Set<String>?
     ) {
@@ -942,43 +925,36 @@
 
         // cant strip any public fields or their generics
         for (field in cl.fields()) {
-            if (!field.checkLevel()) {
+            if (!filter.test(field)) {
                 continue
             }
             val fieldType = field.type()
             if (!fieldType.primitive) {
                 val typeClass = fieldType.asClass()
                 if (typeClass != null) {
-                    cantStripThis(
-                        typeClass, notStrippable, stubImportPackages
-                    )
+                    cantStripThis(typeClass, filter, notStrippable, stubImportPackages)
                 }
                 for (cls in fieldType.typeArgumentClasses()) {
-                    cantStripThis(
-                        cls, notStrippable, stubImportPackages
-                    )
+                    cantStripThis(cls, filter, notStrippable, stubImportPackages)
                 }
             }
         }
         // cant strip any of the type's generics
         for (cls in cl.typeArgumentClasses()) {
-            cantStripThis(
-                cls, notStrippable, stubImportPackages
-            )
+            cantStripThis(cls, filter, notStrippable, stubImportPackages)
         }
         // cant strip any of the annotation elements
         // cantStripThis(cl.annotationElements(), notStrippable);
         // take care of methods
-        cantStripThis(cl.methods(), notStrippable, stubImportPackages)
-        cantStripThis(cl.constructors(), notStrippable, stubImportPackages)
+        cantStripThis(cl.methods(), filter, notStrippable, stubImportPackages)
+        cantStripThis(cl.constructors(), filter, notStrippable, stubImportPackages)
         // blow the outer class open if this is an inner class
         val containingClass = cl.containingClass()
         if (containingClass != null) {
-            cantStripThis(
-                containingClass, notStrippable, stubImportPackages
-            )
+            cantStripThis(containingClass, filter, notStrippable, stubImportPackages)
         }
         // blow open super class and interfaces
+        // TODO: Consider using val superClass = cl.filteredSuperclass(filter)
         val superClass = cl.superClass()
         if (superClass != null) {
             if (superClass.isHiddenOrRemoved()) {
@@ -991,18 +967,16 @@
                 cl.setSuperClass(publicSuper)
                 if (!superClass.isFromClassPath()) {
                     reporter.report(
-                        Errors.HIDDEN_SUPERCLASS, cl, "Public class " + cl.qualifiedName()
-                                + " stripped of unavailable superclass " + superClass.qualifiedName()
+                        Errors.HIDDEN_SUPERCLASS, cl, "Public class " + cl.qualifiedName() +
+                            " stripped of unavailable superclass " + superClass.qualifiedName()
                     )
                 }
             } else {
-                cantStripThis(
-                    superClass, notStrippable, stubImportPackages
-                )
+                cantStripThis(superClass, filter, notStrippable, stubImportPackages)
                 if (superClass.isPrivate && !superClass.isFromClassPath()) {
                     reporter.report(
-                        Errors.PRIVATE_SUPERCLASS, cl, "Public class "
-                                + cl.qualifiedName() + " extends private class " + superClass.qualifiedName()
+                        Errors.PRIVATE_SUPERCLASS, cl, "Public class " +
+                            cl.qualifiedName() + " extends private class " + superClass.qualifiedName()
                     )
                 }
             }
@@ -1010,60 +984,46 @@
     }
 
     private fun cantStripThis(
-        methods: List<MethodItem>, notStrippable: MutableSet<ClassItem>,
+        methods: List<MethodItem>,
+        filter: Predicate<Item>,
+        notStrippable: MutableSet<ClassItem>,
         stubImportPackages: Set<String>?
     ) {
         // for each method, blow open the parameters, throws and return types. also blow open their
         // generics
         for (method in methods) {
-            if (!method.checkLevel()) {
+            if (!filter.test(method)) {
                 continue
             }
             for (typeParameterClass in method.typeArgumentClasses()) {
-                cantStripThis(
-                    typeParameterClass, notStrippable,
-                    stubImportPackages
-                )
+                cantStripThis(typeParameterClass, filter, notStrippable, stubImportPackages)
             }
             for (parameter in method.parameters()) {
                 for (parameterTypeClass in parameter.type().typeArgumentClasses()) {
-                    cantStripThis(
-                        parameterTypeClass, notStrippable, stubImportPackages
-                    )
+                    cantStripThis(parameterTypeClass, filter, notStrippable, stubImportPackages)
                     for (tcl in parameter.type().typeArgumentClasses()) {
                         if (tcl.isHiddenOrRemoved()) {
                             reporter.report(
                                 Errors.UNAVAILABLE_SYMBOL, method,
                                 "Parameter of hidden type ${tcl.fullName()}" +
-                                        "in ${method.containingClass().qualifiedName()}.${method.name()}()"
+                                    "in ${method.containingClass().qualifiedName()}.${method.name()}()"
                             )
                         } else {
-                            cantStripThis(
-                                tcl, notStrippable,
-                                stubImportPackages
-                            )
+                            cantStripThis(tcl, filter, notStrippable, stubImportPackages)
                         }
                     }
                 }
             }
             for (thrown in method.throwsTypes()) {
-                cantStripThis(
-                    thrown, notStrippable, stubImportPackages
-                )
+                cantStripThis(thrown, filter, notStrippable, stubImportPackages)
             }
             val returnType = method.returnType()
             if (returnType != null && !returnType.primitive) {
                 val returnTypeClass = returnType.asClass()
                 if (returnTypeClass != null) {
-                    cantStripThis(
-                        returnTypeClass, notStrippable,
-                        stubImportPackages
-                    )
+                    cantStripThis(returnTypeClass, filter, notStrippable, stubImportPackages)
                     for (tyItem in returnType.typeArgumentClasses()) {
-                        cantStripThis(
-                            tyItem, notStrippable,
-                            stubImportPackages
-                        )
+                        cantStripThis(tyItem, filter, notStrippable, stubImportPackages)
                     }
                 }
             }
diff --git a/src/main/java/com/android/tools/metalava/ArtifactTagger.kt b/src/main/java/com/android/tools/metalava/ArtifactTagger.kt
new file mode 100644
index 0000000..23c9be7
--- /dev/null
+++ b/src/main/java/com/android/tools/metalava/ArtifactTagger.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.metalava.doclava1.ApiFile
+import com.android.tools.metalava.doclava1.ApiParseException
+import com.android.tools.metalava.doclava1.Errors
+import com.android.tools.metalava.doclava1.TextCodebase
+import com.android.tools.metalava.model.ClassItem
+import com.android.tools.metalava.model.Codebase
+import com.android.tools.metalava.model.visitors.ApiVisitor
+import java.io.File
+
+/** Registry of signature files and the corresponding artifact descriptions */
+class ArtifactTagger {
+    /** Ordered map from signature file to artifact description */
+    private val artifacts = LinkedHashMap<File, String>()
+
+    /** Registers the given [artifactId] for the APIs found in the given [signatureFile] */
+    fun register(artifactId: String, signatureFile: File) {
+        artifacts[signatureFile] = artifactId
+    }
+
+    /** Any registered artifacts? */
+    fun any() = artifacts.isNotEmpty()
+
+    /** Returns the artifacts */
+    private fun getRegistrations(): Collection<Map.Entry<File, String>> = artifacts.entries
+
+    /**
+     * Applies the artifact registrations in this map to the given [codebase].
+     * If [warnAboutMissing] is true, it will complain if any classes in the API
+     * are found that have not been tagged (e.g. where no artifact signature file
+     * referenced the API.
+     */
+    fun tag(codebase: Codebase, warnAboutMissing: Boolean = true) {
+        if (!any()) {
+            return
+        }
+
+        // Read through the XML files in order, applying their artifact information
+        // to the Javadoc models.
+        for (artifactSpec in getRegistrations()) {
+            val xmlFile = artifactSpec.key
+            val artifactName = artifactSpec.value
+
+            val specApi: TextCodebase
+            try {
+                val kotlinStyleNulls = options.inputKotlinStyleNulls
+                specApi = ApiFile.parseApi(xmlFile, kotlinStyleNulls, false)
+            } catch (e: ApiParseException) {
+                reporter.report(
+                    Errors.BROKEN_ARTIFACT_FILE, xmlFile,
+                    "Failed to parse $xmlFile for $artifactName artifact data.\n"
+                )
+                continue
+            }
+
+            applyArtifactsFromSpec(artifactName, specApi, codebase)
+        }
+
+        if (warnAboutMissing) {
+            codebase.accept(object : ApiVisitor(codebase) {
+                override fun visitClass(cls: ClassItem) {
+                    if (cls.artifact == null && cls.isTopLevelClass()) {
+                        reporter.report(
+                            Errors.NO_ARTIFACT_DATA, cls,
+                            "No registered artifact signature file referenced class ${cls.qualifiedName()}"
+                        )
+                    }
+                }
+            })
+        }
+    }
+
+    private fun applyArtifactsFromSpec(
+        mavenSpec: String,
+        specApi: TextCodebase,
+        codebase: Codebase
+    ) {
+        for (specPkg in specApi.getPackages().packages) {
+            val pkg = codebase.findPackage(specPkg.qualifiedName()) ?: continue
+            for (cls in pkg.allClasses()) {
+                if (cls.artifact == null) {
+                    cls.artifact = mavenSpec
+                } else {
+                    reporter.report(
+                        Errors.BROKEN_ARTIFACT_FILE, cls,
+                        "Class ${cls.qualifiedName()} belongs to multiple artifacts: ${cls.artifact} and $mavenSpec"
+                    )
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/metalava/ComparisonVisitor.kt b/src/main/java/com/android/tools/metalava/ComparisonVisitor.kt
index ff1a430..1c6e2f6 100644
--- a/src/main/java/com/android/tools/metalava/ComparisonVisitor.kt
+++ b/src/main/java/com/android/tools/metalava/ComparisonVisitor.kt
@@ -26,6 +26,7 @@
 import com.android.tools.metalava.model.PackageItem
 import com.android.tools.metalava.model.ParameterItem
 import com.android.tools.metalava.model.visitors.ApiVisitor
+import com.android.tools.metalava.model.visitors.VisibleItemVisitor
 import com.intellij.util.containers.Stack
 import java.util.Comparator
 import java.util.function.Predicate
@@ -41,11 +42,18 @@
      * instead of just a [#visitConstructor] call. Helps simplify visitors that
      * don't care to distinguish between the two cases. Defaults to true.
      */
-    val visitConstructorsAsMethods: Boolean = true
+    val visitConstructorsAsMethods: Boolean = true,
+    /**
+     * Normally if a new item is found, the visitor will
+     * only visit the top level newly added item, not all
+     * of its children. This flags enables you to request
+     * all individual items to also be visited.
+     */
+    val visitAddedItemsRecursively: Boolean = false
 ) {
     open fun compare(old: Item, new: Item) {}
-    open fun added(item: Item) {}
-    open fun removed(item: Item, from: Item?) {}
+    open fun added(new: Item) {}
+    open fun removed(old: Item, from: Item?) {}
 
     open fun compare(old: PackageItem, new: PackageItem) {}
     open fun compare(old: ClassItem, new: ClassItem) {}
@@ -54,19 +62,19 @@
     open fun compare(old: FieldItem, new: FieldItem) {}
     open fun compare(old: ParameterItem, new: ParameterItem) {}
 
-    open fun added(item: PackageItem) {}
-    open fun added(item: ClassItem) {}
-    open fun added(item: ConstructorItem) {}
-    open fun added(item: MethodItem) {}
-    open fun added(item: FieldItem) {}
-    open fun added(item: ParameterItem) {}
+    open fun added(new: PackageItem) {}
+    open fun added(new: ClassItem) {}
+    open fun added(new: ConstructorItem) {}
+    open fun added(new: MethodItem) {}
+    open fun added(new: FieldItem) {}
+    open fun added(new: ParameterItem) {}
 
-    open fun removed(item: PackageItem, from: Item?) {}
-    open fun removed(item: ClassItem, from: Item?) {}
-    open fun removed(item: ConstructorItem, from: ClassItem?) {}
-    open fun removed(item: MethodItem, from: ClassItem?) {}
-    open fun removed(item: FieldItem, from: ClassItem?) {}
-    open fun removed(item: ParameterItem, from: MethodItem?) {}
+    open fun removed(old: PackageItem, from: Item?) {}
+    open fun removed(old: ClassItem, from: Item?) {}
+    open fun removed(old: ConstructorItem, from: ClassItem?) {}
+    open fun removed(old: MethodItem, from: ClassItem?) {}
+    open fun removed(old: FieldItem, from: ClassItem?) {}
+    open fun removed(old: ParameterItem, from: MethodItem?) {}
 }
 
 class CodebaseComparator {
@@ -83,7 +91,9 @@
     }
 
     private fun compare(
-        visitor: ComparisonVisitor, oldList: List<ItemTree>, newList: List<ItemTree>,
+        visitor: ComparisonVisitor,
+        oldList: List<ItemTree>,
+        newList: List<ItemTree>,
         newParent: Item?
     ) {
         // Debugging tip: You can print out a tree like this: ItemTree.prettyPrint(list)
@@ -121,7 +131,6 @@
                             index2++
                         }
                     }
-
                 } else {
                     // All the remaining items in oldList have been deleted
                     while (index1 < length1) {
@@ -139,8 +148,20 @@
         }
     }
 
+    private fun visitAdded(visitor: ComparisonVisitor, new: Item) {
+        if (visitor.visitAddedItemsRecursively) {
+            new.accept(object : VisibleItemVisitor() {
+                override fun visitItem(item: Item) {
+                    doVisitAdded(visitor, item)
+                }
+            })
+        } else {
+            doVisitAdded(visitor, new)
+        }
+    }
+
     @Suppress("USELESS_CAST") // Overloaded visitor methods: be explicit about which one is being invoked
-    private fun visitAdded(visitor: ComparisonVisitor, item: Item) {
+    private fun doVisitAdded(visitor: ComparisonVisitor, item: Item) {
         visitor.added(item)
 
         when (item) {
diff --git a/src/main/java/com/android/tools/metalava/Compatibility.kt b/src/main/java/com/android/tools/metalava/Compatibility.kt
index 564e4b9..5c21e38 100644
--- a/src/main/java/com/android/tools/metalava/Compatibility.kt
+++ b/src/main/java/com/android/tools/metalava/Compatibility.kt
@@ -65,6 +65,9 @@
     /** Include spaces after commas in type strings */
     var spacesAfterCommas: Boolean = compat
 
+    /** Use two spaces after type for package private elements in signature files */
+    var doubleSpaceForPackagePrivate: Boolean = compat
+
     /**
      * In signature files, whether interfaces should also be described as "abstract"
      */
@@ -89,6 +92,13 @@
     var useErasureInThrows: Boolean = compat
 
     /**
+     * Whether throws classes in methods should be filtered. This should definitely
+     * be the case, but doclava1 doesn't. Note that this only applies to signature
+     * files, not stub files.
+     */
+    var filterThrowsClasses: Boolean = !compat
+
+    /**
      * Include a single space in front of package private classes with no other modifiers
      * (this doesn't align well, but is supported to make the output 100% identical to the
      * doclava1 format
@@ -150,8 +160,11 @@
      * included in the stubs etc (since otherwise subclasses would believe they need
      * to implement that method and can't just inherit it). However, doclava1 does not
      * list these methods. This flag controls this compatibility behavior.
+     * Not that this refers only to the signature files, not the stub file generation.
+     *
+     * An example is StringBuilder#setLength.
      */
-    var skipInheritedInterfaceMethods: Boolean = compat
+    var skipInheritedMethods: Boolean = compat
 
     /**
      * Whether to include parameter names in the signature file
@@ -159,12 +172,11 @@
     var parameterNames: Boolean = true
 
     /**
-     * Whether we should include public methods from super classes.
-     * Doclava1 did not do this in its signature files, but they
-     * were included in stub files. An example of this scenario
-     * is StringBuilder#setLength.
+     * *Some* signatures for doclava1 wrote "<?>" as "<? extends java.lang.Object>",
+     * which is equivalent. Metalava does not do that. This flags ensures that the
+     * signature files look like the old ones for the specific methods which did this.
      */
-    var includePublicMethodsFromHiddenSuperClasses = !compat
+    var includeExtendsObjectInWildcard = compat
 
     // Other examples: sometimes we sort by qualified name, sometimes by full name
 }
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/metalava/CompatibilityCheck.kt b/src/main/java/com/android/tools/metalava/CompatibilityCheck.kt
index ba19c59..ab77657 100644
--- a/src/main/java/com/android/tools/metalava/CompatibilityCheck.kt
+++ b/src/main/java/com/android/tools/metalava/CompatibilityCheck.kt
@@ -67,14 +67,14 @@
                             Errors.INVALID_NULL_CONVERSION,
                             new,
                             "Attempted to change parameter from @Nullable to @NonNull: " +
-                                    "incompatible change for ${describe(new)}"
+                                "incompatible change for ${describe(new)}"
                         )
                     } else if (!oldNullable && old is MethodItem) {
                         report(
                             Errors.INVALID_NULL_CONVERSION,
                             new,
                             "Attempted to change method return from @NonNull to @Nullable: " +
-                                    "incompatible change for ${describe(new)}"
+                                "incompatible change for ${describe(new)}"
                         )
                     }
                 }
@@ -172,7 +172,6 @@
             }
         }
 
-
         if (!oldModifiers.isSealed() && newModifiers.isSealed()) {
             report(Errors.ADD_SEALED, new, "Cannot add `sealed` modifier to ${describe(new)}: Incompatible change")
         } else if (oldModifiers.isAbstract() != newModifiers.isAbstract()) {
@@ -273,8 +272,8 @@
             val oldTypeParameter = oldReturnType.asTypeParameter(old)
             val newTypeParameter = newReturnType.asTypeParameter(new)
             var compatible = true
-            if (oldTypeParameter == null
-                && newTypeParameter == null
+            if (oldTypeParameter == null &&
+                newTypeParameter == null
             ) {
                 if (oldReturnType != newReturnType ||
                     oldReturnType.arrayDimensions() != newReturnType.arrayDimensions()
@@ -429,11 +428,11 @@
         constraints: List<ClassItem>
     ): String {
         return type.toSimpleType() +
-                if (constraints.isEmpty()) {
-                    " (extends java.lang.Object)"
-                } else {
-                    " (extends ${constraints.joinToString(separator = " & ") { it.qualifiedName() }})"
-                }
+            if (constraints.isEmpty()) {
+                " (extends java.lang.Object)"
+            } else {
+                " (extends ${constraints.joinToString(separator = " & ") { it.qualifiedName() }})"
+            }
     }
 
     override fun compare(old: FieldItem, new: FieldItem) {
@@ -527,23 +526,23 @@
         report(error, item, "Removed ${if (item.deprecated) "deprecated " else ""}${describe(item)}")
     }
 
-    override fun added(item: PackageItem) {
-        handleAdded(Errors.ADDED_PACKAGE, item)
+    override fun added(new: PackageItem) {
+        handleAdded(Errors.ADDED_PACKAGE, new)
     }
 
-    override fun added(item: ClassItem) {
-        val error = if (item.isInterface()) {
+    override fun added(new: ClassItem) {
+        val error = if (new.isInterface()) {
             Errors.ADDED_INTERFACE
         } else {
             Errors.ADDED_CLASS
         }
-        handleAdded(error, item)
+        handleAdded(error, new)
     }
 
-    override fun added(item: MethodItem) {
+    override fun added(new: MethodItem) {
         // *Overriding* methods from super classes that are outside the
         // API is OK (e.g. overriding toString() from java.lang.Object)
-        val superMethods = item.superMethods()
+        val superMethods = new.superMethods()
         for (superMethod in superMethods) {
             if (superMethod.isFromClassPath()) {
                 return
@@ -554,64 +553,64 @@
         // existing superclass method, but we should fail if this is overriding
         // an abstract method, because method's abstractness affects how users use it.
         // See if there's a member from inherited class
-        val inherited = if (item.isConstructor()) {
+        val inherited = if (new.isConstructor()) {
             null
         } else {
-            item.containingClass().findMethod(
-                item,
+            new.containingClass().findMethod(
+                new,
                 includeSuperClasses = true,
                 includeInterfaces = false
             )
         }
         if (inherited != null && !inherited.modifiers.isAbstract()) {
-            val error = if (item.modifiers.isAbstract()) Errors.ADDED_ABSTRACT_METHOD else Errors.ADDED_METHOD
-            handleAdded(error, item)
+            val error = if (new.modifiers.isAbstract()) Errors.ADDED_ABSTRACT_METHOD else Errors.ADDED_METHOD
+            handleAdded(error, new)
         }
     }
 
-    override fun added(item: FieldItem) {
-        handleAdded(Errors.ADDED_FIELD, item)
+    override fun added(new: FieldItem) {
+        handleAdded(Errors.ADDED_FIELD, new)
     }
 
-    override fun removed(item: PackageItem, from: Item?) {
-        handleRemoved(Errors.REMOVED_PACKAGE, item)
+    override fun removed(old: PackageItem, from: Item?) {
+        handleRemoved(Errors.REMOVED_PACKAGE, old)
     }
 
-    override fun removed(item: ClassItem, from: Item?) {
+    override fun removed(old: ClassItem, from: Item?) {
         val error = when {
-            item.isInterface() -> Errors.REMOVED_INTERFACE
-            item.deprecated -> Errors.REMOVED_DEPRECATED_CLASS
+            old.isInterface() -> Errors.REMOVED_INTERFACE
+            old.deprecated -> Errors.REMOVED_DEPRECATED_CLASS
             else -> Errors.REMOVED_CLASS
         }
-        handleRemoved(error, item)
+        handleRemoved(error, old)
     }
 
-    override fun removed(item: MethodItem, from: ClassItem?) {
+    override fun removed(old: MethodItem, from: ClassItem?) {
         // See if there's a member from inherited class
-        val inherited = if (item.isConstructor()) {
+        val inherited = if (old.isConstructor()) {
             null
         } else {
             from?.findMethod(
-                item,
+                old,
                 includeSuperClasses = true,
                 includeInterfaces = from.isInterface()
             )
         }
         if (inherited == null) {
-            val error = if (item.deprecated) Errors.REMOVED_DEPRECATED_METHOD else Errors.REMOVED_METHOD
-            handleRemoved(error, item)
+            val error = if (old.deprecated) Errors.REMOVED_DEPRECATED_METHOD else Errors.REMOVED_METHOD
+            handleRemoved(error, old)
         }
     }
 
-    override fun removed(item: FieldItem, from: ClassItem?) {
+    override fun removed(old: FieldItem, from: ClassItem?) {
         val inherited = from?.findField(
-            item.name(),
+            old.name(),
             includeSuperClasses = true,
             includeInterfaces = from.isInterface()
         )
         if (inherited == null) {
-            val error = if (item.deprecated) Errors.REMOVED_DEPRECATED_FIELD else Errors.REMOVED_FIELD
-            handleRemoved(error, item)
+            val error = if (old.deprecated) Errors.REMOVED_DEPRECATED_FIELD else Errors.REMOVED_FIELD
+            handleRemoved(error, old)
         }
     }
 
diff --git a/src/main/java/com/android/tools/metalava/Constants.kt b/src/main/java/com/android/tools/metalava/Constants.kt
index 7badba3..d863b9b 100644
--- a/src/main/java/com/android/tools/metalava/Constants.kt
+++ b/src/main/java/com/android/tools/metalava/Constants.kt
@@ -22,4 +22,9 @@
 const val JAVA_LANG_ENUM = "java.lang.Enum"
 const val JAVA_LANG_ANNOTATION = "java.lang.annotation.Annotation"
 const val ANDROID_SUPPORT_ANNOTATION_PREFIX = "android.support.annotation."
-
+const val ANDROID_ANNOTATION_PREFIX = "android.annotation."
+const val ANDROIDX_ANNOTATION_PREFIX = "androidx.annotation."
+const val ANDROIDX_NOTNULL = "androidx.annotation.NonNull"
+const val ANDROIDX_NULLABLE = "androidx.annotation.Nullable"
+const val RECENTLY_NULLABLE = "androidx.annotation.RecentlyNullable"
+const val RECENTLY_NONNULL = "androidx.annotation.RecentlyNonNull"
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/metalava/DexApiWriter.kt b/src/main/java/com/android/tools/metalava/DexApiWriter.kt
index 15b4573..27952a5 100644
--- a/src/main/java/com/android/tools/metalava/DexApiWriter.kt
+++ b/src/main/java/com/android/tools/metalava/DexApiWriter.kt
@@ -27,11 +27,12 @@
 class DexApiWriter(
     private val writer: PrintWriter,
     filterEmit: Predicate<Item>,
-    filterReference: Predicate<Item>
+    filterReference: Predicate<Item>,
+    inlineInheritedFields: Boolean = true
 ) : ApiVisitor(
     visitConstructorsAsMethods = true,
     nestInnerClasses = false,
-    inlineInheritedFields = true,
+    inlineInheritedFields = inlineInheritedFields,
     filterEmit = filterEmit,
     filterReference = filterReference
 ) {
@@ -43,6 +44,10 @@
     }
 
     override fun visitMethod(method: MethodItem) {
+        if (method.inheritedMethod) {
+            return
+        }
+
         writer.print(method.containingClass().toType().internalName())
         writer.print("->")
         writer.print(method.internalName())
diff --git a/src/main/java/com/android/tools/metalava/DocAnalyzer.kt b/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
index 1e8d470..2c91eaa 100644
--- a/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
+++ b/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
@@ -48,11 +48,29 @@
 
         tweakGrammar()
 
+        injectArtifactIds()
+
         // TODO:
         // insertMissingDocFromHiddenSuperclasses()
     }
 
-    //noinspection SpellCheckingInspection
+    private fun injectArtifactIds() {
+        val artifacts = options.artifactRegistrations
+        if (!artifacts.any()) {
+            return
+        }
+
+        artifacts.tag(codebase)
+
+        codebase.accept(object : VisibleItemVisitor() {
+            override fun visitClass(cls: ClassItem) {
+                cls.artifact?.let {
+                    cls.appendDocumentation(it, "@artifactId")
+                }
+            }
+        })
+    }
+
     val mentionsNull: Pattern = Pattern.compile("\\bnull\\b")
 
     /** Hide packages explicitly listed in [Options.hidePackages] */
@@ -104,7 +122,7 @@
                 if (findThreadAnnotations(annotations).size > 1) {
                     reporter.warning(
                         item, "Found more than one threading annotation on $item; " +
-                                "the auto-doc feature does not handle this correctly",
+                            "the auto-doc feature does not handle this correctly",
                         Errors.MULTIPLE_THREAD_ANNOTATIONS
                     )
                 }
@@ -114,7 +132,10 @@
                 var result: MutableList<String>? = null
                 for (annotation in annotations) {
                     val name = annotation.qualifiedName()
-                    if (name != null && name.endsWith("Thread") && name.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX)) {
+                    if (name != null && name.endsWith("Thread") &&
+                        (name.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX) ||
+                            name.startsWith(ANDROIDX_ANNOTATION_PREFIX))
+                    ) {
                         if (result == null) {
                             result = mutableListOf()
                         }
@@ -141,7 +162,8 @@
 
             private fun handleAnnotation(
                 annotation: AnnotationItem,
-                item: Item, depth: Int
+                item: Item,
+                depth: Int
             ) {
                 val name = annotation.qualifiedName()
                 if (name == null || name.startsWith(JAVA_LANG_PREFIX)) {
@@ -180,10 +202,11 @@
                 }
 
                 // Document required permissions
-                if (item is MemberItem && name == "android.support.annotation.RequiresPermission") {
+                if (item is MemberItem && name == "androidx.annotation.RequiresPermission") {
+                    var values: List<AnnotationAttributeValue>? = null
+                    var any = false
+                    var conditional = false
                     for (attribute in annotation.attributes()) {
-                        var values: List<AnnotationAttributeValue>? = null
-                        var any = false
                         when (attribute.name) {
                             "value", "allOf" -> {
                                 values = attribute.leafValues()
@@ -192,12 +215,13 @@
                                 any = true
                                 values = attribute.leafValues()
                             }
+                            "conditional" -> {
+                                conditional = attribute.value.value() == true
+                            }
                         }
+                    }
 
-                        if (values == null || values.isEmpty()) {
-                            continue
-                        }
-
+                    if (values != null && values.isNotEmpty() && !conditional) {
                         // Look at macros_override.cs for the usage of these
                         // tags. In particular, search for def:dump_permission
 
@@ -223,9 +247,7 @@
                                     Errors.MISSING_PERMISSION, item,
                                     "Cannot find permission field for $value required by $item (may be hidden or removed)"
                                 )
-                                //return
                                 sb.append(value.toSource())
-
                             } else {
                                 if (field.isHiddenOrRemoved()) {
                                     reporter.report(
@@ -242,7 +264,7 @@
                 }
 
                 // Document value ranges
-                if (name == "android.support.annotation.IntRange" || name == "android.support.annotation.FloatRange") {
+                if (name == "androidx.annotation.IntRange" || name == "androidx.annotation.FloatRange") {
                     val from: String? = annotation.findAttribute("from")?.value?.toSource()
                     val to: String? = annotation.findAttribute("to")?.value?.toSource()
                     // TODO: inclusive/exclusive attributes on FloatRange!
@@ -265,8 +287,8 @@
                 }
 
                 // Document expected constants
-                if (name == "android.support.annotation.IntDef" || name == "android.support.annotation.LongDef"
-                    || name == "android.support.annotation.StringDef"
+                if (name == "androidx.annotation.IntDef" || name == "androidx.annotation.LongDef" ||
+                    name == "androidx.annotation.StringDef"
                 ) {
                     val values = annotation.findAttribute("value")?.leafValues() ?: return
                     val flag = annotation.findAttribute("flag")?.value?.toSource() == "true"
@@ -317,12 +339,7 @@
                     val value = annotation.findAttribute("value")?.leafValues()?.firstOrNull() ?: return
                     val sb = StringBuilder(100)
                     val resolved = value.resolve()
-                    val field = if (resolved is FieldItem)
-                        resolved
-                    else {
-                        val v: Any = value.value() ?: value.toSource()
-                        findPermissionField(codebase, v)
-                    }
+                    val field = resolved as? FieldItem
                     sb.append("Requires the ")
                     if (field == null) {
                         reporter.report(
@@ -330,7 +347,6 @@
                             "Cannot find feature field for $value required by $item (may be hidden or removed)"
                         )
                         sb.append("{@link ${value.toSource()}}")
-
                     } else {
                         if (field.isHiddenOrRemoved()) {
                             reporter.report(
@@ -348,6 +364,22 @@
                     appendDocumentation(sb.toString(), item, false)
                 }
 
+                // Required API levels
+                if (name == "androidx.annotation.RequiresApi") {
+                    val level = run {
+                        val api = annotation.findAttribute("api")?.leafValues()?.firstOrNull()?.value()
+                        if (api == null || api == 1) {
+                            annotation.findAttribute("value")?.leafValues()?.firstOrNull()?.value() ?: return
+                        } else {
+                            api
+                        }
+                    }
+
+                    if (level is Int) {
+                        addApiLevelDocumentation(level, item)
+                    }
+                }
+
                 // Thread annotations are ignored here because they're handled as a group afterwards
 
                 // TODO: Resource type annotations
@@ -357,7 +389,7 @@
                     if (depth == 20) { // Temp debugging
                         throw StackOverflowError(
                             "Unbounded recursion, processing annotation " +
-                                    "${annotation.toSource()} in $item in ${item.compilationUnit()} "
+                                "${annotation.toSource()} in $item in ${item.compilationUnit()} "
                         )
                     }
                     handleAnnotation(nested, item, depth + 1)
@@ -396,7 +428,7 @@
 
         val documentation = cls.findTagDocumentation(tag)
         if (documentation != null) {
-            assert(documentation.startsWith("@$tag"), { documentation })
+            assert(documentation.startsWith("@$tag")) { documentation }
             // TODO: Insert it in the right place (@return or @param)
             val section = when {
                 documentation.startsWith("@returnDoc") -> "@return"
@@ -421,7 +453,6 @@
 
     /** Replacements to perform in documentation */
     val typos = mapOf(
-        //noinspection SpellCheckingInspection
         "Andriod" to "Android",
         "Kitkat" to "KitKat",
         "LemonMeringuePie" to "Lollipop",
@@ -498,34 +529,34 @@
                 addApiLevelDocumentation(apiLookup.getFieldVersion(psiField), field)
                 addDeprecatedDocumentation(apiLookup.getFieldDeprecatedIn(psiField), field)
             }
-
-            private fun addApiLevelDocumentation(level: Int, item: Item) {
-                if (level > 1) {
-                    appendDocumentation("Requires API level $level", item, false)
-                    // Also add @since tag, unless already manually entered.
-                    // TODO: Override it everywhere in case the existing doc is wrong (we know
-                    // better), and at least for OpenJDK sources we *should* since the since tags
-                    // are talking about language levels rather than API levels!
-                    if (!item.documentation.contains("@since")) {
-                        item.appendDocumentation(describeApiLevel(level), "@since")
-                    }
-                }
-            }
-
-            private fun addDeprecatedDocumentation(level: Int, item: Item) {
-                if (level > 1) {
-                    // TODO: *pre*pend instead!
-                    val description =
-                        "<p class=\"caution\"><strong>This class was deprecated in API level 21.</strong></p>"
-                    item.appendDocumentation(description, "@deprecated", append = false)
-                }
-            }
-
-            private fun describeApiLevel(level: Int): String {
-                return "${SdkVersionInfo.getVersionString(level)} ${SdkVersionInfo.getCodeName(level)} ($level)"
-            }
         })
     }
+
+    private fun addApiLevelDocumentation(level: Int, item: Item) {
+        if (level > 1) {
+            appendDocumentation("Requires API level $level", item, false)
+            // Also add @since tag, unless already manually entered.
+            // TODO: Override it everywhere in case the existing doc is wrong (we know
+            // better), and at least for OpenJDK sources we *should* since the since tags
+            // are talking about language levels rather than API levels!
+            if (!item.documentation.contains("@since")) {
+                item.appendDocumentation(describeApiLevel(level), "@since")
+            }
+        }
+    }
+
+    private fun addDeprecatedDocumentation(level: Int, item: Item) {
+        if (level > 1) {
+            // TODO: *pre*pend instead!
+            val description =
+                "<p class=\"caution\"><strong>This class was deprecated in API level 21.</strong></p>"
+            item.appendDocumentation(description, "@deprecated", append = false)
+        }
+    }
+
+    private fun describeApiLevel(level: Int): String {
+        return "${SdkVersionInfo.getVersionString(level)} ${SdkVersionInfo.getCodeName(level)} ($level)"
+    }
 }
 
 fun ApiLookup.getClassVersion(cls: PsiClass): Int {
diff --git a/src/main/java/com/android/tools/metalava/Driver.kt b/src/main/java/com/android/tools/metalava/Driver.kt
index cdf2b70..c538126 100644
--- a/src/main/java/com/android/tools/metalava/Driver.kt
+++ b/src/main/java/com/android/tools/metalava/Driver.kt
@@ -18,7 +18,6 @@
 package com.android.tools.metalava
 
 import com.android.SdkConstants
-import com.android.SdkConstants.DOT_JAR
 import com.android.SdkConstants.DOT_JAVA
 import com.android.SdkConstants.DOT_KT
 import com.android.ide.common.process.CachedProcessOutputHandler
@@ -28,6 +27,7 @@
 import com.android.tools.lint.LintCoreApplicationEnvironment
 import com.android.tools.lint.LintCoreProjectEnvironment
 import com.android.tools.lint.annotations.Extractor
+import com.android.tools.lint.checks.infrastructure.ClassName
 import com.android.tools.metalava.apilevels.ApiGenerator
 import com.android.tools.metalava.doclava1.ApiFile
 import com.android.tools.metalava.doclava1.ApiParseException
@@ -45,8 +45,8 @@
 import com.google.common.base.Stopwatch
 import com.google.common.collect.Lists
 import com.google.common.io.Files
+import com.intellij.openapi.roots.LanguageLevelProjectExtension
 import com.intellij.openapi.util.Disposer
-import com.intellij.psi.PsiClassOwner
 import java.io.File
 import java.io.IOException
 import java.io.OutputStreamWriter
@@ -54,12 +54,11 @@
 import java.util.concurrent.TimeUnit
 import java.util.concurrent.TimeUnit.SECONDS
 import java.util.function.Predicate
-import java.util.regex.Pattern
 import kotlin.text.Charsets.UTF_8
 
 const val PROGRAM_NAME = "metalava"
 const val HELP_PROLOGUE = "$PROGRAM_NAME extracts metadata from source code to generate artifacts such as the " +
-        "signature files, the SDK stub files, external annotations etc."
+    "signature files, the SDK stub files, external annotations etc."
 
 @Suppress("PropertyName") // Can't mark const because trimIndent() :-(
 val BANNER: String = """
@@ -145,19 +144,6 @@
 private fun processFlags() {
     val stopwatch = Stopwatch.createStarted()
 
-    val androidApiLevelXml = options.generateApiLevelXml
-    val apiLevelJars = options.apiLevelJars
-    if (androidApiLevelXml != null && apiLevelJars != null) {
-        ApiGenerator.generate(apiLevelJars, androidApiLevelXml)
-
-        if (options.apiJar == null && options.sources.isEmpty() &&
-            options.sourcePath.isEmpty() && options.previousApi == null
-        ) {
-            // Done
-            return
-        }
-    }
-
     val codebase =
         if (options.sources.size == 1 && options.sources[0].path.endsWith(SdkConstants.DOT_TXT)) {
             loadFromSignatureFiles(
@@ -177,10 +163,50 @@
         options.stdout.println("\n$PROGRAM_NAME analyzed API in ${stopwatch.elapsed(TimeUnit.SECONDS)} seconds")
     }
 
+    val androidApiLevelXml = options.generateApiLevelXml
+    val apiLevelJars = options.apiLevelJars
+    if (androidApiLevelXml != null && apiLevelJars != null) {
+        progress("\nGenerating API levels XML descriptor file, ${androidApiLevelXml.name}: ")
+        ApiGenerator.generate(apiLevelJars, androidApiLevelXml, codebase)
+    }
+
+    if ((options.stubsDir != null || options.docStubsDir != null) && codebase.supportsDocumentation()) {
+        progress("\nEnhancing docs: ")
+        val docAnalyzer = DocAnalyzer(codebase)
+        docAnalyzer.enhance()
+
+        val applyApiLevelsXml = options.applyApiLevelsXml
+        if (applyApiLevelsXml != null) {
+            progress("\nApplying API levels")
+            docAnalyzer.applyApiLevels(applyApiLevelsXml)
+        }
+    }
+
+    // Generate the documentation stubs *before* we migrate nullness information.
+    options.docStubsDir?.let { createStubFiles(it, codebase, docStubs = true,
+        writeStubList = options.docStubsSourceList != null) }
+
+    val currentApiFile = options.currentApi
+    if (currentApiFile != null && options.checkCompatibility) {
+        val current =
+            if (currentApiFile.path.endsWith(SdkConstants.DOT_JAR)) {
+                loadFromJarFile(currentApiFile)
+            } else {
+                loadFromSignatureFiles(
+                    currentApiFile, options.inputKotlinStyleNulls,
+                    supportsStagedNullability = true
+                )
+            }
+
+        // If configured, compares the new API with the previous API and reports
+        // any incompatibilities.
+        CompatibilityCheck.checkCompatibility(codebase, current)
+    }
+
     val previousApiFile = options.previousApi
     if (previousApiFile != null) {
         val previous =
-            if (previousApiFile.path.endsWith(DOT_JAR)) {
+            if (previousApiFile.path.endsWith(SdkConstants.DOT_JAR)) {
                 loadFromJarFile(previousApiFile)
             } else {
                 loadFromSignatureFiles(
@@ -191,7 +217,7 @@
 
         // If configured, compares the new API with the previous API and reports
         // any incompatibilities.
-        if (options.checkCompatibility) {
+        if (options.checkCompatibility && options.currentApi == null) { // otherwise checked against currentApi above
             CompatibilityCheck.checkCompatibility(codebase, previous)
         }
 
@@ -205,7 +231,119 @@
 
     // Based on the input flags, generates various output files such
     // as signature files and/or stubs files
-    generateOutputs(codebase)
+    options.apiFile?.let { apiFile ->
+        val apiFilter = FilterPredicate(ApiPredicate(codebase))
+        val apiReference = ApiPredicate(codebase, ignoreShown = true)
+        val apiEmit = apiFilter.and(ElidingPredicate(apiReference))
+
+        createReportFile(codebase, apiFile, "API") { printWriter ->
+            val preFiltered = codebase.original != null
+            SignatureWriter(printWriter, apiEmit, apiReference, preFiltered)
+        }
+    }
+
+    options.dexApiFile?.let { apiFile ->
+        val apiFilter = FilterPredicate(ApiPredicate(codebase))
+        val memberIsNotCloned: Predicate<Item> = Predicate { !it.isCloned() }
+        val apiReference = ApiPredicate(codebase, ignoreShown = true)
+        val dexApiEmit = memberIsNotCloned.and(apiFilter)
+
+        createReportFile(
+            codebase, apiFile, "DEX API"
+        ) { printWriter -> DexApiWriter(printWriter, dexApiEmit, apiReference) }
+    }
+
+    options.removedApiFile?.let { apiFile ->
+        val unfiltered = codebase.original ?: codebase
+
+        val removedFilter = FilterPredicate(ApiPredicate(codebase, matchRemoved = true))
+        val removedReference = ApiPredicate(codebase, ignoreShown = true, ignoreRemoved = true)
+        val removedEmit = removedFilter.and(ElidingPredicate(removedReference))
+
+        createReportFile(unfiltered, apiFile, "removed API") { printWriter ->
+            SignatureWriter(printWriter, removedEmit, removedReference, codebase.original != null)
+        }
+    }
+
+    options.removedDexApiFile?.let { apiFile ->
+        val unfiltered = codebase.original ?: codebase
+
+        val removedFilter = FilterPredicate(ApiPredicate(codebase, matchRemoved = true))
+        val removedReference = ApiPredicate(codebase, ignoreShown = true, ignoreRemoved = true)
+        val memberIsNotCloned: Predicate<Item> = Predicate { !it.isCloned() }
+        val removedDexEmit = memberIsNotCloned.and(removedFilter)
+
+        createReportFile(
+            unfiltered, apiFile, "removed DEX API"
+        ) { printWriter -> DexApiWriter(printWriter, removedDexEmit, removedReference) }
+    }
+
+    options.privateApiFile?.let { apiFile ->
+        val apiFilter = FilterPredicate(ApiPredicate(codebase))
+        val memberIsNotCloned: Predicate<Item> = Predicate { !it.isCloned() }
+        val privateEmit = memberIsNotCloned.and(apiFilter.negate())
+        val privateReference = Predicate<Item> { true }
+
+        createReportFile(codebase, apiFile, "private API") { printWriter ->
+            SignatureWriter(printWriter, privateEmit, privateReference, codebase.original != null)
+        }
+    }
+
+    options.privateDexApiFile?.let { apiFile ->
+        val apiFilter = FilterPredicate(ApiPredicate(codebase))
+        val privateEmit = apiFilter.negate()
+        val privateReference = Predicate<Item> { true }
+
+        createReportFile(
+            codebase, apiFile, "private DEX API"
+        ) { printWriter ->
+            DexApiWriter(
+                printWriter, privateEmit, privateReference, inlineInheritedFields = false
+            )
+        }
+    }
+
+    options.proguard?.let { proguard ->
+        val apiEmit = FilterPredicate(ApiPredicate(codebase))
+        val apiReference = ApiPredicate(codebase, ignoreShown = true)
+        createReportFile(
+            codebase, proguard, "Proguard file"
+        ) { printWriter -> ProguardWriter(printWriter, apiEmit, apiReference) }
+    }
+
+    options.sdkValueDir?.let { dir ->
+        dir.mkdirs()
+        SdkFileWriter(codebase, dir).generate()
+    }
+
+    // Now that we've migrated nullness information we can proceed to write non-doc stubs, if any.
+
+    options.stubsDir?.let {
+        createStubFiles(
+            it, codebase, docStubs = false,
+            writeStubList = options.stubsSourceList != null
+        )
+    }
+    if (options.docStubsDir == null && options.stubsDir == null) {
+        val writeStubsFile: (File) -> Unit = { file ->
+            val root = File("").absoluteFile
+            val sources = options.sources
+            val rootPath = root.path
+            val contents = sources.joinToString(" ") {
+                val path = it.path
+                if (path.startsWith(rootPath)) {
+                    path.substring(rootPath.length)
+                } else {
+                    path
+                }
+            }
+            Files.asCharSink(file, UTF_8).write(contents)
+        }
+        options.stubsSourceList?.let(writeStubsFile)
+        options.docStubsSourceList?.let(writeStubsFile)
+    }
+    options.externalAnnotations?.let { extractAnnotations(codebase, it) }
+    progress("\n")
 
     // Coverage stats?
     if (options.dumpAnnotationStatistics) {
@@ -271,21 +409,25 @@
 
 private fun migrateNulls(codebase: Codebase, previous: Codebase) {
     if (options.migrateNulls) {
-        val prev = previous.supportsStagedNullability
+        val codebaseSupportsNullability = previous.supportsStagedNullability
+        val prevSupportsNullability = previous.supportsStagedNullability
         try {
             previous.supportsStagedNullability = true
+            codebase.supportsStagedNullability = true
             previous.compareWith(
                 NullnessMigration(), codebase,
                 ApiPredicate(codebase)
             )
         } finally {
-            previous.supportsStagedNullability = prev
+            previous.supportsStagedNullability = prevSupportsNullability
+            codebase.supportsStagedNullability = codebaseSupportsNullability
         }
     }
 }
 
 private fun loadFromSignatureFiles(
-    file: File, kotlinStyleNulls: Boolean,
+    file: File,
+    kotlinStyleNulls: Boolean,
     manifest: File? = null,
     performChecks: Boolean = false,
     supportsStagedNullability: Boolean = false
@@ -309,6 +451,10 @@
 private fun loadFromSources(): Codebase {
     val projectEnvironment = createProjectEnvironment()
 
+    // Push language level to PSI handler
+    projectEnvironment.project.getComponent(LanguageLevelProjectExtension::class.java)?.languageLevel =
+        options.javaLanguageLevel
+
     progress("\nProcessing sources: ")
 
     val sources = if (options.sources.isEmpty()) {
@@ -331,7 +477,7 @@
     val project = projectEnvironment.project
 
     val kotlinFiles = sources.filter { it.path.endsWith(SdkConstants.DOT_KT) }
-    KotlinLintAnalyzerFacade.analyze(kotlinFiles, joined, project)
+    KotlinLintAnalyzerFacade().analyze(kotlinFiles, joined, project)
 
     val units = Extractor.createUnitsForFiles(project, sources)
     val packageDocs = gatherHiddenPackagesFromJavaDocs(options.sourcePath)
@@ -341,6 +487,7 @@
     val codebase = PsiBasedCodebase("Codebase loaded from source folders")
     codebase.initialize(project, units, packageDocs)
     codebase.manifest = options.manifest
+    codebase.apiLevel = options.currentApiLevel
 
     progress("\nAnalyzing API: ")
 
@@ -356,10 +503,8 @@
     // General API checks for Android APIs
     AndroidApiChecks().check(codebase)
 
-    val ignoreShown = options.showUnannotated
-
-    val filterEmit = ApiPredicate(codebase, ignoreShown = ignoreShown, ignoreRemoved = false)
-    val apiEmit = ApiPredicate(codebase, ignoreShown = ignoreShown)
+    val filterEmit = ApiPredicate(codebase, ignoreShown = true, ignoreRemoved = false)
+    val apiEmit = ApiPredicate(codebase, ignoreShown = true)
     val apiReference = ApiPredicate(codebase, ignoreShown = true)
 
     // Copy methods from soon-to-be-hidden parents into descendant classes, when necessary
@@ -368,19 +513,9 @@
 
     // Compute default constructors (and add missing package private constructors
     // to make stubs compilable if necessary)
-    if (options.stubsDir != null) {
+    if (options.stubsDir != null || options.docStubsDir != null) {
         progress("\nInsert missing constructors: ")
         analyzer.addConstructors(filterEmit)
-
-        progress("\nEnhancing docs: ")
-        val docAnalyzer = DocAnalyzer(codebase)
-        docAnalyzer.enhance()
-
-        val applyApiLevelsXml = options.applyApiLevelsXml
-        if (applyApiLevelsXml != null) {
-            progress("\nApplying API levels")
-            docAnalyzer.applyApiLevels(applyApiLevelsXml)
-        }
     }
 
     progress("\nPerforming misc API checks: ")
@@ -389,6 +524,7 @@
     return codebase
 }
 
+@Suppress("unused") // Planning to restore for performance optimizations
 private fun filterCodebase(codebase: PsiBasedCodebase): Codebase {
     val ignoreShown = options.showAnnotations.isEmpty()
 
@@ -410,7 +546,7 @@
     projectEnvironment.registerPaths(listOf(apiJar))
 
     val kotlinFiles = emptyList<File>()
-    KotlinLintAnalyzerFacade.analyze(kotlinFiles, listOf(apiJar), project)
+    KotlinLintAnalyzerFacade().analyze(kotlinFiles, listOf(apiJar), project)
 
     val codebase = PsiBasedCodebase()
     codebase.description = "Codebase loaded from $apiJar"
@@ -431,116 +567,45 @@
 }
 
 private fun ensurePsiFileCapacity() {
-    //noinspection SpellCheckingInspection
     val fileSize = System.getProperty("idea.max.intellisense.filesize")
     if (fileSize == null) {
         // Ensure we can handle large compilation units like android.R
-        //noinspection SpellCheckingInspection
         System.setProperty("idea.max.intellisense.filesize", "100000")
     }
 }
 
-private fun generateOutputs(codebase: Codebase) {
-
-    options.apiFile?.let { apiFile ->
-        val apiFilter = FilterPredicate(ApiPredicate(codebase))
-        val apiReference = ApiPredicate(codebase, ignoreShown = true)
-        val apiEmit = apiFilter.and(ElidingPredicate(apiReference))
-
-        createReportFile(codebase, apiFile, "API", { printWriter ->
-            val preFiltered = codebase.original != null
-            SignatureWriter(printWriter, apiEmit, apiReference, preFiltered)
-        })
-    }
-
-    options.removedApiFile?.let { apiFile ->
-        val unfiltered = codebase.original ?: codebase
-
-        val removedFilter = FilterPredicate(ApiPredicate(codebase, matchRemoved = true))
-        val removedReference = ApiPredicate(codebase, ignoreShown = true, ignoreRemoved = true)
-        val removedEmit = removedFilter.and(ElidingPredicate(removedReference))
-
-        createReportFile(unfiltered, apiFile, "removed API", { printWriter ->
-            SignatureWriter(printWriter, removedEmit, removedReference, codebase.original != null)
-        })
-    }
-
-    options.privateApiFile?.let { apiFile ->
-        val apiFilter = FilterPredicate(ApiPredicate(codebase))
-        val privateEmit = apiFilter.negate()
-        val privateReference = Predicate<Item> { true }
-
-        createReportFile(codebase, apiFile, "private API", { printWriter ->
-            SignatureWriter(printWriter, privateEmit, privateReference, codebase.original != null)
-        })
-    }
-
-    options.privateDexApiFile?.let { apiFile ->
-        val apiFilter = FilterPredicate(ApiPredicate(codebase))
-        val privateEmit = apiFilter.negate()
-        val privateReference = Predicate<Item> { true }
-
-        createReportFile(codebase, apiFile, "DEX API",
-            { printWriter -> DexApiWriter(printWriter, privateEmit, privateReference) })
-    }
-
-    options.proguard?.let { proguard ->
-        val apiEmit = FilterPredicate(ApiPredicate(codebase))
-        val apiReference = ApiPredicate(codebase, ignoreShown = true)
-        createReportFile(codebase, proguard, "Proguard file",
-            { printWriter -> ProguardWriter(printWriter, apiEmit, apiReference) })
-    }
-
-    options.sdkValueDir?.let { dir ->
-        dir.mkdirs()
-        SdkFileWriter(codebase, dir).generate()
-    }
-
-    options.stubsDir?.let { createStubFiles(it, codebase) }
-    // Otherwise, if we've asked to write out a file list, write out the
-    // input file list instead
-            ?: options.stubsSourceList?.let { file ->
-                val root = File("").absoluteFile
-                val sources = options.sources
-                val rootPath = root.path
-                val contents = sources.joinToString(" ") {
-                    val path = it.path
-                    if (path.startsWith(rootPath)) {
-                        path.substring(rootPath.length)
-                    } else {
-                        path
-                    }
-                }
-                Files.asCharSink(file, UTF_8).write(contents)
-            }
-
-    options.externalAnnotations?.let { extractAnnotations(codebase, it) }
-    progress("\n")
-}
-
 private fun extractAnnotations(codebase: Codebase, file: File) {
     val localTimer = Stopwatch.createStarted()
-    val units = codebase.units
 
-    @Suppress("UNCHECKED_CAST")
-    ExtractAnnotations().extractAnnotations(units.asSequence().filter { it is PsiClassOwner }.toList() as List<PsiClassOwner>)
-    if (options.verbose) {
-        options.stdout.print("\n$PROGRAM_NAME extracted annotations into $file in $localTimer")
-        options.stdout.flush()
+    options.externalAnnotations?.let { outputFile ->
+        @Suppress("UNCHECKED_CAST")
+        ExtractAnnotations(
+            codebase,
+            outputFile
+        ).extractAnnotations()
+        if (options.verbose) {
+            options.stdout.print("\n$PROGRAM_NAME extracted annotations into $file in $localTimer")
+            options.stdout.flush()
+        }
     }
 }
 
-private fun createStubFiles(stubDir: File, codebase: Codebase) {
+private fun createStubFiles(stubDir: File, codebase: Codebase, docStubs: Boolean, writeStubList: Boolean) {
     // Generating stubs from a sig-file-based codebase is problematic
     assert(codebase.supportsDocumentation())
 
-    progress("\nGenerating stub files: ")
+    if (docStubs) {
+        progress("\nGenerating documentation stub files: ")
+    } else {
+        progress("\nGenerating stub files: ")
+    }
+
     val localTimer = Stopwatch.createStarted()
     val prevCompatibility = compatibility
     if (compatibility.compat) {
-        //if (!options.quiet) {
+        // if (!options.quiet) {
         //    options.stderr.println("Warning: Turning off compat mode when generating stubs")
-        //}
+        // }
         compatibility = Compatibility(false)
         // But preserve the setting for whether we want to erase throws signatures (to ensure the API
         // stays compatible)
@@ -549,56 +614,37 @@
 
     val stubWriter =
         StubWriter(
-            codebase = codebase, stubsDir = stubDir, generateAnnotations = options.generateAnnotations,
-            preFiltered = codebase.original != null
+            codebase = codebase,
+            stubsDir = stubDir,
+            generateAnnotations = options.generateAnnotations,
+            preFiltered = codebase.original != null,
+            docStubs = docStubs
         )
     codebase.accept(stubWriter)
 
-    // Optionally also write out a list of source files that were generated; used
-    // for example to point javadoc to the stubs output to generate documentation
-    options.stubsSourceList?.let {
-        val root = File("").absoluteFile
-        stubWriter.writeSourceList(it, root)
+    if (writeStubList) {
+        // Optionally also write out a list of source files that were generated; used
+        // for example to point javadoc to the stubs output to generate documentation
+        val file = if (docStubs) {
+            options.docStubsSourceList ?: options.stubsSourceList
+        } else {
+            options.stubsSourceList
+        }
+        file?.let {
+            val root = File("").absoluteFile
+            stubWriter.writeSourceList(it, root)
+        }
     }
 
-    /*
-    // Temporary hack: Also write out annotations to make stub compilation work. This is
-    // just temporary: the Makefiles for the platform should be updated to supply a
-    // boot classpath instead.
-    val nullable = File(stubDir, "android/support/annotation/Nullable.java")
-    val nonnull = File(stubDir, "android/support/annotation/NonNull.java")
-    nullable.parentFile.mkdirs()
-    nonnull.parentFile.mkdirs()
-    Files.asCharSink(nullable, UTF_8).write(
-        "package android.support.annotation;\n" +
-                "import java.lang.annotation.*;\n" +
-                "import static java.lang.annotation.ElementType.*;\n" +
-                "import static java.lang.annotation.RetentionPolicy.SOURCE;\n" +
-                "@SuppressWarnings(\"WeakerAccess\")\n" +
-                "@Retention(SOURCE)\n" +
-                "@Target({METHOD, PARAMETER, FIELD})\n" +
-                "public @interface Nullable {\n" +
-                "}\n"
-    )
-    Files.asCharSink(nonnull, UTF_8).write(
-        "package android.support.annotation;\n" +
-                "import java.lang.annotation.*;\n" +
-                "import static java.lang.annotation.ElementType.*;\n" +
-                "import static java.lang.annotation.RetentionPolicy.SOURCE;\n" +
-                "@SuppressWarnings(\"WeakerAccess\")\n" +
-                "@Retention(SOURCE)\n" +
-                "@Target({METHOD, PARAMETER, FIELD})\n" +
-                "public @interface NonNull {\n" +
-                "}\n"
-    )
-    */
-
     compatibility = prevCompatibility
 
-    progress("\n$PROGRAM_NAME wrote stubs directory $stubDir in ${localTimer.elapsed(SECONDS)} seconds")
+    progress(
+        "\n$PROGRAM_NAME wrote ${if (docStubs) "documentation" else ""} stubs directory $stubDir in ${
+        localTimer.elapsed(SECONDS)} seconds"
+    )
 }
 
-private fun progress(message: String) {
+fun progress(message: String) {
     if (options.verbose) {
         options.stdout.print(message)
         options.stdout.flush()
@@ -639,6 +685,9 @@
 fun tick() {
     tick++
     if (tick % 100 == 0) {
+        if (!options.verbose) {
+            return
+        }
         options.stdout.print(".")
         options.stdout.flush()
     }
@@ -681,10 +730,8 @@
                     if (child.isDirectory)
                         if (pkg.isEmpty())
                             child.name
-                        else
-                            pkg + "." + child.name
-                    else
-                        pkg
+                        else pkg + "." + child.name
+                    else pkg
                 addHiddenPackages(packageToDoc, hiddenPackages, child, subPkg)
             }
         }
@@ -737,7 +784,13 @@
     if (path.endsWith(DOT_JAVA) || path.endsWith(DOT_KT)) {
         val pkg = findPackage(file) ?: return null
         val parent = file.parentFile ?: return null
-        return File(path.substring(0, parent.path.length - pkg.length))
+        val endIndex = parent.path.length - pkg.length
+        val before = path[endIndex - 1]
+        if (before == '/' || before == '\\') {
+            return File(path.substring(0, endIndex))
+        } else {
+            reporter.report(Errors.IO_ERROR, file, "$PROGRAM_NAME was unable to determine the package name")
+        }
     }
 
     return null
@@ -749,16 +802,7 @@
     return findPackage(source)
 }
 
-@Suppress("PrivatePropertyName")
-private val PACKAGE_PATTERN = Pattern.compile("package\\s+([\\S&&[^;]]*)")
-
 /** Finds the package of the given Java/Kotlin source code, if possible */
 fun findPackage(source: String): String? {
-    val matcher = PACKAGE_PATTERN.matcher(source)
-    val foundPackage = matcher.find()
-    return if (foundPackage) {
-        matcher.group(1).trim { it <= ' ' }
-    } else {
-        null
-    }
+    return ClassName(source).packageName
 }
diff --git a/src/main/java/com/android/tools/metalava/OptionsException.kt b/src/main/java/com/android/tools/metalava/DriverException.kt
similarity index 100%
rename from src/main/java/com/android/tools/metalava/OptionsException.kt
rename to src/main/java/com/android/tools/metalava/DriverException.kt
diff --git a/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt b/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt
index f97c112..dd3fb67 100644
--- a/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt
+++ b/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt
@@ -16,36 +16,609 @@
 
 package com.android.tools.metalava
 
+import com.android.SdkConstants
 import com.android.tools.lint.annotations.Extractor
-import com.intellij.psi.PsiClassOwner
+import com.android.tools.lint.client.api.AnnotationLookup
+import com.android.tools.lint.detector.api.ConstantEvaluator
+import com.android.tools.metalava.doclava1.Errors
+import com.android.tools.metalava.model.AnnotationItem
+import com.android.tools.metalava.model.ClassItem
+import com.android.tools.metalava.model.Codebase
+import com.android.tools.metalava.model.FieldItem
+import com.android.tools.metalava.model.Item
+import com.android.tools.metalava.model.MemberItem
+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.psi.PsiAnnotationItem
+import com.android.tools.metalava.model.psi.PsiClassItem
+import com.android.tools.metalava.model.visitors.ApiVisitor
+import com.android.utils.XmlUtils
+import com.google.common.base.Charsets
+import com.google.common.xml.XmlEscapers
+import com.intellij.psi.PsiAnnotation
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiField
+import com.intellij.psi.PsiNameValuePair
+import org.jetbrains.uast.UAnnotation
+import org.jetbrains.uast.UBinaryExpressionWithType
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UExpression
+import org.jetbrains.uast.ULiteralExpression
+import org.jetbrains.uast.UNamedExpression
+import org.jetbrains.uast.UReferenceExpression
+import org.jetbrains.uast.UastEmptyExpression
+import org.jetbrains.uast.java.JavaUAnnotation
+import org.jetbrains.uast.java.expressions.JavaUAnnotationCallExpression
+import org.jetbrains.uast.util.isArrayInitializer
+import org.jetbrains.uast.util.isTypeCast
+import java.io.BufferedOutputStream
+import java.io.File
+import java.io.FileOutputStream
+import java.io.PrintWriter
+import java.io.StringWriter
+import java.util.ArrayList
+import java.util.jar.JarEntry
+import java.util.jar.JarOutputStream
 
-class ExtractAnnotations {
-    fun extractAnnotations(units: List<PsiClassOwner>) {
-        val rmTypeDefs = if (options.rmTypeDefs != null) listOf(options.rmTypeDefs) else emptyList()
-        val typedefFile = options.typedefFile
-        val filter = options.apiFilter
+// Like the tools/base Extractor class, but limited to our own (mapped) AnnotationItems,
+// and only those with source retention (and in particular right now that just means the
+// typedef annotations.)
+class ExtractAnnotations(
+    private val codebase: Codebase,
+    private val outputFile: File
+) : ApiVisitor(codebase) {
+    // Used linked hash map for order such that we always emit parameters after their surrounding method etc
+    private val packageToAnnotationPairs = LinkedHashMap<PackageItem, MutableList<Pair<Item, AnnotationHolder>>>()
 
-        val verbose = !options.quiet
-        val skipClassRetention = options.skipClassRetention
-        val extractor = Extractor(filter, rmTypeDefs, verbose, !skipClassRetention, true)
-        extractor.isListIgnored = !options.hideFiltered
-        extractor.extractFromProjectSource(units)
-        for (jar in options.mergeAnnotations) {
-            extractor.mergeExisting(jar)
-        }
+    private val annotationLookup = AnnotationLookup()
 
-        extractor.export(options.externalAnnotations, null)
+    private data class AnnotationHolder(
+        val annotationClass: ClassItem?,
+        val annotationItem: AnnotationItem,
+        val uAnnotation: UAnnotation?
+    )
 
-        if (typedefFile != null) {
-            extractor.writeTypedefFile(typedefFile)
-        }
+    private val classToAnnotationHolder = mutableMapOf<String, AnnotationHolder>()
 
-        if (rmTypeDefs.isNotEmpty()) {
-            if (typedefFile != null) {
-                Extractor.removeTypedefClasses(rmTypeDefs, typedefFile)
-            } else {
-                extractor.removeTypedefClasses()
+    fun extractAnnotations() {
+        codebase.accept(this)
+
+        // Write external annotations
+        FileOutputStream(outputFile).use { fileOutputStream ->
+            JarOutputStream(BufferedOutputStream(fileOutputStream)).use { zos ->
+                val sortedPackages =
+                    packageToAnnotationPairs.keys.asSequence().sortedBy { it.qualifiedName() }.toList()
+
+                for (pkg in sortedPackages) {
+                    // Note: Using / rather than File.separator: jar lib requires it
+                    val name = pkg.qualifiedName().replace('.', '/') + "/annotations.xml"
+
+                    val outEntry = JarEntry(name)
+                    outEntry.time = 0
+                    zos.putNextEntry(outEntry)
+
+                    val pairs = packageToAnnotationPairs[pkg] ?: continue
+
+                    StringPrintWriter.create().use { writer ->
+                        writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>")
+
+                        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
+                            prev = item
+
+                            writer.print("  <item name=\"")
+                            writer.print(item.getExternalAnnotationSignature())
+                            writer.println("\">")
+
+                            writeAnnotation(writer, item, annotation)
+
+                            writer.print("  </item>")
+                            writer.println()
+                        }
+
+                        writer.println("</root>\n")
+                        writer.close()
+                        val bytes = writer.contents.toByteArray(Charsets.UTF_8)
+                        zos.write(bytes)
+                        zos.closeEntry()
+                    }
+                }
             }
         }
     }
+
+    /** 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
+
+        val pkg = when (item) {
+            is MemberItem -> item.containingClass().containingPackage()
+            is ParameterItem -> item.containingMethod().containingClass().containingPackage()
+            else -> return
+        }
+
+        val list = packageToAnnotationPairs[pkg] ?: run {
+            val new =
+                mutableListOf<Pair<Item, AnnotationHolder>>()
+            packageToAnnotationPairs[pkg] = new
+            new
+        }
+        list.add(Pair(item, typedef))
+    }
+
+    override fun visitField(field: FieldItem) {
+        checkItem(field)
+    }
+
+    override fun visitMethod(method: MethodItem) {
+        checkItem(method)
+    }
+
+    override fun visitParameter(parameter: ParameterItem) {
+        checkItem(parameter)
+    }
+
+    private fun findTypeDef(item: Item): AnnotationHolder? {
+        for (annotation in item.modifiers.annotations()) {
+            val qualifiedName = annotation.qualifiedName() ?: continue
+            if (qualifiedName.startsWith(JAVA_LANG_PREFIX) ||
+                qualifiedName.startsWith(ANDROIDX_ANNOTATION_PREFIX) ||
+                qualifiedName.startsWith(ANDROID_ANNOTATION_PREFIX) ||
+                qualifiedName.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX)
+            ) {
+                if (annotation.isTypeDefAnnotation()) {
+                    // Imported typedef
+                    return AnnotationHolder(null, annotation, null)
+                }
+
+                continue
+            }
+
+            val typeDefClass = annotation.resolve() ?: continue
+            val className = typeDefClass.qualifiedName()
+            if (typeDefClass.isAnnotationType()) {
+                val cached = classToAnnotationHolder[className]
+                if (cached != null) {
+                    return cached
+                }
+
+                val typeDefAnnotation = typeDefClass.modifiers.annotations().firstOrNull {
+                    it.isTypeDefAnnotation()
+                }
+                if (typeDefAnnotation != null) {
+                    // Make sure it has the right retention
+                    if (!hasSourceRetention(typeDefClass)) {
+                        reporter.report(
+                            Errors.ANNOTATION_EXTRACTION, typeDefClass,
+                            "This typedef annotation class should have @Retention(RetentionPolicy.SOURCE)"
+                        )
+                    }
+
+                    if (filterEmit.test(typeDefClass)) {
+                        reporter.report(
+                            Errors.ANNOTATION_EXTRACTION, typeDefClass,
+                            "This typedef annotation class should be marked @hide or should not be marked public"
+                        )
+                    }
+
+                    if (typeDefAnnotation is PsiAnnotationItem && typeDefClass is PsiClassItem) {
+                        val result = AnnotationHolder(
+                            typeDefClass, typeDefAnnotation,
+                            annotationLookup.findRealAnnotation(
+                                typeDefAnnotation.psiAnnotation,
+                                typeDefClass.psiClass,
+                                null
+                            )
+                        )
+                        classToAnnotationHolder[className] = result
+                        return result
+                    }
+                }
+            }
+        }
+        return null
+    }
+
+    private fun hasSourceRetention(annotationClass: ClassItem): Boolean {
+        if (annotationClass is PsiClassItem) {
+            return hasSourceRetention(annotationClass.psiClass)
+        }
+        return false
+    }
+
+    private fun hasSourceRetention(cls: PsiClass): Boolean {
+        val modifierList = cls.modifierList
+        if (modifierList != null) {
+            for (psiAnnotation in modifierList.annotations) {
+                val annotation = JavaUAnnotation.wrap(psiAnnotation)
+                if (hasSourceRetention(annotation)) {
+                    return true
+                }
+            }
+        }
+
+        return false
+    }
+
+    private fun hasSourceRetention(annotation: UAnnotation): Boolean {
+        val qualifiedName = annotation.qualifiedName
+        if ("java.lang.annotation.Retention" == qualifiedName || "kotlin.annotation.Retention" == qualifiedName) {
+            val attributes = annotation.attributeValues
+            if (attributes.size != 1) {
+                error("Expected exactly one parameter passed to @Retention")
+                return false
+            }
+            val value = attributes[0].expression
+            if (value is UReferenceExpression) {
+                try {
+                    val element = value.resolve()
+                    if (element is PsiField) {
+                        val field = element as PsiField?
+                        if ("SOURCE" == field!!.name) {
+                            return true
+                        }
+                    }
+                } catch (t: Throwable) {
+                    val s = value.asSourceString()
+                    return s.contains("SOURCE")
+                }
+            }
+        }
+
+        return false
+    }
+
+    /**
+     * A writer which stores all its contents into a string and has the ability to mark a certain
+     * freeze point and then reset back to it
+     */
+    private class StringPrintWriter constructor(private val stringWriter: StringWriter) :
+        PrintWriter(stringWriter) {
+        private var mark: Int = 0
+
+        val contents: String get() = stringWriter.toString()
+
+        fun mark() {
+            flush()
+            mark = stringWriter.buffer.length
+        }
+
+        fun reset() {
+            stringWriter.buffer.setLength(mark)
+        }
+
+        override fun toString(): String {
+            return contents
+        }
+
+        companion object {
+            fun create(): StringPrintWriter {
+                return StringPrintWriter(StringWriter(1000))
+            }
+        }
+    }
+
+    private fun escapeXml(unescaped: String): String {
+        return XmlEscapers.xmlAttributeEscaper().escape(unescaped)
+    }
+
+    private fun Item.getExternalAnnotationSignature(): String? {
+        when (this) {
+            is PackageItem -> {
+                return escapeXml(qualifiedName())
+            }
+
+            is ClassItem -> {
+                return escapeXml(qualifiedName())
+            }
+
+            is MethodItem -> {
+                val sb = StringBuilder(100)
+                sb.append(escapeXml(containingClass().qualifiedName()))
+                sb.append(' ')
+
+                if (isConstructor()) {
+                    sb.append(escapeXml(containingClass().simpleName()))
+                } else if (returnType() != null) {
+                    sb.append(escapeXml(returnType()!!.toTypeString()))
+                    sb.append(' ')
+                    sb.append(escapeXml(name()))
+                }
+
+                sb.append('(')
+
+                // The signature must match *exactly* the formatting used by IDEA,
+                // since it looks up external annotations in a map by this key.
+                // Therefore, it is vital that the parameter list uses exactly one
+                // space after each comma between parameters, and *no* spaces between
+                // generics variables, e.g. foo(Map<A,B>, int)
+                var i = 0
+                val parameterList = parameters()
+                val n = parameterList.size
+                while (i < n) {
+                    if (i > 0) {
+                        sb.append(',').append(' ')
+                    }
+                    val type = parameterList[i].type().toTypeString().replace(" ", "")
+                    sb.append(type)
+                    i++
+                }
+                sb.append(')')
+                return sb.toString()
+            }
+
+            is FieldItem -> {
+                return escapeXml(containingClass().qualifiedName()) + ' '.toString() + name()
+            }
+
+            is ParameterItem -> {
+                return containingMethod().getExternalAnnotationSignature() + ' '.toString() + this.parameterIndex
+            }
+        }
+
+        return null
+    }
+
+    private fun writeAnnotation(
+        writer: StringPrintWriter,
+        item: Item,
+        annotationHolder: AnnotationHolder
+    ) {
+        val annotationItem = annotationHolder.annotationItem
+        val qualifiedName = annotationItem.qualifiedName()
+
+        writer.mark()
+        writer.print("    <annotation name=\"")
+        writer.print(qualifiedName)
+
+        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)
+
+                // 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
+                    }
+
+                    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
+                    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("\" />")
+            }
+
+            if (empty) {
+                // All items were filtered out: don't write the annotation at all
+                writer.reset()
+                return
+            }
+        }
+
+        writer.println("    </annotation>")
+    }
+
+    private fun attributeString(value: UExpression?, inlineConstants: Boolean): String? {
+        value ?: return null
+        val sb = StringBuilder()
+        return if (appendExpression(sb, value, inlineConstants)) {
+            sb.toString()
+        } else {
+            null
+        }
+    }
+
+    private fun appendExpression(
+        sb: StringBuilder,
+        expression: UExpression,
+        inlineConstants: Boolean
+    ): Boolean {
+        if (expression.isArrayInitializer()) {
+            val call = expression as UCallExpression
+            val initializers = call.valueArguments
+            sb.append('{')
+            var first = true
+            val initialLength = sb.length
+            for (e in initializers) {
+                val length = sb.length
+                if (first) {
+                    first = false
+                } else {
+                    sb.append(", ")
+                }
+                val appended = appendExpression(sb, e, inlineConstants)
+                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 sb.length != 2
+        } else if (expression is UReferenceExpression) {
+            val resolved = expression.resolve()
+            if (resolved is PsiField) {
+                val field = resolved as PsiField?
+                if (!inlineConstants) {
+                    // Inline constants
+                    val value = field!!.computeConstantValue()
+                    if (appendLiteralValue(sb, value)) {
+                        return true
+                    }
+                }
+
+                val declaringClass = field!!.containingClass
+                if (declaringClass == null) {
+                    error("No containing class found for " + field.name)
+                    return false
+                }
+                val qualifiedName = declaringClass.qualifiedName
+                val fieldName = field.name
+
+                if (qualifiedName != null) {
+                    val cls = codebase.findClass(qualifiedName)
+                    val fld = cls?.findField(fieldName, true)
+                    if (fld == null || !filterReference.test(fld)) {
+                        // This field is not visible: remove from typedef
+                        if (fld != null) {
+                            reporter.report(
+                                Errors.HIDDEN_TYPEDEF_CONSTANT, fld,
+                                "Typedef class references hidden field $fld: removed from typedef metadata"
+                            )
+                        }
+                        return false
+                    }
+                    sb.append(qualifiedName)
+                    sb.append('.')
+                    sb.append(fieldName)
+                    return true
+                }
+                return false
+            } else {
+                warning("Unexpected reference to $expression")
+                return false
+            }
+        } else if (expression is ULiteralExpression) {
+            val literalValue = expression.value
+            if (appendLiteralValue(sb, literalValue)) {
+                return true
+            }
+        } else if (expression is UBinaryExpressionWithType) {
+            if ((expression).isTypeCast()) {
+                val operand = expression.operand
+                return appendExpression(sb, operand, inlineConstants)
+            }
+            return false
+        }
+
+        // For example, binary expressions like 3 + 4
+        val literalValue = ConstantEvaluator.evaluate(null, expression)
+        if (literalValue != null) {
+            if (appendLiteralValue(sb, literalValue)) {
+                return true
+            }
+        }
+
+        warning("Unexpected annotation expression of type ${expression.javaClass} and is $expression")
+
+        return false
+    }
+
+    private fun appendLiteralValue(sb: StringBuilder, literalValue: Any?): Boolean {
+        if (literalValue is Number || literalValue is Boolean) {
+            sb.append(literalValue.toString())
+            return true
+        } else if (literalValue is String || literalValue is Char) {
+            sb.append('"')
+            XmlUtils.appendXmlAttributeValue(sb, literalValue.toString())
+            sb.append('"')
+            return true
+        }
+        return false
+    }
+
+    private fun isInlinedConstant(annotationItem: AnnotationItem): Boolean {
+        return annotationItem.isTypeDefAnnotation()
+    }
+
+    /** Whether to sort annotation attributes (otherwise their declaration order is used)  */
+    private val sortAnnotations: Boolean = true
+
+    private fun warning(string: String) {
+        reporter.report(Severity.ERROR, null as PsiElement?, string, Errors.ANNOTATION_EXTRACTION)
+    }
+
+    private fun error(string: String) {
+        reporter.report(Severity.WARNING, null as PsiElement?, string, Errors.ANNOTATION_EXTRACTION)
+    }
 }
diff --git a/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt b/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt
index ebda9ad..7af08d1 100644
--- a/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt
+++ b/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt
@@ -16,7 +16,6 @@
 
 package com.android.tools.metalava
 
-import com.android.annotations.NonNull
 import com.android.tools.metalava.doclava1.Errors
 import com.android.tools.metalava.model.Codebase
 import com.android.tools.metalava.model.FieldItem
@@ -79,15 +78,18 @@
         val doc = method.documentation
         for (exception in exceptions.sortedBy { it.qualifiedName() }) {
             val checked = !(exception.extends("java.lang.RuntimeException") ||
-                    exception.extends("java.lang.Error"))
+                exception.extends("java.lang.Error"))
             if (checked) {
                 val annotation = method.modifiers.findAnnotation("kotlin.jvm.Throws")
                 if (annotation != null) {
-                    val attribute = annotation.findAttribute("exceptionClasses")
+                    annotation.attributes().first().name
+                    val attribute =
+                        annotation.findAttribute("exceptionClasses") ?: annotation.findAttribute("value")
+                        ?: annotation.attributes().firstOrNull()
                     if (attribute != null) {
                         for (v in attribute.leafValues()) {
                             val source = v.toSource()
-                            if (source == exception.qualifiedName() + ".class") { // contains: is
+                            if (source.endsWith(exception.simpleName() + "::class")) {
                                 return
                             }
                         }
@@ -152,7 +154,7 @@
                             } parameters (such as parameter ${i + 1}, \"${parameter.name()}\", in ${
                             method.containingClass().qualifiedName()}.${method.name()
                             }) should be last to improve Kotlin interoperability; see " +
-                                    "https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
+                                "https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
                         reporter.report(Errors.SAM_SHOULD_BE_LAST, method, message)
                         break
                     }
@@ -343,7 +345,7 @@
     }
 
     /** Returns true if the given string is a reserved Java keyword  */
-    fun isJavaKeyword(@NonNull keyword: String): Boolean {
+    fun isJavaKeyword(keyword: String): Boolean {
         // TODO when we built on top of IDEA core replace this with
         //   JavaLexer.isKeyword(candidate, LanguageLevel.JDK_1_5)
         when (keyword) {
diff --git a/src/main/java/com/android/tools/metalava/NullnessMigration.kt b/src/main/java/com/android/tools/metalava/NullnessMigration.kt
index 60c727f..8cb8d6b 100644
--- a/src/main/java/com/android/tools/metalava/NullnessMigration.kt
+++ b/src/main/java/com/android/tools/metalava/NullnessMigration.kt
@@ -17,23 +17,16 @@
 package com.android.tools.metalava
 
 import com.android.tools.metalava.model.AnnotationItem
+import com.android.tools.metalava.model.FieldItem
 import com.android.tools.metalava.model.Item
+import com.android.tools.metalava.model.MethodItem
+import com.android.tools.metalava.model.ParameterItem
+import com.android.tools.metalava.model.TypeItem
 
 /**
  * Performs null migration analysis, looking at previous API signature
  * files and new signature files, and replacing new @Nullable and @NonNull
- * annotations with @NewlyNullable and @NewlyNonNull, and similarly
- * moving @NewlyNullable and @NewlyNonNull to @RecentlyNullable and @RecentlyNonNull
- * (and finally once the annotations have been there for another API level,
- * finally moving them to unconditionally nullable/nonnull.)
- *
- * (Newly null is the initial level; user code is marked as warnings if in
- * conflict with the annotation. Recently null is the next level; once an
- * API has had newly-null metadata in one API level, it gets promoted to
- * recently, which generates errors instead of warnings. The reason we have
- * this instead of just making it unconditional is that you can still invoke
- * the compiler with a flag to defeat it, so the Kotlin team suggested we do
- * this.
+ * annotations with @RecentlyNullable and @RecentlyNonNull.
  *
  * TODO: Enforce compatibility across type use annotations, e.g.
  * changing parameter value from
@@ -42,40 +35,81 @@
  *    {@code @NonNull List<@NonNull String>}
  * is forbidden.
  */
-class NullnessMigration : ComparisonVisitor() {
+class NullnessMigration : ComparisonVisitor(visitAddedItemsRecursively = true) {
     override fun compare(old: Item, new: Item) {
+        if (hasNullnessInformation(new) && !hasNullnessInformation(old)) {
+            markRecent(new)
+        }
+    }
+
+    override fun added(new: Item) {
+        // Translate newly added items into RecentlyNull/RecentlyNonNull
         if (hasNullnessInformation(new)) {
-            if (!hasNullnessInformation(old)) {
-                // Nullness information change: Add migration annotation
-                val annotation = if (isNullable(new)) NEWLY_NULLABLE else NEWLY_NONNULL
+            markRecent(new)
+        }
+    }
+    override fun compare(old: MethodItem, new: MethodItem) {
+        val newType = new.returnType() ?: return
+        val oldType = old.returnType() ?: return
+        checkType(oldType, newType)
+    }
 
-                val migration = findNullnessAnnotation(new) ?: return
-                val modifiers = new.mutableModifiers()
-                modifiers.removeAnnotation(migration)
+    override fun compare(old: FieldItem, new: FieldItem) {
+        val newType = new.type()
+        val oldType = old.type()
+        checkType(oldType, newType)
+    }
 
-                // Don't map annotation names - this would turn newly non null back into non null
-                modifiers.addAnnotation(new.codebase.createAnnotation("@" + annotation, new, mapName = false))
-            } else if (hasMigrationAnnotation(old)) {
-                // Already marked migration before: Now we can promote it to
-                // no longer migrated!
-                val nullAnnotation = findNullnessAnnotation(new) ?: return
-                val migration = findMigrationAnnotation(old)?.toSource() ?: return
-                val modifiers = new.mutableModifiers()
-                modifiers.removeAnnotation(nullAnnotation)
+    override fun compare(old: ParameterItem, new: ParameterItem) {
+        val newType = new.type()
+        val oldType = old.type()
+        checkType(oldType, newType)
+    }
 
-                if (isNewlyMigrated(old)) {
-                    // Move from newly to recently
-                    val source = migration.replace("Newly", "Recently")
-                    modifiers.addAnnotation(new.codebase.createAnnotation(source, new, mapName = false))
-                } else {
-                    // Move from recently to no longer marked as migrated
-                    val source = migration.replace("Newly", "").replace("Recently", "")
-                    modifiers.addAnnotation(new.codebase.createAnnotation(source, new, mapName = false))
-                }
+    override fun added(new: MethodItem) {
+        checkType(new.returnType() ?: return)
+    }
+
+    override fun added(new: FieldItem) {
+        checkType(new.type())
+    }
+
+    override fun added(new: ParameterItem) {
+        checkType(new.type())
+    }
+
+    private fun hasNullnessInformation(type: TypeItem): Boolean {
+        val typeString = type.toTypeString(false, true, false)
+        return typeString.contains(".Nullable") || typeString.contains(".NonNull")
+    }
+
+    private fun checkType(old: TypeItem, new: TypeItem) {
+        if (hasNullnessInformation(new)) {
+            if (old.toTypeString(false, true, false) !=
+                new.toTypeString(false, true, false)) {
+                new.markRecent()
             }
         }
     }
 
+    private fun checkType(new: TypeItem) {
+        if (hasNullnessInformation(new)) {
+            new.markRecent()
+        }
+    }
+
+    private fun markRecent(new: Item) {
+        val annotation = findNullnessAnnotation(new) ?: return
+        // Nullness information change: Add migration annotation
+        val annotationClass = if (annotation.isNullable()) RECENTLY_NULLABLE else RECENTLY_NONNULL
+
+        val modifiers = new.mutableModifiers()
+        modifiers.removeAnnotation(annotation)
+
+        // Don't map annotation names - this would turn newly non null back into non null
+        modifiers.addAnnotation(new.codebase.createAnnotation("@$annotationClass", new, mapName = false))
+    }
+
     companion object {
         fun hasNullnessInformation(item: Item): Boolean {
             return isNullable(item) || isNonNull(item)
@@ -85,86 +119,21 @@
             return item.modifiers.annotations().firstOrNull { it.isNullnessAnnotation() }
         }
 
-        fun findMigrationAnnotation(item: Item): AnnotationItem? {
-            return item.modifiers.annotations().firstOrNull {
-                val qualifiedName = it.qualifiedName() ?: ""
-                isMigrationAnnotation(qualifiedName)
-            }
-        }
-
         fun isNullable(item: Item): Boolean {
             return item.modifiers.annotations().any { it.isNullable() }
         }
 
-        fun isNonNull(item: Item): Boolean {
+        private fun isNonNull(item: Item): Boolean {
             return item.modifiers.annotations().any { it.isNonNull() }
         }
 
-        fun hasMigrationAnnotation(item: Item): Boolean {
-            return item.modifiers.annotations().any { isMigrationAnnotation(it.qualifiedName() ?: "") }
-        }
-
-        fun isNewlyMigrated(item: Item): Boolean {
-            return item.modifiers.annotations().any { isNewlyMigrated(it.qualifiedName() ?: "") }
-        }
-
-        fun isRecentlyMigrated(item: Item): Boolean {
+        private fun isRecentlyMigrated(item: Item): Boolean {
             return item.modifiers.annotations().any { isRecentlyMigrated(it.qualifiedName() ?: "") }
         }
 
-        fun isNewlyMigrated(qualifiedName: String): Boolean {
-            return qualifiedName.endsWith(".NewlyNullable") ||
-                    qualifiedName.endsWith(".NewlyNonNull")
-        }
-
-        fun isRecentlyMigrated(qualifiedName: String): Boolean {
+        private fun isRecentlyMigrated(qualifiedName: String): Boolean {
             return qualifiedName.endsWith(".RecentlyNullable") ||
-                    qualifiedName.endsWith(".RecentlyNonNull")
-        }
-
-        fun isMigrationAnnotation(qualifiedName: String): Boolean {
-            return isNewlyMigrated(qualifiedName) || isRecentlyMigrated(qualifiedName)
+                qualifiedName.endsWith(".RecentlyNonNull")
         }
     }
 }
-
-/**
- * @TypeQualifierNickname
- * @NonNull
- * @kotlin.annotations.jvm.UnderMigration(status = kotlin.annotations.jvm.MigrationStatus.WARN)
- * @Retention(RetentionPolicy.CLASS)
- * public @interface NewlyNullable {
- * }
- */
-const val NEWLY_NULLABLE = "android.support.annotation.NewlyNullable"
-
-/**
- * @TypeQualifierNickname
- * @NonNull
- * @kotlin.annotations.jvm.UnderMigration(status = kotlin.annotations.jvm.MigrationStatus.WARN)
- * @Retention(RetentionPolicy.CLASS)
- * public @interface NewlyNonNull {
- * }
- */
-const val NEWLY_NONNULL = "android.support.annotation.NewlyNonNull"
-
-/**
- * @TypeQualifierNickname
- * @NonNull
- * @kotlin.annotations.jvm.UnderMigration(status = kotlin.annotations.jvm.MigrationStatus.STRICT)
- * @Retention(RetentionPolicy.CLASS)
- * public @interface NewlyNullable {
- * }
- */
-
-const val RECENTLY_NULLABLE = "android.support.annotation.RecentlyNullable"
-/**
- * @TypeQualifierNickname
- * @NonNull
- * @kotlin.annotations.jvm.UnderMigration(status = kotlin.annotations.jvm.MigrationStatus.STRICT)
- * @Retention(RetentionPolicy.CLASS)
- * public @interface NewlyNonNull {
- * }
- */
-const val RECENTLY_NONNULL = "android.support.annotation.RecentlyNonNull"
-
diff --git a/src/main/java/com/android/tools/metalava/Options.kt b/src/main/java/com/android/tools/metalava/Options.kt
index 8fc443b..b2c1c68 100644
--- a/src/main/java/com/android/tools/metalava/Options.kt
+++ b/src/main/java/com/android/tools/metalava/Options.kt
@@ -18,13 +18,12 @@
 
 import com.android.SdkConstants
 import com.android.sdklib.SdkVersionInfo
-import com.android.tools.lint.annotations.ApiDatabase
 import com.android.tools.metalava.doclava1.Errors
 import com.android.utils.SdkUtils.wrap
 import com.google.common.base.CharMatcher
 import com.google.common.base.Splitter
-import com.google.common.collect.Lists
 import com.google.common.io.Files
+import com.intellij.pom.java.LanguageLevel
 import java.io.File
 import java.io.IOException
 import java.io.OutputStreamWriter
@@ -48,25 +47,25 @@
 private const val ARG_SOURCE_FILES = "--source-files"
 private const val ARG_API = "--api"
 private const val ARG_PRIVATE_API = "--private-api"
+private const val ARG_DEX_API = "--dex-api"
 private const val ARG_PRIVATE_DEX_API = "--private-dex-api"
 private const val ARG_SDK_VALUES = "--sdk-values"
 private const val ARG_REMOVED_API = "--removed-api"
+private const val ARG_REMOVED_DEX_API = "--removed-dex-api"
 private const val ARG_MERGE_ANNOTATIONS = "--merge-annotations"
 private const val ARG_INPUT_API_JAR = "--input-api-jar"
 private const val ARG_EXACT_API = "--exact-api"
 private const val ARG_STUBS = "--stubs"
+private const val ARG_DOC_STUBS = "--doc-stubs"
 private const val ARG_STUBS_SOURCE_LIST = "--write-stubs-source-list"
+private const val ARG_DOC_STUBS_SOURCE_LIST = "--write-doc-stubs-source-list"
 private const val ARG_PROGUARD = "--proguard"
 private const val ARG_EXTRACT_ANNOTATIONS = "--extract-annotations"
 private const val ARG_EXCLUDE_ANNOTATIONS = "--exclude-annotations"
-private const val ARG_API_FILTER = "--api-filter"
-private const val ARG_RM_TYPEDEFS = "--rmtypedefs"
-private const val ARG_TYPEDEF_FILE = "--typedef-file"
-private const val ARG_SKIP_CLASS_RETENTION = "--skip-class-retention"
-private const val ARG_HIDE_FILTERED = "--hide-filtered"
 private const val ARG_HIDE_PACKAGE = "--hide-package"
 private const val ARG_MANIFEST = "--manifest"
 private const val ARG_PREVIOUS_API = "--previous-api"
+private const val ARG_CURRENT_API = "--current-api"
 private const val ARG_MIGRATE_NULLNESS = "--migrate-nullness"
 private const val ARG_CHECK_COMPATIBILITY = "--check-compatibility"
 private const val ARG_INPUT_KOTLIN_NULLS = "--input-kotlin-nulls"
@@ -74,6 +73,8 @@
 private const val ARG_OUTPUT_DEFAULT_VALUES = "--output-default-values"
 private const val ARG_ANNOTATION_COVERAGE_STATS = "--annotation-coverage-stats"
 private const val ARG_ANNOTATION_COVERAGE_OF = "--annotation-coverage-of"
+private const val ARG_WRITE_CLASS_COVERAGE_TO = "--write-class-coverage-to"
+private const val ARG_WRITE_MEMBER_COVERAGE_TO = "--write-member-coverage-to"
 private const val ARG_WARNINGS_AS_ERRORS = "--warnings-as-errors"
 private const val ARG_LINTS_AS_ERRORS = "--lints-as-errors"
 private const val ARG_SHOW_ANNOTATION = "--show-annotation"
@@ -90,7 +91,6 @@
 private const val ARG_UNHIDE_CLASSPATH_CLASSES = "--unhide-classpath-classes"
 private const val ARG_ALLOW_REFERENCING_UNKNOWN_CLASSES = "--allow-referencing-unknown-classes"
 private const val ARG_NO_UNKNOWN_CLASSES = "--no-unknown-classes"
-private const val ARG_INCLUDE_DOC_ONLY = "--include-doconly"
 private const val ARG_APPLY_API_LEVELS = "--apply-api-levels"
 private const val ARG_GENERATE_API_LEVELS = "--generate-api-levels"
 private const val ARG_ANDROID_JAR_PATTERN = "--android-jar-pattern"
@@ -105,6 +105,8 @@
 private const val ARG_HIDDEN = "--hidden"
 private const val ARG_NO_DOCS = "--no-docs"
 private const val ARG_GENERATE_DOCUMENTATION = "--generate-documentation"
+private const val ARG_JAVA_SOURCE = "--java-source"
+private const val ARG_REGISTER_ARTIFACT = "--register-artifact"
 
 class Options(
     args: Array<String>,
@@ -224,10 +226,17 @@
     /** If set, a directory to write stub files to. Corresponds to the --stubs/-stubs flag. */
     var stubsDir: File? = null
 
+    /** If set, a directory to write documentation stub files to. Corresponds to the --stubs/-stubs flag. */
+    var docStubsDir: File? = null
+
     /** If set, a source file to write the stub index (list of source files) to. Can be passed to
      * other tools like javac/javadoc using the special @-syntax. */
     var stubsSourceList: File? = null
 
+    /** If set, a source file to write the doc stub index (list of source files) to. Can be passed to
+     * other tools like javac/javadoc using the special @-syntax. */
+    var docStubsSourceList: File? = null
+
     /** Proguard Keep list file to write */
     var proguard: File? = null
 
@@ -237,6 +246,9 @@
     /** If set, a file to write the private API file to. Corresponds to the --private-api/-privateApi flag. */
     var privateApiFile: File? = null
 
+    /** If set, a file to write the DEX signatures to. Corresponds to --dex-api. */
+    var dexApiFile: File? = null
+
     /** If set, a file to write the private DEX signatures to. Corresponds to --private-dex-api. */
     var privateDexApiFile: File? = null
 
@@ -249,27 +261,32 @@
     /** A manifest file to read to for example look up available permissions */
     var manifest: File? = null
 
-    /** If set, a file to write an API file to. Corresponds to the --removed-api/-removedApi flag. */
+    /** If set, a file to write a dex API file to. Corresponds to the --removed-dex-api/-removedDexApi flag. */
     var removedApiFile: File? = null
 
+    /** If set, a file to write an API file to. Corresponds to the --removed-api/-removedApi flag. */
+    var removedDexApiFile: File? = null
+
     /** Whether output should be colorized */
     var color = System.getenv("TERM")?.startsWith("xterm") ?: false
 
     /** Whether to omit Java and Kotlin runtime library packages from annotation coverage stats */
-    var omitRuntimePackageStats = true
-
-    /** Whether to include doc-only-marked items */
-    var includeDocOnly = false
+    var omitRuntimePackageStats = false
 
     /** Whether to generate annotations into the stubs */
     var generateAnnotations = true
 
     /**
-     * A signature file for the previous version of this API (for compatibility checks, nullness
-     * migration, etc.)
+     * A signature file for the previous version of this API (for nullness
+     * migration, possibly for compatibility checking (if [currentApi] is not defined), etc.)
      */
     var previousApi: File? = null
 
+    /**
+     * A signature file for the current version of this API (for compatibility checks).
+     */
+    var currentApi: File? = null
+
     /** Whether we should check API compatibility based on the previous API in [previousApi] */
     var checkCompatibility: Boolean = false
 
@@ -282,20 +299,11 @@
     /** Set of jars and class files for existing apps that we want to measure coverage of */
     var annotationCoverageOf: List<File> = mutableAnnotationCoverageOf
 
-    /** Framework API definition to restrict included APIs to */
-    var apiFilter: ApiDatabase? = null
+    /** File to write the annotation class coverage report to, if any */
+    var annotationCoverageClassReport: File? = null
 
-    /** If filtering out non-APIs, supply this flag to hide listing matches */
-    var hideFiltered: Boolean = false
-
-    /** Don't extract annotations that have class retention */
-    var skipClassRetention: Boolean = false
-
-    /** Remove typedef classes found in the given folder */
-    var rmTypeDefs: File? = null
-
-    /** Framework API definition to restrict included APIs to */
-    var typedefFile: File? = null
+    /** File to write the annotation member coverage report to, if any */
+    var annotationCoverageMemberReport: File? = null
 
     /** An optional <b>jar</b> file to load classes from instead of from source.
      * This is similar to the [classpath] attribute except we're explicitly saying
@@ -330,6 +338,9 @@
      */
     var apiLevelJars: Array<File>? = null
 
+    /** The api level of the codebase, or -1 if not known/specified */
+    var currentApiLevel = -1
+
     /** API level XML file to generate */
     var generateApiLevelXml: File? = null
 
@@ -346,6 +357,14 @@
      */
     var omitLocations = false
 
+    /**
+     * The language level to use for Java files, set with [ARG_JAVA_SOURCE]
+     */
+    var javaLanguageLevel: LanguageLevel = LanguageLevel.JDK_1_8
+
+    /** Map from XML API descriptor file to corresponding artifact id name */
+    val artifactRegistrations = ArtifactTagger()
+
     init {
         // Pre-check whether --color/--no-color is present and use that to decide how
         // to emit the banner even before we emit errors
@@ -369,9 +388,7 @@
         stdout.println()
         stdout.flush()
 
-        val apiFilters = mutableListOf<File>()
         var androidJarPatterns: MutableList<String>? = null
-        var currentApiLevel: Int = -1
         var currentCodeName: String? = null
         var currentJar: File? = null
 
@@ -428,13 +445,16 @@
                 "-sdkvalues", ARG_SDK_VALUES -> sdkValueDir = stringToNewDir(getValue(args, ++index))
 
                 ARG_API, "-api" -> apiFile = stringToNewFile(getValue(args, ++index))
+                ARG_DEX_API, "-dexApi" -> dexApiFile = stringToNewFile(getValue(args, ++index))
 
                 ARG_PRIVATE_API, "-privateApi" -> privateApiFile = stringToNewFile(getValue(args, ++index))
                 ARG_PRIVATE_DEX_API, "-privateDexApi" -> privateDexApiFile = stringToNewFile(getValue(args, ++index))
 
                 ARG_REMOVED_API, "-removedApi" -> removedApiFile = stringToNewFile(getValue(args, ++index))
+                ARG_REMOVED_DEX_API, "-removedDexApi" -> removedDexApiFile = stringToNewFile(getValue(args, ++index))
 
                 ARG_EXACT_API, "-exactApi" -> {
+                    getValue(args, ++index) // prevent next arg from tripping up parser
                     unimplemented(arg) // Not yet implemented (because it seems to no longer be hooked up in doclava1)
                 }
 
@@ -452,7 +472,9 @@
                 "--hideAnnotations", "-hideAnnotation" -> mutableHideAnnotations.add(getValue(args, ++index))
 
                 ARG_STUBS, "-stubs" -> stubsDir = stringToNewDir(getValue(args, ++index))
+                ARG_DOC_STUBS -> docStubsDir = stringToNewDir(getValue(args, ++index))
                 ARG_STUBS_SOURCE_LIST -> stubsSourceList = stringToNewFile(getValue(args, ++index))
+                ARG_DOC_STUBS_SOURCE_LIST -> docStubsSourceList = stringToNewFile(getValue(args, ++index))
 
                 ARG_EXCLUDE_ANNOTATIONS -> generateAnnotations = false
 
@@ -503,6 +525,7 @@
                 ARG_EXTRACT_ANNOTATIONS -> externalAnnotations = stringToNewFile(getValue(args, ++index))
 
                 ARG_PREVIOUS_API -> previousApi = stringToExistingFile(getValue(args, ++index))
+                ARG_CURRENT_API -> currentApi = stringToExistingFile(getValue(args, ++index))
 
                 ARG_MIGRATE_NULLNESS -> migrateNulls = true
 
@@ -511,19 +534,35 @@
                 }
 
                 ARG_ANNOTATION_COVERAGE_STATS -> dumpAnnotationStatistics = true
-                ARG_ANNOTATION_COVERAGE_OF -> mutableAnnotationCoverageOf.add(
-                    stringToExistingFileOrDir(
+                ARG_ANNOTATION_COVERAGE_OF -> mutableAnnotationCoverageOf.addAll(
+                    stringToExistingDirsOrJars(
                         getValue(args, ++index)
                     )
                 )
+                ARG_WRITE_CLASS_COVERAGE_TO -> {
+                    annotationCoverageClassReport = stringToNewFile(getValue(args, ++index))
+                }
+                ARG_WRITE_MEMBER_COVERAGE_TO -> {
+                    annotationCoverageMemberReport = stringToNewFile(getValue(args, ++index))
+                }
 
                 ARG_ERROR, "-error" -> Errors.setErrorLevel(getValue(args, ++index), Severity.ERROR)
                 ARG_WARNING, "-warning" -> Errors.setErrorLevel(getValue(args, ++index), Severity.WARNING)
                 ARG_LINT, "-lint" -> Errors.setErrorLevel(getValue(args, ++index), Severity.LINT)
                 ARG_HIDE, "-hide" -> Errors.setErrorLevel(getValue(args, ++index), Severity.HIDDEN)
 
-                ARG_WARNINGS_AS_ERRORS, "-werror" -> warningsAreErrors = true
-                ARG_LINTS_AS_ERRORS, "-lerror" -> lintsAreErrors = true
+                ARG_WARNINGS_AS_ERRORS -> warningsAreErrors = true
+                ARG_LINTS_AS_ERRORS -> lintsAreErrors = true
+                "-werror" -> {
+                    // Temporarily disabled; this is used in various builds but is pretty much
+                    // never what we want.
+                    //warningsAreErrors = true
+                }
+                "-lerror" -> {
+                    // Temporarily disabled; this is used in various builds but is pretty much
+                    // never what we want.
+                    //lintsAreErrors = true
+                }
 
                 ARG_CHECK_KOTLIN_INTEROP -> checkKotlinInterop = true
 
@@ -542,15 +581,6 @@
                 ARG_ALLOW_REFERENCING_UNKNOWN_CLASSES -> allowReferencingUnknownClasses = true
                 ARG_NO_UNKNOWN_CLASSES -> noUnknownClasses = true
 
-                ARG_INCLUDE_DOC_ONLY -> includeDocOnly = true
-
-            // Annotation extraction flags
-                ARG_API_FILTER -> apiFilters.add(stringToExistingFile(getValue(args, ++index)))
-                ARG_RM_TYPEDEFS -> rmTypeDefs = stringToExistingDir(getValue(args, ++index))
-                ARG_TYPEDEF_FILE -> typedefFile = stringToNewFile(getValue(args, ++index))
-                ARG_HIDE_FILTERED -> hideFiltered = true
-                ARG_SKIP_CLASS_RETENTION -> skipClassRetention = true
-
             // Extracting API levels
                 ARG_ANDROID_JAR_PATTERN -> {
                     val list = androidJarPatterns ?: run {
@@ -576,7 +606,13 @@
                     generateApiLevelXml = stringToNewFile(getValue(args, ++index))
                 }
                 ARG_APPLY_API_LEVELS -> {
-                    applyApiLevelsXml = stringToExistingFile(getValue(args, ++index))
+                    applyApiLevelsXml = if (args.contains(ARG_GENERATE_API_LEVELS)) {
+                        // If generating the API file at the same time, it doesn't have
+                        // to already exist
+                        stringToNewFile(getValue(args, ++index))
+                    } else {
+                        stringToExistingFile(getValue(args, ++index))
+                    }
                 }
 
                 ARG_NO_DOCS, "-nodocs" -> noDocs = true
@@ -585,10 +621,16 @@
                     // Digest all the remaining arguments.
                     // Allow "STUBS_DIR" to reference the stubs directory.
                     invokeDocumentationToolArguments = args.slice(++index until args.size).mapNotNull {
-                        if (it == "STUBS_DIR" && stubsDir != null) {
+                        if (it == "STUBS_DIR" && docStubsDir != null) {
+                            docStubsDir?.path
+                        } else if (it == "STUBS_DIR" && stubsDir != null) {
                             stubsDir?.path
+                        } else if (it == "DOC_STUBS_SOURCE_LIST" && docStubsSourceList != null) {
+                            "@${docStubsSourceList?.path}"
                         } else if (it == "STUBS_SOURCE_LIST" && stubsSourceList != null) {
                             "@${stubsSourceList?.path}"
+                        } else if (it == "STUBS_SOURCE_LIST" && docStubsSourceList != null) {
+                            "@${docStubsSourceList?.path}"
                         } else {
                             it
                         }
@@ -597,8 +639,15 @@
                     index = args.size // jump to end of argument loop
                 }
 
+                ARG_REGISTER_ARTIFACT, "-artifact" -> {
+                    val descriptor = stringToExistingFile(getValue(args, ++index))
+                    val artifactId = getValue(args, ++index)
+                    artifactRegistrations.register(artifactId, descriptor)
+                }
+
             // Unimplemented doclava1 flags (no arguments)
-                "-quiet" -> {
+                "-quiet",
+                "-yamlV2" -> {
                     unimplemented(arg)
                 }
 
@@ -624,10 +673,13 @@
                     }
                 }
 
-                "-source" -> {
+                ARG_JAVA_SOURCE, "-source" -> {
                     val value = getValue(args, ++index)
-                    if (value != "1.8") {
-                        throw DriverException("$value: Only source 1.8 is supported")
+                    val level = LanguageLevel.parse(value)
+                    when {
+                        level == null -> throw DriverException("$value is not a valid or supported Java language level")
+                        level.isLessThan(LanguageLevel.JDK_1_7) -> throw DriverException("$arg must be at least 1.7")
+                        else -> javaLanguageLevel = level
                     }
                 }
 
@@ -680,7 +732,6 @@
             // doclava1 flags with two arguments
                 "-federate",
                 "-federationapi",
-                "-artifact",
                 "-htmldir2" -> {
                     javadoc(arg)
                     index += 2
@@ -739,8 +790,7 @@
                     } else if (arg.startsWith(ARGS_COMPAT_OUTPUT)) {
                         compatOutput = if (arg == ARGS_COMPAT_OUTPUT)
                             true
-                        else
-                            yesNo(arg.substring(ARGS_COMPAT_OUTPUT.length + 1))
+                        else yesNo(arg.substring(ARGS_COMPAT_OUTPUT.length + 1))
                     } else if (arg.startsWith("-")) {
                         // Compatibility flag; map to mutable properties in the Compatibility
                         // class and assign it
@@ -769,26 +819,11 @@
             ++index
         }
 
-        if (!apiFilters.isEmpty()) {
-            apiFilter = try {
-                val lines = Lists.newArrayList<String>()
-                for (file in apiFilters) {
-                    lines.addAll(Files.readLines(file, com.google.common.base.Charsets.UTF_8))
-                }
-                ApiDatabase(lines)
-            } catch (e: IOException) {
-                throw DriverException("Could not open API database $apiFilters: ${e.localizedMessage}")
-            }
-        }
-
         if (generateApiLevelXml != null) {
-            if (currentJar != null && currentApiLevel == -1 || currentJar == null && currentApiLevel != -1) {
-                throw DriverException("You must specify both --current-jar and --current-version (or neither one)")
-            }
             if (androidJarPatterns == null) {
                 androidJarPatterns = mutableListOf(
                     "prebuilts/tools/common/api-versions/android-%/android.jar",
-                    "prebuilts/sdk/%/android.jar"
+                    "prebuilts/sdk/%/public/android.jar"
                 )
             }
             apiLevelJars = findAndroidJars(androidJarPatterns!!, currentApiLevel, currentCodeName, currentJar)
@@ -822,8 +857,10 @@
     }
 
     private fun findAndroidJars(
-        androidJarPatterns: List<String>, currentApiLevel: Int,
-        currentCodeName: String?, currentJar: File?
+        androidJarPatterns: List<String>,
+        currentApiLevel: Int,
+        currentCodeName: String?,
+        currentJar: File?
     ): Array<File> {
 
         @Suppress("NAME_SHADOWING")
@@ -883,8 +920,8 @@
 
     /** Makes sure that the flag combinations make sense */
     private fun checkFlagConsistency() {
-        if (checkCompatibility && previousApi == null) {
-            throw DriverException(stderr = "$ARG_CHECK_COMPATIBILITY requires $ARG_PREVIOUS_API")
+        if (checkCompatibility && currentApi == null && previousApi == null) {
+            throw DriverException(stderr = "$ARG_CHECK_COMPATIBILITY requires $ARG_CURRENT_API")
         }
 
         if (migrateNulls && previousApi == null) {
@@ -898,20 +935,16 @@
         if (compatOutput && outputKotlinStyleNulls) {
             throw DriverException(
                 stderr = "$ARG_OUTPUT_KOTLIN_NULLS should not be combined with " +
-                        "$ARGS_COMPAT_OUTPUT=yes"
+                    "$ARGS_COMPAT_OUTPUT=yes"
             )
         }
 
         if (compatOutput && outputDefaultValues) {
             throw DriverException(
                 stderr = "$ARG_OUTPUT_DEFAULT_VALUES should not be combined with " +
-                        "$ARGS_COMPAT_OUTPUT=yes"
+                    "$ARGS_COMPAT_OUTPUT=yes"
             )
         }
-
-//        if (stubsSourceList != null && stubsDir == null) {
-//            throw OptionsException(stderr = "$ARG_STUBS_SOURCE_LIST should only be used when $ARG_STUBS is set")
-//        }
     }
 
     private fun javadoc(arg: String) {
@@ -932,11 +965,11 @@
         }
         if (!options.quiet) {
             val message = "Ignoring unimplemented doclava1 flag $arg" +
-                    when (arg) {
-                        "-encoding" -> " (UTF-8 assumed)"
-                        "-source" -> "  (1.8 assumed)"
-                        else -> ""
-                    }
+                when (arg) {
+                    "-encoding" -> " (UTF-8 assumed)"
+                    "-source" -> "  (1.8 assumed)"
+                    else -> ""
+                }
             reporter.report(Severity.WARNING, null as String?, message, color = color)
         }
     }
@@ -1124,28 +1157,30 @@
             ARG_NO_COLOR, "Do not attempt to colorize the output",
 
             "", "\nAPI sources:",
-            ARG_SOURCE_FILES + " <files>", "A comma separated list of source files to be parsed. Can also be " +
-                    "@ followed by a path to a text file containing paths to the full set of files to parse.",
+            "$ARG_SOURCE_FILES <files>", "A comma separated list of source files to be parsed. Can also be " +
+                "@ followed by a path to a text file containing paths to the full set of files to parse.",
 
-            ARG_SOURCE_PATH + " <paths>", "One or more directories (separated by `${File.pathSeparator}`) " +
-                    "containing source files (within a package hierarchy)",
+            "$ARG_SOURCE_PATH <paths>", "One or more directories (separated by `${File.pathSeparator}`) " +
+                "containing source files (within a package hierarchy)",
 
-            ARG_CLASS_PATH + " <paths>", "One or more directories or jars (separated by " +
-                    "`${File.pathSeparator}`) containing classes that should be on the classpath when parsing the " +
-                    "source files",
+            "$ARG_CLASS_PATH <paths>", "One or more directories or jars (separated by " +
+                "`${File.pathSeparator}`) containing classes that should be on the classpath when parsing the " +
+                "source files",
 
-            ARG_MERGE_ANNOTATIONS + " <file>", "An external annotations file (using IntelliJ's external " +
-                    "annotations database format) to merge and overlay the sources",
+            "$ARG_MERGE_ANNOTATIONS <file>", "An external annotations file (using IntelliJ's external " +
+                "annotations database format) to merge and overlay the sources. A subset of .jaif files " +
+                "is also supported.",
 
-            ARG_INPUT_API_JAR + " <file>", "A .jar file to read APIs from directly",
+            "$ARG_INPUT_API_JAR <file>", "A .jar file to read APIs from directly",
 
-            ARG_MANIFEST + " <file>", "A manifest file, used to for check permissions to cross check APIs",
+            "$ARG_MANIFEST <file>", "A manifest file, used to for check permissions to cross check APIs",
 
-            ARG_HIDE_PACKAGE + " <package>", "Remove the given packages from the API even if they have not been " +
-                    "marked with @hide",
+            "$ARG_HIDE_PACKAGE <package>", "Remove the given packages from the API even if they have not been " +
+                "marked with @hide",
 
-            ARG_SHOW_ANNOTATION + " <annotation class>", "Include the given annotation in the API analysis",
+            "$ARG_SHOW_ANNOTATION <annotation class>", "Include the given annotation in the API analysis",
             ARG_SHOW_UNANNOTATED, "Include un-annotated public APIs in the signature file as well",
+            "$ARG_JAVA_SOURCE <level>", "Sets the source level for Java source files; default is 1.8.",
 
             "", "\nDocumentation:",
             ARG_PUBLIC, "Only include elements that are public",
@@ -1156,83 +1191,97 @@
 
             "", "\nExtracting Signature Files:",
             // TODO: Document --show-annotation!
-            ARG_API + " <file>", "Generate a signature descriptor file",
-            ARG_PRIVATE_API + " <file>", "Generate a signature descriptor file listing the exact private APIs",
-            ARG_PRIVATE_DEX_API + " <file>", "Generate a DEX signature descriptor file listing the exact private APIs",
-            ARG_REMOVED_API + " <file>", "Generate a signature descriptor file for APIs that have been removed",
-            ARG_OUTPUT_KOTLIN_NULLS + "[=yes|no]", "Controls whether nullness annotations should be formatted as " +
-                    "in Kotlin (with \"?\" for nullable types, \"\" for non nullable types, and \"!\" for unknown. " +
-                    "The default is yes.",
-            ARG_OUTPUT_DEFAULT_VALUES + "[=yes|no]", "Controls whether default values should be included in " +
-                    "signature files. The default is yes.",
-            ARGS_COMPAT_OUTPUT + "=[yes|no]", "Controls whether to keep signature files compatible with the " +
-                    "historical format (with its various quirks) or to generate the new format (which will also include " +
-                    "annotations that are part of the API, etc.)",
-            ARG_OMIT_COMMON_PACKAGES + "[=yes|no]", "Skip common package prefixes like java.lang.* and " +
-                    "kotlin.* in signature files, along with packages for well known annotations like @Nullable and " +
-                    "@NonNull.",
+            "$ARG_API <file>", "Generate a signature descriptor file",
+            "$ARG_PRIVATE_API <file>", "Generate a signature descriptor file listing the exact private APIs",
+            "$ARG_DEX_API <file>", "Generate a DEX signature descriptor file listing the APIs",
+            "$ARG_PRIVATE_DEX_API <file>", "Generate a DEX signature descriptor file listing the exact private APIs",
+            "$ARG_REMOVED_API <file>", "Generate a signature descriptor file for APIs that have been removed",
+            "$ARG_OUTPUT_KOTLIN_NULLS[=yes|no]", "Controls whether nullness annotations should be formatted as " +
+                "in Kotlin (with \"?\" for nullable types, \"\" for non nullable types, and \"!\" for unknown. " +
+                "The default is yes.",
+            "$ARG_OUTPUT_DEFAULT_VALUES[=yes|no]", "Controls whether default values should be included in " +
+                "signature files. The default is yes.",
+            "$ARGS_COMPAT_OUTPUT=[yes|no]", "Controls whether to keep signature files compatible with the " +
+                "historical format (with its various quirks) or to generate the new format (which will also include " +
+                "annotations that are part of the API, etc.)",
+            "$ARG_OMIT_COMMON_PACKAGES[=yes|no]", "Skip common package prefixes like java.lang.* and " +
+                "kotlin.* in signature files, along with packages for well known annotations like @Nullable and " +
+                "@NonNull.",
 
-            ARG_PROGUARD + " <file>", "Write a ProGuard keep file for the API",
-            ARG_SDK_VALUES + " <dir>", "Write SDK values files to the given directory",
+            "$ARG_PROGUARD <file>", "Write a ProGuard keep file for the API",
+            "$ARG_SDK_VALUES <dir>", "Write SDK values files to the given directory",
 
             "", "\nGenerating Stubs:",
-            ARG_STUBS + " <dir>", "Generate stub source files for the API",
+            "$ARG_STUBS <dir>", "Generate stub source files for the API",
+            "$ARG_DOC_STUBS <dir>", "Generate documentation stub source files for the API. Documentation stub " +
+                "files are similar to regular stub files, but there are some differences. For example, in " +
+                "the stub files, we'll use special annotations like @RecentlyNonNull instead of @NonNull to " +
+                "indicate that an element is recently marked as non null, whereas in the documentation stubs we'll " +
+                "just list this as @NonNull. Another difference is that @doconly elements are included in " +
+                "documentation stubs, but not regular stubs, etc.",
             ARG_EXCLUDE_ANNOTATIONS, "Exclude annotations such as @Nullable from the stub files",
-            ARG_STUBS_SOURCE_LIST + " <file>", "Write the list of generated stub files into the given source " +
-                    "list file",
+            "$ARG_STUBS_SOURCE_LIST <file>", "Write the list of generated stub files into the given source " +
+                "list file. If generating documentation stubs and you haven't also specified " +
+                "$ARG_DOC_STUBS_SOURCE_LIST, this list will refer to the documentation stubs; " +
+                "otherwise it's the non-documentation stubs.",
+            "$ARG_DOC_STUBS_SOURCE_LIST <file>", "Write the list of generated doc stub files into the given source " +
+                "list file",
+            "$ARG_REGISTER_ARTIFACT <api-file> <id>", "Registers the given id for the packages found in " +
+                "the given signature file. $PROGRAM_NAME will inject an @artifactId <id> tag into every top " +
+                "level stub class in that API.",
 
             "", "\nDiffs and Checks:",
-            ARG_PREVIOUS_API + " <signature file>", "A signature file for the previous version of this " +
-                    "API to apply diffs with",
-            ARG_INPUT_KOTLIN_NULLS + "[=yes|no]", "Whether the signature file being read should be " +
-                    "interpreted as having encoded its types using Kotlin style types: a suffix of \"?\" for nullable " +
-                    "types, no suffix for non nullable types, and \"!\" for unknown. The default is no.",
+            "$ARG_PREVIOUS_API <signature file>", "A signature file for the previous version of this " +
+                "API to apply diffs with",
+            "$ARG_INPUT_KOTLIN_NULLS[=yes|no]", "Whether the signature file being read should be " +
+                "interpreted as having encoded its types using Kotlin style types: a suffix of \"?\" for nullable " +
+                "types, no suffix for non nullable types, and \"!\" for unknown. The default is no.",
             ARG_CHECK_COMPATIBILITY, "Check compatibility with the previous API",
             ARG_CHECK_KOTLIN_INTEROP, "Check API intended to be used from both Kotlin and Java for interoperability " +
-                    "issues",
+                "issues",
+            "$ARG_CURRENT_API <signature file>", "A signature file for the current version of this " +
+                "API to check compatibility with. If not specified, $ARG_PREVIOUS_API will be used " +
+                "instead.",
             ARG_MIGRATE_NULLNESS, "Compare nullness information with the previous API and mark newly " +
-                    "annotated APIs as under migration.",
+                "annotated APIs as under migration.",
             ARG_WARNINGS_AS_ERRORS, "Promote all warnings to errors",
             ARG_LINTS_AS_ERRORS, "Promote all API lint warnings to errors",
-            ARG_ERROR + " <id>", "Report issues of the given id as errors",
-            ARG_WARNING + " <id>", "Report issues of the given id as warnings",
-            ARG_LINT + " <id>", "Report issues of the given id as having lint-severity",
-            ARG_HIDE + " <id>", "Hide/skip issues of the given id",
+            "$ARG_ERROR <id>", "Report issues of the given id as errors",
+            "$ARG_WARNING <id>", "Report issues of the given id as warnings",
+            "$ARG_LINT <id>", "Report issues of the given id as having lint-severity",
+            "$ARG_HIDE <id>", "Hide/skip issues of the given id",
 
             "", "\nStatistics:",
             ARG_ANNOTATION_COVERAGE_STATS, "Whether $PROGRAM_NAME should emit coverage statistics for " +
-                    "annotations, listing the percentage of the API that has been annotated with nullness information.",
+                "annotations, listing the percentage of the API that has been annotated with nullness information.",
 
-            ARG_ANNOTATION_COVERAGE_OF + " <paths>", "One or more jars (separated by `${File.pathSeparator}`) " +
-                    "containing existing apps that we want to measure annotation coverage statistics for. The set of " +
-                    "API usages in those apps are counted up and the most frequently used APIs that are missing " +
-                    "annotation metadata are listed in descending order.",
+            "$ARG_ANNOTATION_COVERAGE_OF <paths>", "One or more jars (separated by `${File.pathSeparator}`) " +
+                "containing existing apps that we want to measure annotation coverage statistics for. The set of " +
+                "API usages in those apps are counted up and the most frequently used APIs that are missing " +
+                "annotation metadata are listed in descending order.",
 
             ARG_SKIP_JAVA_IN_COVERAGE_REPORT, "In the coverage annotation report, skip java.** and kotlin.** to " +
-                    "narrow the focus down to the Android framework APIs.",
+                "narrow the focus down to the Android framework APIs.",
+
+            "$ARG_WRITE_CLASS_COVERAGE_TO <path>", "Specifies a file to write the annotation " +
+                "coverage report for classes to.",
+            "$ARG_WRITE_MEMBER_COVERAGE_TO <path>", "Specifies a file to write the annotation " +
+                "coverage report for members to.",
 
             "", "\nExtracting Annotations:",
-            ARG_EXTRACT_ANNOTATIONS + " <zipfile>", "Extracts annotations from the source files and writes them " +
-                    "into the given zip file",
-
-            ARG_API_FILTER + " <file>", "Applies the given signature file as a filter (which means no classes," +
-                    "methods or fields not found in the filter will be included.)",
-            ARG_HIDE_FILTERED, "Omit listing APIs that were skipped because of the $ARG_API_FILTER",
-
-            ARG_SKIP_CLASS_RETENTION, "Do not extract annotations that have class file retention",
-            ARG_RM_TYPEDEFS, "Delete all the typedef .class files",
-            ARG_TYPEDEF_FILE + " <file>", "Writes an typedef annotation class names into the given file",
+            "$ARG_EXTRACT_ANNOTATIONS <zipfile>", "Extracts source annotations from the source files and writes " +
+                "them into the given zip file",
 
             "", "\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",
+            "$ARG_APPLY_API_LEVELS <api-versions.xml>", "Reads an XML file containing API level descriptions " +
+                "and merges the information into the documentation",
 
             "", "\nExtracting API Levels:",
-            ARG_GENERATE_API_LEVELS + " <xmlfile>",
+            "$ARG_GENERATE_API_LEVELS <xmlfile>",
             "Reads android.jar SDK files and generates an XML file recording " +
-                    "the API level for each class, method and field",
-            ARG_ANDROID_JAR_PATTERN + " <pattern>", "Patterns to use to locate Android JAR files. The default " +
-                    "is \$ANDROID_HOME/platforms/android-%/android.jar.",
+                "the API level for each class, method and field",
+            "$ARG_ANDROID_JAR_PATTERN <pattern>", "Patterns to use to locate Android JAR files. The default " +
+                "is \$ANDROID_HOME/platforms/android-%/android.jar.",
             ARG_CURRENT_VERSION, "Sets the current API level of the current source code",
             ARG_CURRENT_CODENAME, "Sets the code name for the current source code",
             ARG_CURRENT_JAR, "Points to the current API jar, if any"
diff --git a/src/main/java/com/android/tools/metalava/Reporter.kt b/src/main/java/com/android/tools/metalava/Reporter.kt
index c8d1f0c..846b9ae 100644
--- a/src/main/java/com/android/tools/metalava/Reporter.kt
+++ b/src/main/java/com/android/tools/metalava/Reporter.kt
@@ -188,7 +188,7 @@
             path
         } else {
             val lineNumber = getLineNumber(psiFile.text, range.startOffset) + 1
-            path + ":" + lineNumber
+            "$path:$lineNumber"
         }
     }
 
@@ -214,7 +214,10 @@
     }
 
     open fun report(
-        severity: Severity, location: String?, message: String, id: Errors.Error? = null,
+        severity: Severity,
+        location: String?,
+        message: String,
+        id: Errors.Error? = null,
         color: Boolean = options.color
     ) {
         if (severity == HIDDEN) {
diff --git a/src/main/java/com/android/tools/metalava/SdkFileWriter.kt b/src/main/java/com/android/tools/metalava/SdkFileWriter.kt
index 4f88b62..0d68845 100644
--- a/src/main/java/com/android/tools/metalava/SdkFileWriter.kt
+++ b/src/main/java/com/android/tools/metalava/SdkFileWriter.kt
@@ -80,7 +80,7 @@
                     if (SDK_CONSTANT_ANNOTATION == annotation.qualifiedName()) {
                         val resolved =
                             annotation.findAttribute(null)?.leafValues()?.firstOrNull()?.resolve() as? FieldItem
-                                    ?: continue
+                                ?: continue
                         val type = resolved.containingClass().qualifiedName() + "." + resolved.name()
                         when {
                             SDK_CONSTANT_TYPE_ACTIVITY_ACTION == type -> activityActions.add(value.toString())
diff --git a/src/main/java/com/android/tools/metalava/SignatureWriter.kt b/src/main/java/com/android/tools/metalava/SignatureWriter.kt
index 6d651d1..7fca3d8 100644
--- a/src/main/java/com/android/tools/metalava/SignatureWriter.kt
+++ b/src/main/java/com/android/tools/metalava/SignatureWriter.kt
@@ -23,6 +23,7 @@
 import com.android.tools.metalava.model.MethodItem
 import com.android.tools.metalava.model.ModifierList
 import com.android.tools.metalava.model.PackageItem
+import com.android.tools.metalava.model.ParameterItem
 import com.android.tools.metalava.model.TypeItem
 import com.android.tools.metalava.model.TypeParameterList
 import com.android.tools.metalava.model.javaEscapeString
@@ -57,7 +58,7 @@
         writer.print("    ctor ")
         writeModifiers(constructor)
         // Note - we don't write out the type parameter list (constructor.typeParameterList()) in signature files!
-        //writeTypeParameterList(constructor.typeParameterList(), addSpace = true)
+        // writeTypeParameterList(constructor.typeParameterList(), addSpace = true)
         writer.print(constructor.containingClass().fullName())
         writeParameterList(constructor)
         writeThrowsList(constructor)
@@ -70,7 +71,7 @@
         writer.print(name)
         writer.print(" ")
         writeModifiers(field)
-        writeType(field.type(), field.modifiers)
+        writeType(field, field.type(), field.modifiers)
         writer.print(' ')
         writer.print(field.name())
         field.writeValueWithSemicolon(writer, allowDefaultValue = false, requireInitialValue = false)
@@ -84,7 +85,7 @@
             return
         }
 
-        if (compatibility.skipInheritedInterfaceMethods && method.inheritedInterfaceMethod) {
+        if (compatibility.skipInheritedMethods && method.inheritedMethod) {
             return
         }
 
@@ -92,7 +93,7 @@
         writeModifiers(method)
         writeTypeParameterList(method.typeParameterList(), addSpace = true)
 
-        writeType(method.returnType(), method.modifiers)
+        writeType(method, method.returnType(), method.modifiers)
         writer.print(' ')
         writer.print(method.name())
         writeParameterList(method)
@@ -148,7 +149,8 @@
             includeDeprecated = true,
             includeAnnotations = compatibility.annotationsInSignatures,
             skipNullnessAnnotations = options.outputKotlinStyleNulls,
-            omitCommonPackages = options.omitCommonPackages
+            omitCommonPackages = options.omitCommonPackages,
+            onlyIncludeSignatureAnnotations = true
         )
     }
 
@@ -164,8 +166,7 @@
 
         val superClass = if (preFiltered)
             cls.superClassType()
-        else
-            cls.filteredSuperClassType(filterReference)
+        else cls.filteredSuperClassType(filterReference)
         if (superClass != null && !superClass.isJavaLangObject()) {
             val superClassString =
                 superClass.toTypeString(erased = compatibility.omitTypeParametersInInterfaces)
@@ -185,8 +186,7 @@
 
         val interfaces = if (preFiltered)
             cls.interfaceTypes().asSequence()
-        else
-            cls.filteredInterfaceTypes(filterReference).asSequence()
+        else cls.filteredInterfaceTypes(filterReference).asSequence()
         val all: Sequence<TypeItem> = if (isInterface && compatibility.extendsForInterfaceSuperClass) {
             val superClassType = cls.superClassType()
             if (superClassType != null && !superClassType.isJavaLangObject()) {
@@ -227,7 +227,7 @@
                 writer.print(", ")
             }
             writeModifiers(parameter)
-            writeType(parameter.type(), parameter.modifiers)
+            writeType(parameter, parameter.type(), parameter.modifiers)
             if (emitParameterNames) {
                 val name = parameter.publicName()
                 if (name != null) {
@@ -250,7 +250,11 @@
         writer.print(")")
     }
 
-    private fun writeType(type: TypeItem?, modifiers: ModifierList) {
+    private fun writeType(
+        item: Item,
+        type: TypeItem?,
+        modifiers: ModifierList
+    ) {
         type ?: return
 
         var typeString = type.toTypeString(
@@ -264,6 +268,24 @@
             typeString = TypeItem.shortenTypes(typeString)
         }
 
+        if (typeString.endsWith(", ?>") && compatibility.includeExtendsObjectInWildcard && item is ParameterItem) {
+            // This wasn't done universally; just in a few places, so replicate it for those exact places
+            val methodName = item.containingMethod().name()
+            when (methodName) {
+                "computeIfAbsent" -> {
+                    if (typeString == "java.util.function.Function<? super java.lang.Object, ?>") {
+                        typeString = "java.util.function.Function<? super java.lang.Object, ? extends java.lang.Object>"
+                    }
+                }
+                "computeIfPresent", "merge", "replaceAll", "compute" -> {
+                    if (typeString == "java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ?>") {
+                        typeString =
+                            "java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>"
+                    }
+                }
+            }
+        }
+
         writer.print(typeString)
 
         if (options.outputKotlinStyleNulls && !type.primitive) {
@@ -284,15 +306,14 @@
     }
 
     private fun writeThrowsList(method: MethodItem) {
-        val throws = if (preFiltered)
-            method.throwsTypes().asSequence().sortedWith(ClassItem.fullNameComparator)
-        else
-            method.throwsTypes().asSequence()
-                .filter { filterReference.test(it) }
-                .sortedWith(ClassItem.fullNameComparator)
+        val throws = when {
+            preFiltered -> method.throwsTypes().asSequence()
+            compatibility.filterThrowsClasses -> method.filteredThrowsTypes(filterReference).asSequence()
+            else -> method.throwsTypes().asSequence()
+        }
         if (throws.any()) {
             writer.print(" throws ")
-            throws.asSequence().forEachIndexed { i, type ->
+            throws.asSequence().sortedWith(ClassItem.fullNameComparator).forEachIndexed { i, type ->
                 if (i > 0) {
                     writer.print(", ")
                 }
diff --git a/src/main/java/com/android/tools/metalava/StubWriter.kt b/src/main/java/com/android/tools/metalava/StubWriter.kt
index 832ff92..40a6a5a 100644
--- a/src/main/java/com/android/tools/metalava/StubWriter.kt
+++ b/src/main/java/com/android/tools/metalava/StubWriter.kt
@@ -44,7 +44,8 @@
     private val codebase: Codebase,
     private val stubsDir: File,
     private val generateAnnotations: Boolean = false,
-    private val preFiltered: Boolean = true
+    private val preFiltered: Boolean = true,
+    docStubs: Boolean
 ) : ApiVisitor(
     visitConstructorsAsMethods = false,
     nestInnerClasses = true,
@@ -53,8 +54,9 @@
     // Methods are by default sorted in source order in stubs, to encourage methods
     // that are near each other in the source to show up near each other in the documentation
     methodComparator = MethodItem.sourceOrderComparator,
-    filterEmit = FilterPredicate(ApiPredicate(codebase)),
-    filterReference = ApiPredicate(codebase, ignoreShown = true)
+    filterEmit = FilterPredicate(ApiPredicate(codebase, ignoreShown = true, includeDocOnly = docStubs)),
+    filterReference = ApiPredicate(codebase, ignoreShown = true, includeDocOnly = docStubs),
+    includeEmptyOuterClasses = true
 ) {
 
     private val sourceList = StringBuilder(20000)
@@ -135,11 +137,14 @@
             ModifierList.writeAnnotations(
                 list = pkg.modifiers,
                 separateLines = true,
+                // Some bug in UAST triggers duplicate nullability annotations
+                // here; make sure the are filtered out
+                filterDuplicates = true,
+                onlyIncludeSignatureAnnotations = true,
                 writer = writer
             )
             writer.println("package ${pkg.qualifiedName()};")
 
-
             writer.flush()
             writer.close()
         }
@@ -159,7 +164,7 @@
     }
 
     private fun getClassFile(classItem: ClassItem): File {
-        assert(classItem.containingClass() == null, { "Should only be called on top level classes" })
+        assert(classItem.containingClass() == null) { "Should only be called on top level classes" }
         // TODO: Look up compilation unit language
         return File(getPackageDir(classItem.containingPackage()), "${classItem.simpleName()}.java")
     }
@@ -296,7 +301,8 @@
 
         ModifierList.write(
             writer, modifiers, item, removeAbstract = removeAbstract, removeFinal = removeFinal,
-            addPublic = addPublic, includeAnnotations = generateAnnotations
+            addPublic = addPublic, includeAnnotations = generateAnnotations,
+            onlyIncludeSignatureAnnotations = true
         )
     }
 
@@ -308,9 +314,7 @@
 
         val superClass = if (preFiltered)
             cls.superClassType()
-        else
-            cls.filteredSuperClassType(filterReference)
-
+        else cls.filteredSuperClassType(filterReference)
 
         if (superClass != null && !superClass.isJavaLangObject()) {
             val qualifiedName = superClass.toTypeString()
@@ -340,14 +344,12 @@
 
         val interfaces = if (preFiltered)
             cls.interfaceTypes().asSequence()
-        else
-            cls.filteredInterfaceTypes(filterReference).asSequence()
+        else cls.filteredInterfaceTypes(filterReference).asSequence()
 
         if (interfaces.any()) {
             if (cls.isInterface() && cls.superClassType() != null)
                 writer.print(", ")
-            else
-                writer.print(" implements")
+            else writer.print(" implements")
             interfaces.forEachIndexed { index, type ->
                 if (index > 0) {
                     writer.print(",")
@@ -409,7 +411,7 @@
             val invokeOnThis = constructor != null && constructor.containingClass() == it.containingClass()
             if (invokeOnThis || parameters.isNotEmpty()) {
                 val includeCasts = parameters.isNotEmpty() &&
-                        it.containingClass().constructors().filter { filterReference.test(it) }.size > 1
+                    it.containingClass().constructors().filter { filterReference.test(it) }.size > 1
                 if (invokeOnThis) {
                     writer.print("this(")
                 } else {
@@ -434,7 +436,6 @@
                             writer.write(")")
                         }
                         writer.write("null")
-
                     } else {
                         if (typeString != "boolean" && typeString != "int" && typeString != "long") {
                             writer.write("(")
@@ -471,8 +472,8 @@
         val isAnnotation = containingClass.isAnnotationType()
 
         if (isEnum && (method.name() == "values" ||
-                    method.name() == "valueOf" && method.parameters().size == 1 &&
-                    method.parameters()[0].type().toTypeString() == JAVA_LANG_STRING)
+                method.name() == "valueOf" && method.parameters().size == 1 &&
+                method.parameters()[0].type().toTypeString() == JAVA_LANG_STRING)
         ) {
             // Skip the values() and valueOf(String) methods in enums: these are added by
             // the compiler for enums anyway, but was part of the doclava1 signature files
@@ -563,10 +564,11 @@
 
     private fun generateThrowsList(method: MethodItem) {
         // Note that throws types are already sorted internally to help comparison matching
-        val throws = if (preFiltered)
+        val throws = if (preFiltered) {
             method.throwsTypes().asSequence()
-        else
-            method.throwsTypes().asSequence().filter { filterReference.test(it) }
+        } else {
+            method.filteredThrowsTypes(filterReference).asSequence()
+        }
         if (throws.any()) {
             writer.print(" throws ")
             throws.asSequence().sortedWith(ClassItem.fullNameComparator).forEachIndexed { i, type ->
diff --git a/src/main/java/com/android/tools/metalava/Terminal.kt b/src/main/java/com/android/tools/metalava/Terminal.kt
index 8a32691..8ba7551 100644
--- a/src/main/java/com/android/tools/metalava/Terminal.kt
+++ b/src/main/java/com/android/tools/metalava/Terminal.kt
@@ -30,8 +30,11 @@
 }
 
 fun terminalAttributes(
-    bold: Boolean = false, underline: Boolean = false, reverse: Boolean = false,
-    foreground: TerminalColor? = null, background: TerminalColor? = null
+    bold: Boolean = false,
+    underline: Boolean = false,
+    reverse: Boolean = false,
+    foreground: TerminalColor? = null,
+    background: TerminalColor? = null
 ): String {
     val sb = StringBuilder()
     sb.append("\u001B[")
@@ -81,8 +84,11 @@
 
 fun PrintWriter.terminalPrint(
     string: String,
-    bold: Boolean = false, underline: Boolean = false, reverse: Boolean = false,
-    foreground: TerminalColor? = null, background: TerminalColor? = null
+    bold: Boolean = false,
+    underline: Boolean = false,
+    reverse: Boolean = false,
+    foreground: TerminalColor? = null,
+    background: TerminalColor? = null
 ) {
     print(
         terminalAttributes(
diff --git a/src/main/java/com/android/tools/metalava/apilevels/AddApisFromCodebase.kt b/src/main/java/com/android/tools/metalava/apilevels/AddApisFromCodebase.kt
new file mode 100644
index 0000000..f46ca3a
--- /dev/null
+++ b/src/main/java/com/android/tools/metalava/apilevels/AddApisFromCodebase.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.apilevels
+
+import com.android.tools.metalava.model.ClassItem
+import com.android.tools.metalava.model.Codebase
+import com.android.tools.metalava.model.FieldItem
+import com.android.tools.metalava.model.MethodItem
+import com.android.tools.metalava.model.visitors.ApiVisitor
+
+/** Visits the API codebase and inserts into the [Api] the classes, methods and fields */
+fun addApisFromCodebase(api: Api, apiLevel: Int, codebase: Codebase) {
+    codebase.accept(object : ApiVisitor(
+        codebase,
+        visitConstructorsAsMethods = true,
+        nestInnerClasses = false
+    ) {
+
+        var currentClass: ApiClass? = null
+
+        override fun afterVisitClass(cls: ClassItem) {
+            currentClass = null
+        }
+
+        override fun visitClass(cls: ClassItem) {
+            val newClass = api.addClass(cls.internalName(), apiLevel, cls.deprecated)
+            currentClass = newClass
+
+            if (cls.isClass()) {
+                // Sadly it looks like the signature files use the non-public references instead
+                val filteredSuperClass = cls.filteredSuperclass(filterReference)
+                val superClass = cls.superClass()
+                if (filteredSuperClass != superClass && filteredSuperClass != null) {
+                    val existing = newClass.superClasses.firstOrNull()?.name
+                    if (existing == superClass?.internalName()) {
+                        newClass.addSuperClass(superClass?.internalName(), apiLevel)
+                    } else {
+                        newClass.addSuperClass(filteredSuperClass.internalName(), apiLevel)
+                    }
+                } else if (superClass != null) {
+                    newClass.addSuperClass(superClass.internalName(), apiLevel)
+                }
+            }
+
+            for (interfaceType in cls.filteredInterfaceTypes(filterReference)) {
+                val interfaceClass = interfaceType.asClass() ?: return
+                newClass.addInterface(interfaceClass.internalName(), apiLevel)
+            }
+        }
+
+        override fun visitMethod(method: MethodItem) {
+            currentClass?.addMethod(
+                method.internalName() +
+                    // Use "V" instead of the type of the constructor for backwards compatibility
+                    // with the older bytecode
+                    method.internalDesc(voidConstructorTypes = true), apiLevel, method.deprecated
+            )
+        }
+
+        override fun visitField(field: FieldItem) {
+            // We end up moving constants from interfaces in the codebase but that's not the
+            // case in older bytecode
+            if (field.isCloned()) {
+                return
+            }
+            currentClass?.addField(field.internalName(), apiLevel, field.deprecated)
+        }
+    })
+}
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/metalava/apilevels/AndroidJarReader.java b/src/main/java/com/android/tools/metalava/apilevels/AndroidJarReader.java
index 378d536..c5a7d59 100644
--- a/src/main/java/com/android/tools/metalava/apilevels/AndroidJarReader.java
+++ b/src/main/java/com/android/tools/metalava/apilevels/AndroidJarReader.java
@@ -15,9 +15,11 @@
  */
 package com.android.tools.metalava.apilevels;
 
-import com.android.annotations.NonNull;
+import com.android.tools.metalava.model.Codebase;
 import com.google.common.io.ByteStreams;
 import com.google.common.io.Closeables;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.tree.ClassNode;
@@ -40,16 +42,23 @@
     private File mCurrentJar;
     private List<String> mPatterns;
     private File[] mApiLevels;
+    private final Codebase mCodebase;
 
-    AndroidJarReader(@NonNull List<String> patterns, int minApi, @NonNull File currentJar, int currentApi) {
+    AndroidJarReader(@NotNull List<String> patterns,
+                     int minApi,
+                     @NotNull File currentJar,
+                     int currentApi,
+                     @Nullable Codebase codebase) {
         mPatterns = patterns;
         mMinApi = minApi;
         mCurrentJar = currentJar;
         mCurrentApi = currentApi;
+        mCodebase = codebase;
     }
 
-    AndroidJarReader(@NonNull File[] apiLevels) {
+    AndroidJarReader(@NotNull File[] apiLevels, @Nullable Codebase codebase) {
         mApiLevels = apiLevels;
+        mCodebase = codebase;
     }
 
     public Api getApi() throws IOException {
@@ -59,6 +68,12 @@
                 File jar = getAndroidJarFile(apiLevel);
                 readJar(api, apiLevel, jar);
             }
+            if (mCodebase != null) {
+                int apiLevel = mCodebase.getApiLevel();
+                if (apiLevel != -1) {
+                    processCodebase(api, apiLevel);
+                }
+            }
         } else {
             // Get all the android.jar. They are in platforms-#
             int apiLevel = mMinApi - 1;
@@ -72,10 +87,11 @@
                     jar = getAndroidJarFile(apiLevel);
                 }
                 if (jar == null || !jar.isFile()) {
-                    System.out.println("Last API level found: " + (apiLevel - 1));
+                    if (mCodebase != null) {
+                        processCodebase(api, apiLevel);
+                    }
                     break;
                 }
-                System.out.println("Found API " + apiLevel + " at " + jar.getPath());
                 readJar(api, apiLevel, jar);
             }
         }
@@ -86,6 +102,13 @@
         return api;
     }
 
+    private void processCodebase(Api api, int apiLevel) {
+        if (mCodebase == null) {
+            return;
+        }
+        AddApisFromCodebaseKt.addApisFromCodebase(api, apiLevel, mCodebase);
+    }
+
     private void readJar(Api api, int apiLevel, File jar) throws IOException {
         api.update(apiLevel);
 
@@ -108,7 +131,7 @@
                 reader.accept(classNode, 0 /*flags*/);
 
                 ApiClass theClass = api.addClass(classNode.name, apiLevel,
-                        (classNode.access & Opcodes.ACC_DEPRECATED) != 0);
+                    (classNode.access & Opcodes.ACC_DEPRECATED) != 0);
 
                 // super class
                 if (classNode.superName != null) {
@@ -127,7 +150,7 @@
                         continue;
                     }
                     if (!fieldNode.name.startsWith("this$") &&
-                            !fieldNode.name.equals("$VALUES")) {
+                        !fieldNode.name.equals("$VALUES")) {
                         boolean deprecated = (fieldNode.access & Opcodes.ACC_DEPRECATED) != 0;
                         theClass.addField(fieldNode.name, apiLevel, deprecated);
                     }
diff --git a/src/main/java/com/android/tools/metalava/apilevels/Api.java b/src/main/java/com/android/tools/metalava/apilevels/Api.java
index 30dc5f7..f37e9c3 100644
--- a/src/main/java/com/android/tools/metalava/apilevels/Api.java
+++ b/src/main/java/com/android/tools/metalava/apilevels/Api.java
@@ -23,7 +23,7 @@
  * Represents the whole Android API.
  */
 public class Api extends ApiElement {
-    private final Map<String, ApiClass> mClasses = new HashMap<String, ApiClass>();
+    private final Map<String, ApiClass> mClasses = new HashMap<>();
 
     public Api() {
         // Pretend that API started from version 0 to make sure that classes existed in the first version
diff --git a/src/main/java/com/android/tools/metalava/apilevels/ApiClass.java b/src/main/java/com/android/tools/metalava/apilevels/ApiClass.java
index 90dd511..d215ec0 100644
--- a/src/main/java/com/android/tools/metalava/apilevels/ApiClass.java
+++ b/src/main/java/com/android/tools/metalava/apilevels/ApiClass.java
@@ -16,6 +16,7 @@
 package com.android.tools.metalava.apilevels;
 
 import com.google.common.collect.Iterables;
+import org.jetbrains.annotations.NotNull;
 
 import java.io.PrintStream;
 import java.util.ArrayList;
@@ -30,11 +31,11 @@
  * This is used to write the simplified XML file containing all the public API.
  */
 public class ApiClass extends ApiElement {
-    private final List<ApiElement> mSuperClasses = new ArrayList<ApiElement>();
-    private final List<ApiElement> mInterfaces = new ArrayList<ApiElement>();
+    private final List<ApiElement> mSuperClasses = new ArrayList<>();
+    private final List<ApiElement> mInterfaces = new ArrayList<>();
 
-    private final Map<String, ApiElement> mFields = new HashMap<String, ApiElement>();
-    private final Map<String, ApiElement> mMethods = new HashMap<String, ApiElement>();
+    private final Map<String, ApiElement> mFields = new HashMap<>();
+    private final Map<String, ApiElement> mMethods = new HashMap<>();
 
     public ApiClass(String name, int version, boolean deprecated) {
         super(name, version, deprecated);
@@ -52,6 +53,11 @@
         addToArray(mSuperClasses, superClass, since);
     }
 
+    @NotNull
+    List<ApiElement> getSuperClasses() {
+        return mSuperClasses;
+    }
+
     public void addInterface(String interfaceClass, int since) {
         addToArray(mInterfaces, interfaceClass, since);
     }
diff --git a/src/main/java/com/android/tools/metalava/apilevels/ApiElement.java b/src/main/java/com/android/tools/metalava/apilevels/ApiElement.java
index a5b38dd..ab5af66 100644
--- a/src/main/java/com/android/tools/metalava/apilevels/ApiElement.java
+++ b/src/main/java/com/android/tools/metalava/apilevels/ApiElement.java
@@ -15,7 +15,7 @@
  */
 package com.android.tools.metalava.apilevels;
 
-import com.android.annotations.NonNull;
+import org.jetbrains.annotations.NotNull;
 
 import java.io.PrintStream;
 import java.util.ArrayList;
@@ -182,7 +182,7 @@
     }
 
     private <T extends ApiElement> List<T> sortedList(Collection<T> elements) {
-        List<T> list = new ArrayList<T>(elements);
+        List<T> list = new ArrayList<>(elements);
         Collections.sort(list);
         return list;
     }
@@ -225,7 +225,7 @@
     }
 
     @Override
-    public int compareTo(@NonNull ApiElement other) {
+    public int compareTo(@NotNull ApiElement other) {
         return mName.compareTo(other.mName);
     }
 }
diff --git a/src/main/java/com/android/tools/metalava/apilevels/ApiGenerator.java b/src/main/java/com/android/tools/metalava/apilevels/ApiGenerator.java
index e3b3225..afcac41 100644
--- a/src/main/java/com/android/tools/metalava/apilevels/ApiGenerator.java
+++ b/src/main/java/com/android/tools/metalava/apilevels/ApiGenerator.java
@@ -16,7 +16,9 @@
 
 package com.android.tools.metalava.apilevels;
 
-import com.android.annotations.NonNull;
+import com.android.tools.metalava.model.Codebase;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
 import java.io.IOException;
@@ -93,10 +95,8 @@
             } else if (arg.length() >= 2 && arg.substring(0, 2).equals("--")) {
                 System.err.println("Unknown argument: " + arg);
                 error = true;
-
             } else if (outPath == null) {
                 outPath = arg;
-
             } else if (new File(arg).isDirectory()) {
                 String pattern = arg;
                 if (!pattern.endsWith(File.separator)) {
@@ -104,7 +104,6 @@
                 }
                 pattern += "platforms" + File.separator + "android-%" + File.separator + "android.jar";
                 patterns.add(pattern);
-
             } else {
                 System.err.println("Unknown argument: " + arg);
                 error = true;
@@ -137,7 +136,7 @@
         }
 
         try {
-            if (!generate(minApi, currentApi, currentJar, patterns, outPath)) {
+            if (!generate(minApi, currentApi, currentJar, patterns, outPath, null)) {
                 System.exit(1);
             }
         } catch (IOException e) {
@@ -148,16 +147,19 @@
 
     private static boolean generate(int minApi,
                                     int currentApi,
-                                    @NonNull File currentJar,
-                                    @NonNull List<String> patterns,
-                                    @NonNull String outPath) throws IOException {
-        AndroidJarReader reader = new AndroidJarReader(patterns, minApi, currentJar, currentApi);
+                                    @NotNull File currentJar,
+                                    @NotNull List<String> patterns,
+                                    @NotNull String outPath,
+                                    @Nullable Codebase codebase) throws IOException {
+        AndroidJarReader reader = new AndroidJarReader(patterns, minApi, currentJar, currentApi, codebase);
         Api api = reader.getApi();
         return createApiFile(new File(outPath), api);
     }
 
-    public static boolean generate(@NonNull File[] apiLevels, @NonNull File outputFile) throws IOException {
-        AndroidJarReader reader = new AndroidJarReader(apiLevels);
+    public static boolean generate(@NotNull File[] apiLevels,
+                                   @NotNull File outputFile,
+                                   @Nullable Codebase codebase) throws IOException {
+        AndroidJarReader reader = new AndroidJarReader(apiLevels, codebase);
         Api api = reader.getApi();
         return createApiFile(outputFile, api);
     }
@@ -165,16 +167,16 @@
     private static void printUsage() {
         System.err.println("\nGenerates a single API file from the content of an SDK.");
         System.err.println("Usage:");
-        System.err.println("\tApiCheck [--min-api=1] OutFile [SdkFolder | --pattern sdk/%/android.jar]+");
+        System.err.println("\tApiCheck [--min-api=1] OutFile [SdkFolder | --pattern sdk/%/public/android.jar]+");
         System.err.println("Options:");
         System.err.println("--min-api <int> : The first API level to consider (>=1).");
         System.err.println("--pattern <pattern>: Path pattern to find per-API android.jar files, where\n" +
-                "            '%' is replaced by the API level.");
+            "            '%' is replaced by the API level.");
         System.err.println("--current-jar <path>: Path pattern to find the current android.jar");
         System.err.println("--current-version <int>: The API level for the current API");
         System.err.println("--current-codename <name>: REL, if a release, or codename for previews");
         System.err.println("SdkFolder: if given, this adds the pattern\n" +
-                "           '$SdkFolder/platforms/android-%/android.jar'");
+            "           '$SdkFolder/platforms/android-%/android.jar'");
         System.err.println("If multiple --pattern are specified, they are tried in the order given.\n");
     }
 
@@ -185,26 +187,20 @@
      * @param api     the api to write
      */
     private static boolean createApiFile(File outFile, Api api) {
-        PrintStream stream = null;
-        try {
-            File parentFile = outFile.getParentFile();
-            if (!parentFile.exists()) {
-                boolean ok = parentFile.mkdirs();
-                if (!ok) {
-                    System.err.println("Could not create directory " + parentFile);
-                    return false;
-                }
+        File parentFile = outFile.getParentFile();
+        if (!parentFile.exists()) {
+            boolean ok = parentFile.mkdirs();
+            if (!ok) {
+                System.err.println("Could not create directory " + parentFile);
+                return false;
             }
-            stream = new PrintStream(outFile, "UTF-8");
+        }
+        try (PrintStream stream = new PrintStream(outFile, "UTF-8")) {
             stream.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
             api.print(stream);
         } catch (Exception e) {
             e.printStackTrace();
             return false;
-        } finally {
-            if (stream != null) {
-                stream.close();
-            }
         }
 
         return true;
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 88bfbbb..fca21ff 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/ApiFile.java
+++ b/src/main/java/com/android/tools/metalava/doclava1/ApiFile.java
@@ -16,7 +16,6 @@
 
 package com.android.tools.metalava.doclava1;
 
-import com.android.tools.lint.annotations.Extractor;
 import com.android.tools.lint.checks.infrastructure.ClassNameKt;
 import com.android.tools.metalava.model.AnnotationItem;
 import com.android.tools.metalava.model.TypeParameterList;
@@ -38,6 +37,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static com.android.tools.metalava.ConstantsKt.ANDROIDX_NOTNULL;
+import static com.android.tools.metalava.ConstantsKt.ANDROIDX_NULLABLE;
 import static com.android.tools.metalava.ConstantsKt.JAVA_LANG_ANNOTATION;
 import static com.android.tools.metalava.ConstantsKt.JAVA_LANG_ENUM;
 import static com.android.tools.metalava.ConstantsKt.JAVA_LANG_STRING;
@@ -89,7 +90,7 @@
     }
 
     private static void parsePackage(TextCodebase api, Tokenizer tokenizer)
-            throws ApiParseException {
+        throws ApiParseException {
         String token;
         String name;
         TextPackageItem pkg;
@@ -114,7 +115,7 @@
     }
 
     private static void parseClass(TextCodebase api, TextPackageItem pkg, Tokenizer tokenizer, String token)
-            throws ApiParseException {
+        throws ApiParseException {
         boolean isPublic = false;
         boolean isProtected = false;
         boolean isPrivate = false;
@@ -217,9 +218,9 @@
         token = tokenizer.requireToken();
 
         cl = new TextClassItem(api, tokenizer.pos(), isPublic, isProtected,
-                isPrivate, internal, isStatic, isInterface, isAbstract, isEnum, isAnnotation,
-                isFinal, sealed, typeInfo.toErasedTypeString(), typeInfo.qualifiedTypeName(),
-                rawName, annotations);
+            isPrivate, internal, isStatic, isInterface, isAbstract, isEnum, isAnnotation,
+            isFinal, sealed, typeInfo.toErasedTypeString(), typeInfo.qualifiedTypeName(),
+            rawName, annotations);
         cl.setContainingPackage(pkg);
         cl.setTypeInfo(typeInfo);
         cl.setDeprecated(isDeprecated);
@@ -282,17 +283,17 @@
         if (api.getKotlinStyleNulls()) {
             if (token.endsWith("?")) {
                 token = token.substring(0, token.length() - 1);
-                annotations = mergeAnnotations(annotations, Extractor.SUPPORT_NULLABLE);
+                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
-                    annotations = mergeAnnotations(annotations, Extractor.SUPPORT_NOTNULL);
+                    annotations = mergeAnnotations(annotations, ANDROIDX_NOTNULL);
                 }
             }
         } else if (token.endsWith("?") || token.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: " + token);
         }
         //noinspection unchecked
         return new Pair<>(token, annotations);
@@ -337,7 +338,7 @@
     }
 
     private static void parseConstructor(TextCodebase api, Tokenizer tokenizer, TextClassItem cl, String token)
-            throws ApiParseException {
+        throws ApiParseException {
         boolean isPublic = false;
         boolean isProtected = false;
         boolean isPrivate = false;
@@ -389,12 +390,12 @@
             throw new ApiParseException("expected (", tokenizer.getLine());
         }
         method = new TextConstructorItem(api, /*typeParameters*/
-                name, /*signature*/ cl, isPublic, isProtected, isPrivate, isInternal, false/*isFinal*/,
-                false/*isStatic*/, /*isSynthetic*/ false/*isAbstract*/, false/*isSynthetic*/,
-                false/*isNative*/, false/* isDefault */,
-                /*isAnnotationElement*/  /*flatSignature*/
-                /*overriddenMethod*/ cl.asTypeInfo(),
-                /*thrownExceptions*/ tokenizer.pos(), annotations);
+            name, /*signature*/ cl, isPublic, isProtected, isPrivate, isInternal, false/*isFinal*/,
+            false/*isStatic*/, /*isSynthetic*/ false/*isAbstract*/, false/*isSynthetic*/,
+            false/*isNative*/, false/* isDefault */,
+            /*isAnnotationElement*/  /*flatSignature*/
+            /*overriddenMethod*/ cl.asTypeInfo(),
+            /*thrownExceptions*/ tokenizer.pos(), annotations);
         method.setDeprecated(isDeprecated);
         token = tokenizer.requireToken();
         parseParameterList(api, tokenizer, method, /*new HashSet<String>(),*/ token);
@@ -409,7 +410,7 @@
     }
 
     private static void parseMethod(TextCodebase api, Tokenizer tokenizer, TextClassItem cl, String token)
-            throws ApiParseException {
+        throws ApiParseException {
         boolean isPublic = false;
         boolean isProtected = false;
         boolean isPrivate = false;
@@ -514,10 +515,10 @@
         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,
-                returnType, tokenizer.pos(), annotations);
+            api, name, /*signature*/ cl,
+            isPublic, isProtected, isPrivate, isInternal, isFinal, isStatic, isAbstract/*isAbstract*/,
+            isSynchronized, false/*isNative*/, isDefault/*isDefault*/, isInfix, isOperator, isInline,
+            returnType, tokenizer.pos(), annotations);
         method.setDeprecated(isDeprecated);
         method.setTypeParameterList(typeParameterList);
         token = tokenizer.requireToken();
@@ -542,15 +543,15 @@
         }
         // Reverse effect of TypeItem.shortenTypes(...)
         String qualifiedName = annotation.indexOf('.') == -1
-                ? "@android.support.annotation" + annotation
-                : "@" + annotation;
+            ? "@androidx.annotation" + annotation
+            : "@" + annotation;
 
         annotations.add(qualifiedName);
         return annotations;
     }
 
     private static void parseField(TextCodebase api, Tokenizer tokenizer, TextClassItem cl, String token, boolean isEnum)
-            throws ApiParseException {
+        throws ApiParseException {
         boolean isPublic = false;
         boolean isProtected = false;
         boolean isPrivate = false;
@@ -646,8 +647,8 @@
         }
 
         field = new TextFieldItem(api, name, cl, isPublic, isProtected, isPrivate, isInternal, isFinal, isStatic,
-                isTransient, isVolatile, typeInfo, v, tokenizer.pos(),
-                annotations);
+            isTransient, isVolatile, typeInfo, v, tokenizer.pos(),
+            annotations);
         field.setDeprecated(isDeprecated);
         if (isEnum) {
             cl.addEnumConstant(field);
@@ -788,10 +789,10 @@
             }
 
             method.addParameter(new TextParameterItem(api, method, name, publicName, defaultValue, index, type,
-                    typeInfo,
-                    vararg || type.endsWith("..."),
-                    tokenizer.pos(),
-                    annotations));
+                typeInfo,
+                vararg || type.endsWith("..."),
+                tokenizer.pos(),
+                annotations));
             if (type.endsWith("...")) {
                 method.setVarargs(true);
             }
@@ -800,7 +801,7 @@
     }
 
     private static String parseThrows(Tokenizer tokenizer, TextMethodItem method)
-            throws ApiParseException {
+        throws ApiParseException {
         String token = tokenizer.requireToken();
         boolean comma = true;
         while (true) {
@@ -967,7 +968,7 @@
                         }
                     }
                 } while (mPos < mBuf.length
-                        && ((!isSpace(mBuf[mPos]) && !isSeparator(mBuf[mPos], parenIsSep)) || genericDepth != 0));
+                    && ((!isSpace(mBuf[mPos]) && !isSeparator(mBuf[mPos], parenIsSep)) || genericDepth != 0));
                 if (mPos >= mBuf.length) {
                     throw new ApiParseException("Unexpected end of file for \" starting at " + line, mLine);
                 }
@@ -994,9 +995,6 @@
     }
 
     private static boolean isIdent(char c) {
-        if (c == '"' || isSeparator(c, true)) {
-            return false;
-        }
-        return true;
+        return c != '"' && !isSeparator(c, true);
     }
 }
diff --git a/src/main/java/com/android/tools/metalava/doclava1/ApiPredicate.kt b/src/main/java/com/android/tools/metalava/doclava1/ApiPredicate.kt
index dfbcaee..bdace72 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/ApiPredicate.kt
+++ b/src/main/java/com/android/tools/metalava/doclava1/ApiPredicate.kt
@@ -48,7 +48,10 @@
     private val matchRemoved: Boolean = false,
 
     /** Whether we allow matching items loaded from jar files instead of sources */
-    private val allowFromJar: Boolean = true
+    private val allowFromJar: Boolean = true,
+
+    /** Whether we should include doc-only items */
+    private val includeDocOnly: Boolean = false
 ) : Predicate<Item> {
 
     override fun test(member: Item): Boolean {
@@ -94,7 +97,7 @@
             removed = matchRemoved
         }
 
-        if (docOnly && options.includeDocOnly) {
+        if (docOnly && includeDocOnly) {
             docOnly = false
         }
 
diff --git a/src/main/java/com/android/tools/metalava/doclava1/ElidingPredicate.kt b/src/main/java/com/android/tools/metalava/doclava1/ElidingPredicate.kt
index 3f7c9d7..6d091e2 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/ElidingPredicate.kt
+++ b/src/main/java/com/android/tools/metalava/doclava1/ElidingPredicate.kt
@@ -20,8 +20,8 @@
             val differentSuper = method.findPredicateSuperMethod(Predicate { test ->
                 // We're looking for included and perfect signature
                 wrapped.test(test) &&
-                        test is MethodItem &&
-                        MethodItem.sameSignature(method, test, false)
+                    test is MethodItem &&
+                    MethodItem.sameSignature(method, test, false)
             })
             differentSuper == null
         } else {
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 625d865..93ceee1 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/Errors.java
+++ b/src/main/java/com/android/tools/metalava/doclava1/Errors.java
@@ -15,9 +15,9 @@
  */
 package com.android.tools.metalava.doclava1;
 
-import com.android.annotations.Nullable;
 import com.android.tools.metalava.Severity;
 import com.google.common.base.Splitter;
+import org.jetbrains.annotations.Nullable;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
@@ -179,7 +179,7 @@
 
     // Metalava new warnings (not from doclava)
 
-    public static final Error TYPO = new Error(131, LINT);
+    public static final Error TYPO = new Error(131, WARNING);
     public static final Error MISSING_PERMISSION = new Error(132, LINT);
     public static final Error MULTIPLE_THREAD_ANNOTATIONS = new Error(133, LINT);
     public static final Error UNRESOLVED_CLASS = new Error(134, LINT);
@@ -194,6 +194,9 @@
     public static final Error MISSING_JVMSTATIC = new Error(143, WARNING);
     public static final Error DEFAULT_VALUE_CHANGE = new Error(144, ERROR);
     public static final Error DOCUMENT_EXCEPTIONS = new Error(145, ERROR);
+    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);
 
     static {
         // Attempt to initialize error names based on the field names
diff --git a/src/main/java/com/android/tools/metalava/doclava1/FilterPredicate.kt b/src/main/java/com/android/tools/metalava/doclava1/FilterPredicate.kt
index 6fc7557..084c655 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/FilterPredicate.kt
+++ b/src/main/java/com/android/tools/metalava/doclava1/FilterPredicate.kt
@@ -28,7 +28,7 @@
         return when {
             wrapped.test(method) -> true
             method is MethodItem -> !method.isConstructor() &&
-                    method.findPredicateSuperMethod(wrapped) != null
+                method.findPredicateSuperMethod(wrapped) != null
             else -> false
         }
     }
diff --git a/src/main/java/com/android/tools/metalava/doclava1/SourcePositionInfo.java b/src/main/java/com/android/tools/metalava/doclava1/SourcePositionInfo.java
index 015533c..a7f098e 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/SourcePositionInfo.java
+++ b/src/main/java/com/android/tools/metalava/doclava1/SourcePositionInfo.java
@@ -16,7 +16,7 @@
 
 package com.android.tools.metalava.doclava1;
 
-import com.android.annotations.NonNull;
+import org.jetbrains.annotations.NotNull;
 
 // Copied from doclava1
 public class SourcePositionInfo implements Comparable {
@@ -55,7 +55,7 @@
         return file + ':' + line;
     }
 
-    public int compareTo(@NonNull Object o) {
+    public int compareTo(@NotNull Object o) {
         SourcePositionInfo that = (SourcePositionInfo) o;
         int r = this.file.compareTo(that.file);
         if (r != 0) return r;
diff --git a/src/main/java/com/android/tools/metalava/doclava1/TextCodebase.kt b/src/main/java/com/android/tools/metalava/doclava1/TextCodebase.kt
index 0e73a53..2b66cf6 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/TextCodebase.kt
+++ b/src/main/java/com/android/tools/metalava/doclava1/TextCodebase.kt
@@ -16,7 +16,6 @@
 
 package com.android.tools.metalava.doclava1
 
-import com.android.annotations.NonNull
 import com.android.tools.metalava.CodebaseComparator
 import com.android.tools.metalava.ComparisonVisitor
 import com.android.tools.metalava.JAVA_LANG_ANNOTATION
@@ -70,7 +69,7 @@
         return mPackages.size
     }
 
-    override fun findClass(@NonNull className: String): TextClassItem? {
+    override fun findClass(className: String): TextClassItem? {
         return mAllClasses[className]
     }
 
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 a21f0f4..f87833f 100644
--- a/src/main/java/com/android/tools/metalava/model/AnnotationItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/AnnotationItem.kt
@@ -18,10 +18,15 @@
 
 import com.android.SdkConstants
 import com.android.SdkConstants.ATTR_VALUE
+import com.android.SdkConstants.INT_DEF_ANNOTATION
+import com.android.SdkConstants.LONG_DEF_ANNOTATION
+import com.android.SdkConstants.STRING_DEF_ANNOTATION
+import com.android.tools.lint.annotations.Extractor.ANDROID_INT_DEF
+import com.android.tools.lint.annotations.Extractor.ANDROID_LONG_DEF
+import com.android.tools.lint.annotations.Extractor.ANDROID_STRING_DEF
+import com.android.tools.metalava.ANDROIDX_ANNOTATION_PREFIX
 import com.android.tools.metalava.ANDROID_SUPPORT_ANNOTATION_PREFIX
 import com.android.tools.metalava.JAVA_LANG_PREFIX
-import com.android.tools.metalava.NEWLY_NONNULL
-import com.android.tools.metalava.NEWLY_NULLABLE
 import com.android.tools.metalava.Options
 import com.android.tools.metalava.RECENTLY_NONNULL
 import com.android.tools.metalava.RECENTLY_NULLABLE
@@ -34,8 +39,8 @@
 
 fun isNonNullAnnotation(qualifiedName: String): Boolean {
     return qualifiedName.endsWith("NonNull") ||
-            qualifiedName.endsWith("NotNull") ||
-            qualifiedName.endsWith("Nonnull")
+        qualifiedName.endsWith("NotNull") ||
+        qualifiedName.endsWith("Nonnull")
 }
 
 interface AnnotationItem {
@@ -49,7 +54,7 @@
 
     /** Whether this annotation is significant and should be included in signature files, stubs, etc */
     fun isSignificant(): Boolean {
-        return isSignificantAnnotation(qualifiedName() ?: return false)
+        return includeInSignatures(qualifiedName() ?: return false)
     }
 
     /** Attributes of the annotation (may be empty) */
@@ -70,6 +75,17 @@
         return isNonNullAnnotation(qualifiedName() ?: return false)
     }
 
+    /** True if this annotation represents @IntDef, @LongDef or @StringDef */
+    fun isTypeDefAnnotation(): Boolean {
+        val name = qualifiedName() ?: return false
+        return (INT_DEF_ANNOTATION.isEquals(name) ||
+            STRING_DEF_ANNOTATION.isEquals(name) ||
+            LONG_DEF_ANNOTATION.isEquals(name) ||
+            ANDROID_INT_DEF == name ||
+            ANDROID_STRING_DEF == name ||
+            ANDROID_LONG_DEF == name)
+    }
+
     /**
      * True if this annotation represents a @ParameterName annotation (or some synonymous annotation).
      * The parameter name should be the default attribute or "value".
@@ -99,8 +115,20 @@
 
     companion object {
         /** Whether the given annotation name is "significant", e.g. should be included in signature files */
-        fun isSignificantAnnotation(qualifiedName: String?): Boolean {
-            return qualifiedName?.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX) ?: false
+        fun includeInSignatures(qualifiedName: String?): Boolean {
+            qualifiedName ?: return false
+            if (qualifiedName.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX) ||
+                qualifiedName.startsWith(ANDROIDX_ANNOTATION_PREFIX)
+            ) {
+
+                // Don't include typedefs in the stub files.
+                if (qualifiedName.endsWith("IntDef") || qualifiedName.endsWith("StringDef")) {
+                    return false
+                }
+
+                return true
+            }
+            return false
         }
 
         /** The simple name of an annotation, which is the annotation name (not qualified name) prefixed by @ */
@@ -118,63 +146,110 @@
 
             when (qualifiedName) {
             // Resource annotations
-                "android.annotation.AnimRes" -> return "android.support.annotation.AnimRes"
-                "android.annotation.AnimatorRes" -> return "android.support.annotation.AnimatorRes"
-                "android.annotation.AnyRes" -> return "android.support.annotation.AnyRes"
-                "android.annotation.ArrayRes" -> return "android.support.annotation.ArrayRes"
-                "android.annotation.AttrRes" -> return "android.support.annotation.AttrRes"
-                "android.annotation.BoolRes" -> return "android.support.annotation.BoolRes"
-                "android.annotation.ColorRes" -> return "android.support.annotation.ColorRes"
-                "android.annotation.DimenRes" -> return "android.support.annotation.DimenRes"
-                "android.annotation.DrawableRes" -> return "android.support.annotation.DrawableRes"
-                "android.annotation.FontRes" -> return "android.support.annotation.FontRes"
-                "android.annotation.FractionRes" -> return "android.support.annotation.FractionRes"
-                "android.annotation.IdRes" -> return "android.support.annotation.IdRes"
-                "android.annotation.IntegerRes" -> return "android.support.annotation.IntegerRes"
-                "android.annotation.InterpolatorRes" -> return "android.support.annotation.InterpolatorRes"
-                "android.annotation.LayoutRes" -> return "android.support.annotation.LayoutRes"
-                "android.annotation.MenuRes" -> return "android.support.annotation.MenuRes"
-                "android.annotation.PluralsRes" -> return "android.support.annotation.PluralsRes"
-                "android.annotation.RawRes" -> return "android.support.annotation.RawRes"
-                "android.annotation.StringRes" -> return "android.support.annotation.StringRes"
-                "android.annotation.StyleRes" -> return "android.support.annotation.StyleRes"
-                "android.annotation.StyleableRes" -> return "android.support.annotation.StyleableRes"
-                "android.annotation.TransitionRes" -> return "android.support.annotation.TransitionRes"
-                "android.annotation.XmlRes" -> return "android.support.annotation.XmlRes"
+                "android.support.annotation.AnimRes",
+                "android.annotation.AnimRes" -> return "androidx.annotation.AnimRes"
+                "android.support.annotation.AnimatorRes",
+                "android.annotation.AnimatorRes" -> return "androidx.annotation.AnimatorRes"
+                "android.support.annotation.AnyRes",
+                "android.annotation.AnyRes" -> return "androidx.annotation.AnyRes"
+                "android.support.annotation.ArrayRes",
+                "android.annotation.ArrayRes" -> return "androidx.annotation.ArrayRes"
+                "android.support.annotation.AttrRes",
+                "android.annotation.AttrRes" -> return "androidx.annotation.AttrRes"
+                "android.support.annotation.BoolRes",
+                "android.annotation.BoolRes" -> return "androidx.annotation.BoolRes"
+                "android.support.annotation.ColorRes",
+                "android.annotation.ColorRes" -> return "androidx.annotation.ColorRes"
+                "android.support.annotation.DimenRes",
+                "android.annotation.DimenRes" -> return "androidx.annotation.DimenRes"
+                "android.support.annotation.DrawableRes",
+                "android.annotation.DrawableRes" -> return "androidx.annotation.DrawableRes"
+                "android.support.annotation.FontRes",
+                "android.annotation.FontRes" -> return "androidx.annotation.FontRes"
+                "android.support.annotation.FractionRes",
+                "android.annotation.FractionRes" -> return "androidx.annotation.FractionRes"
+                "android.support.annotation.IdRes",
+                "android.annotation.IdRes" -> return "androidx.annotation.IdRes"
+                "android.support.annotation.IntegerRes",
+                "android.annotation.IntegerRes" -> return "androidx.annotation.IntegerRes"
+                "android.support.annotation.InterpolatorRes",
+                "android.annotation.InterpolatorRes" -> return "androidx.annotation.InterpolatorRes"
+                "android.support.annotation.LayoutRes",
+                "android.annotation.LayoutRes" -> return "androidx.annotation.LayoutRes"
+                "android.support.annotation.MenuRes",
+                "android.annotation.MenuRes" -> return "androidx.annotation.MenuRes"
+                "android.support.annotation.PluralsRes",
+                "android.annotation.PluralsRes" -> return "androidx.annotation.PluralsRes"
+                "android.support.annotation.RawRes",
+                "android.annotation.RawRes" -> return "androidx.annotation.RawRes"
+                "android.support.annotation.StringRes",
+                "android.annotation.StringRes" -> return "androidx.annotation.StringRes"
+                "android.support.annotation.StyleRes",
+                "android.annotation.StyleRes" -> return "androidx.annotation.StyleRes"
+                "android.support.annotation.StyleableRes",
+                "android.annotation.StyleableRes" -> return "androidx.annotation.StyleableRes"
+                "android.support.annotation.TransitionRes",
+                "android.annotation.TransitionRes" -> return "androidx.annotation.TransitionRes"
+                "android.support.annotation.XmlRes",
+                "android.annotation.XmlRes" -> return "androidx.annotation.XmlRes"
 
             // Threading
-                "android.annotation.AnyThread" -> return "android.support.annotation.AnyThread"
-                "android.annotation.BinderThread" -> return "android.support.annotation.BinderThread"
-                "android.annotation.MainThread" -> return "android.support.annotation.MainThread"
-                "android.annotation.UiThread" -> return "android.support.annotation.UiThread"
-                "android.annotation.WorkerThread" -> return "android.support.annotation.WorkerThread"
+                "android.support.annotation.AnyThread",
+                "android.annotation.AnyThread" -> return "androidx.annotation.AnyThread"
+                "android.support.annotation.BinderThread",
+                "android.annotation.BinderThread" -> return "androidx.annotation.BinderThread"
+                "android.support.annotation.MainThread",
+                "android.annotation.MainThread" -> return "androidx.annotation.MainThread"
+                "android.support.annotation.UiThread",
+                "android.annotation.UiThread" -> return "androidx.annotation.UiThread"
+                "android.support.annotation.WorkerThread",
+                "android.annotation.WorkerThread" -> return "androidx.annotation.WorkerThread"
 
             // Colors
-                "android.annotation.ColorInt" -> return "android.support.annotation.ColorInt"
-                "android.annotation.ColorLong" -> return "android.support.annotation.ColorLong"
-                "android.annotation.HalfFloat" -> return "android.support.annotation.HalfFloat"
+                "android.support.annotation.ColorInt",
+                "android.annotation.ColorInt" -> return "androidx.annotation.ColorInt"
+                "android.support.annotation.ColorLong",
+                "android.annotation.ColorLong" -> return "androidx.annotation.ColorLong"
+                "android.support.annotation.HalfFloat",
+                "android.annotation.HalfFloat" -> return "androidx.annotation.HalfFloat"
 
             // Ranges and sizes
-                "android.annotation.FloatRange" -> return "android.support.annotation.FloatRange"
-                "android.annotation.IntRange" -> return "android.support.annotation.IntRange"
-                "android.annotation.Size" -> return "android.support.annotation.Size"
-                "android.annotation.Px" -> return "android.support.annotation.Px"
-                "android.annotation.Dimension" -> return "android.support.annotation.Dimension"
+                "android.support.annotation.FloatRange",
+                "android.annotation.FloatRange" -> return "androidx.annotation.FloatRange"
+                "android.support.annotation.IntRange",
+                "android.annotation.IntRange" -> return "androidx.annotation.IntRange"
+                "android.support.annotation.Size",
+                "android.annotation.Size" -> return "androidx.annotation.Size"
+                "android.support.annotation.Px",
+                "android.annotation.Px" -> return "androidx.annotation.Px"
+                "android.support.annotation.Dimension",
+                "android.annotation.Dimension" -> return "androidx.annotation.Dimension"
 
             // Null
-                "android.annotation.NonNull" -> return "android.support.annotation.NonNull"
-                "android.annotation.Nullable" -> return "android.support.annotation.Nullable"
-                "libcore.util.NonNull" -> return "android.support.annotation.NonNull"
-                "libcore.util.Nullable" -> return "android.support.annotation.Nullable"
+                "android.support.annotation.NonNull",
+                "android.annotation.NonNull" -> return "androidx.annotation.NonNull"
+                "android.support.annotation.Nullable",
+                "android.annotation.Nullable" -> return "androidx.annotation.Nullable"
+                "libcore.util.NonNull" -> return "androidx.annotation.NonNull"
+                "libcore.util.Nullable" -> return "androidx.annotation.Nullable"
+                "org.jetbrains.annotations.NotNull" -> return "androidx.annotation.NonNull"
+                "org.jetbrains.annotations.Nullable" -> return "androidx.annotation.Nullable"
 
             // Typedefs
-                "android.annotation.IntDef" -> return "android.support.annotation.IntDef"
-                "android.annotation.StringDef" -> return "android.support.annotation.StringDef"
+                "android.support.annotation.IntDef",
+                "android.annotation.IntDef" -> return "androidx.annotation.IntDef"
+                "android.support.annotation.StringDef",
+                "android.annotation.StringDef" -> return "androidx.annotation.StringDef"
+                "android.support.annotation.LongDef",
+                "android.annotation.LongDef" -> return "androidx.annotation.LongDef"
 
             // Misc
-                "android.annotation.CallSuper" -> return "android.support.annotation.CallSuper"
-                "android.annotation.CheckResult" -> return "android.support.annotation.CheckResult"
-                "android.annotation.RequiresPermission" -> return "android.support.annotation.RequiresPermission"
+                "android.support.annotation.CallSuper",
+                "android.annotation.CallSuper" -> return "androidx.annotation.CallSuper"
+                "android.support.annotation.CheckResult",
+                "android.annotation.CheckResult" -> return "androidx.annotation.CheckResult"
+                "android.support.annotation.RequiresPermission",
+                "android.annotation.RequiresPermission" -> return "androidx.annotation.RequiresPermission"
 
             // These aren't support annotations, but could/should be:
                 "android.annotation.CurrentTimeMillisLong",
@@ -218,8 +293,8 @@
                 "android.annotation.SuppressLint" -> return qualifiedName
 
             // We only change recently/newly nullable annotation if the codebase supports it
-                NEWLY_NULLABLE, RECENTLY_NULLABLE -> return if (codebase.supportsStagedNullability) qualifiedName else "android.support.annotation.Nullable"
-                NEWLY_NONNULL, RECENTLY_NONNULL -> return if (codebase.supportsStagedNullability) qualifiedName else "android.support.annotation.NonNull"
+                RECENTLY_NULLABLE -> return if (codebase.supportsStagedNullability) qualifiedName else "androidx.annotation.Nullable"
+                RECENTLY_NONNULL -> return if (codebase.supportsStagedNullability) qualifiedName else "androidx.annotation.NonNull"
 
                 else -> {
                     // Some new annotations added to the platform: assume they are support annotations?
@@ -229,11 +304,11 @@
                             "kotlin.annotations.jvm.internal${qualifiedName.substring(qualifiedName.lastIndexOf('.'))}"
 
                     // Other third party nullness annotations?
-                        isNullableAnnotation(qualifiedName) -> "android.support.annotation.Nullable"
-                        isNonNullAnnotation(qualifiedName) -> "android.support.annotation.NonNull"
+                        isNullableAnnotation(qualifiedName) -> "androidx.annotation.Nullable"
+                        isNonNullAnnotation(qualifiedName) -> "androidx.annotation.NonNull"
 
                     // Support library annotations are all included, as is the built-in stuff like @Retention
-                        qualifiedName.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX) -> return qualifiedName
+                        qualifiedName.startsWith(ANDROIDX_ANNOTATION_PREFIX) -> return qualifiedName
                         qualifiedName.startsWith(JAVA_LANG_PREFIX) -> return qualifiedName
 
                     // Unknown Android platform annotations
@@ -246,6 +321,14 @@
                             }
                         }
 
+                        qualifiedName.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX) -> {
+                            return mapName(
+                                codebase,
+                                ANDROIDX_ANNOTATION_PREFIX + qualifiedName.substring(ANDROID_SUPPORT_ANNOTATION_PREFIX.length),
+                                filter
+                            )
+                        }
+
                         else -> {
                             // Remove, unless (a) public or (b) specifically included in --showAnnotations
                             return if (options.showAnnotations.contains(qualifiedName)) {
@@ -271,8 +354,8 @@
          * This is intended to be used by the [Options.omitCommonPackages] flag
          * to reduce clutter in signature files.
          *
-         * For example, this method will convert `@android.support.annotation.Nullable` to just
-         * `@Nullable`, and `@android.support.annotation.IntRange(from=20)` to `IntRange(from=20)`.
+         * For example, this method will convert `@androidx.annotation.Nullable` to just
+         * `@Nullable`, and `@androidx.annotation.IntRange(from=20)` to `IntRange(from=20)`.
          */
         fun shortenAnnotation(source: String): String {
             return when {
@@ -282,6 +365,9 @@
                 source.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX, 1) -> {
                     "@" + source.substring("@android.support.annotation.".length)
                 }
+                source.startsWith(ANDROIDX_ANNOTATION_PREFIX, 1) -> {
+                    "@" + source.substring("@androidx.annotation.".length)
+                }
                 else -> source
             }
         }
@@ -294,11 +380,11 @@
             return when {
             // These 3 annotations are in the android.annotation. package, not android.support.annotation
                 source.startsWith("@SystemService") ||
-                        source.startsWith("@TargetApi") ||
-                        source.startsWith("@SuppressLint") ->
+                    source.startsWith("@TargetApi") ||
+                    source.startsWith("@SuppressLint") ->
                     "@android.annotation." + source.substring(1)
                 else -> {
-                    "@android.support.annotation." + source.substring(1)
+                    "@androidx.annotation." + source.substring(1)
                 }
             }
         }
@@ -381,8 +467,9 @@
         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" })
+                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
@@ -456,7 +543,7 @@
 class DefaultAnnotationArrayAttributeValue(val value: String) : DefaultAnnotationValue(),
     AnnotationArrayAttributeValue {
     init {
-        assert(value.startsWith("{") && value.endsWith("}"), { value })
+        assert(value.startsWith("{") && value.endsWith("}")) { value }
     }
 
     override val values = value.substring(1, value.length - 1).split(",").map {
diff --git a/src/main/java/com/android/tools/metalava/model/ClassItem.kt b/src/main/java/com/android/tools/metalava/model/ClassItem.kt
index 328d5af..de95759 100644
--- a/src/main/java/com/android/tools/metalava/model/ClassItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/ClassItem.kt
@@ -83,7 +83,7 @@
         }
 
         return curr.containingPackage().qualifiedName().replace('.', '/') + "/" +
-                fullName().replace('.', '$')
+            fullName().replace('.', '$')
     }
 
     /** The super class of this class, if any  */
@@ -216,6 +216,12 @@
 
     var hasPrivateConstructor: Boolean
 
+    /**
+     * Maven artifact of this class, if any. (Not used for the Android SDK, but used in
+     * for example support libraries.
+     */
+    var artifact: String?
+
     override fun accept(visitor: ItemVisitor) {
         if (visitor is ApiVisitor) {
             accept(visitor)
@@ -381,6 +387,37 @@
         return null
     }
 
+    /** Finds a given method in this class matching the VM name signature */
+    fun findMethodByDesc(
+        name: String,
+        desc: String,
+        includeSuperClasses: Boolean = false,
+        includeInterfaces: Boolean = false
+    ): MethodItem? {
+        if (desc.startsWith("<init>")) {
+            constructors().asSequence()
+                .filter { it.internalDesc() == desc }
+                .forEach { return it }
+            return null
+        } else {
+            methods().asSequence()
+                .filter { it.name() == name && it.internalDesc() == desc }
+                .forEach { return it }
+        }
+
+        if (includeSuperClasses) {
+            superClass()?.findMethodByDesc(name, desc, true, includeInterfaces)?.let { return it }
+        }
+
+        if (includeInterfaces) {
+            for (itf in interfaceTypes()) {
+                val cls = itf.asClass() ?: continue
+                cls.findMethodByDesc(name, desc, includeSuperClasses, true)?.let { return it }
+            }
+        }
+        return null
+    }
+
     fun findConstructor(template: ConstructorItem): ConstructorItem? {
         constructors().asSequence()
             .filter { it.matches(template) }
@@ -447,7 +484,6 @@
         return true
     }
 
-
     /** Returns the corresponding compilation unit, if any */
     fun getCompilationUnit(): CompilationUnit? = null
 
@@ -497,8 +533,8 @@
         val methods = LinkedHashSet<MethodItem>()
         for (method in methods()) {
             if (predicate.test(method) || method.findPredicateSuperMethod(predicate) != null) {
-                //val duplicated = method.duplicate(this)
-                //methods.add(duplicated)
+                // val duplicated = method.duplicate(this)
+                // methods.add(duplicated)
                 methods.remove(method)
                 methods.add(method)
             }
@@ -616,6 +652,10 @@
     }
 
     fun allInnerClasses(includeSelf: Boolean = false): Sequence<ClassItem> {
+        if (!includeSelf && innerClasses().isEmpty()) {
+            return emptySequence()
+        }
+
         val list = ArrayList<ClassItem>()
         if (includeSelf) {
             list.add(this)
@@ -689,13 +729,14 @@
                 cls.filteredFields(filterEmit).asSequence()
             } else {
                 cls.fields().asSequence()
+                    .filter { filterEmit.test(it) }
             }
         if (cls.isEnum()) {
             fields = fieldSequence
-                .filter({ !it.isEnumConstant() })
+                .filter { !it.isEnumConstant() }
                 .sortedWith(FieldItem.comparator)
             enums = fieldSequence
-                .filter({ it.isEnumConstant() })
+                .filter { it.isEnumConstant() }
                 .filter { filterEmit.test(it) }
                 .sortedWith(FieldItem.comparator)
         } else {
@@ -744,8 +785,7 @@
             return
         }
 
-        val emitClass = emitClass()
-
+        val emitClass = if (visitor.includeEmptyOuterClasses) emit() else emitClass()
         if (emitClass) {
             if (!visitor.visitingPackage) {
                 visitor.visitingPackage = true
@@ -789,7 +829,7 @@
             }
         }
 
-        if (visitor.nestInnerClasses) {  // otherwise done below
+        if (visitor.nestInnerClasses) { // otherwise done below
             innerClasses.forEach { it.accept() }
         }
 
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 c18e047..41ce549 100644
--- a/src/main/java/com/android/tools/metalava/model/Codebase.kt
+++ b/src/main/java/com/android/tools/metalava/model/Codebase.kt
@@ -44,6 +44,9 @@
     /** Description of what this codebase is (useful during debugging) */
     var description: String
 
+    /** The API level of this codebase, or -1 if not known */
+    var apiLevel: Int
+
     /** The packages in the codebase (may include packages that are not included in the API) */
     fun getPackages(): PackageList
 
@@ -92,7 +95,8 @@
      * Creates an annotation item for the given (fully qualified) Java source
      */
     fun createAnnotation(
-        @Language("JAVA") source: String, context: Item? = null,
+        @Language("JAVA") source: String,
+        context: Item? = null,
         mapName: Boolean = true
     ): AnnotationItem = TextBackedAnnotationItem(
         this, source, mapName
@@ -153,11 +157,13 @@
     override var original: Codebase? = null
     override var supportsStagedNullability: Boolean = false
     override var units: List<PsiFile> = emptyList()
+    override var apiLevel: Int = -1
 
     override fun getPermissionLevel(name: String): String? {
         if (permissions == null) {
-            assert(manifest != null,
-                { "This method should only be called when a manifest has been configured on the codebase" })
+            assert(manifest != null) {
+                "This method should only be called when a manifest has been configured on the codebase"
+            }
             try {
                 val map = HashMap<String, String>(600)
                 val doc = XmlUtils.parseDocument(manifest?.readText(UTF_8), true)
diff --git a/src/main/java/com/android/tools/metalava/model/FieldItem.kt b/src/main/java/com/android/tools/metalava/model/FieldItem.kt
index b0773e8..f512833 100644
--- a/src/main/java/com/android/tools/metalava/model/FieldItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/FieldItem.kt
@@ -110,6 +110,25 @@
         return false
     }
 
+    override fun hasNullnessInfo(): Boolean {
+        if (!requiresNullnessInfo()) {
+            return true
+        }
+
+        return modifiers.hasNullnessInfo()
+    }
+
+    override fun requiresNullnessInfo(): Boolean {
+        if (type().primitive) {
+            return false
+        }
+
+        if (modifiers.isFinal() && initialValue(true) != null) {
+            return false
+        }
+
+        return true
+    }
 
     companion object {
         val comparator: java.util.Comparator<FieldItem> = Comparator { a, b -> a.name().compareTo(b.name()) }
@@ -126,7 +145,7 @@
     ) {
         val value =
             initialValue(!allowDefaultValue)
-                    ?: if (allowDefaultValue && !containingClass().isClass()) type().defaultValue() else null
+                ?: if (allowDefaultValue && !containingClass().isClass()) type().defaultValue() else null
         if (value != null) {
             when (value) {
                 is Int -> {
@@ -310,8 +329,8 @@
                     in 'a'..'f' -> (escaped.toInt() or (10 + (c - 'a'))).toChar()
                     in 'A'..'F' -> (escaped.toInt() or (10 + (c - 'A'))).toChar()
                     else -> throw IllegalArgumentException(
-                        "bad escape sequence: '" + c + "' at pos " + i + " in: \""
-                                + str + "\""
+                        "bad escape sequence: '" + c + "' at pos " + i + " in: \"" +
+                            str + "\""
                     )
                 }
                 if (state == CHAR4) {
@@ -324,7 +343,7 @@
         }
     }
     if (state != START) {
-        throw IllegalArgumentException("unfinished escape sequence: " + str)
+        throw IllegalArgumentException("unfinished escape sequence: $str")
     }
     return buf.toString()
 }
diff --git a/src/main/java/com/android/tools/metalava/model/Item.kt b/src/main/java/com/android/tools/metalava/model/Item.kt
index 028960f..e698476 100644
--- a/src/main/java/com/android/tools/metalava/model/Item.kt
+++ b/src/main/java/com/android/tools/metalava/model/Item.kt
@@ -121,15 +121,23 @@
 
     override fun hashCode(): Int
 
+    /** Whether this member was cloned in from a super class or interface */
+    fun isCloned(): Boolean
+
     /**
      * Returns true if this item requires nullness information (e.g. for a method
      * where either the return value or any of the parameters are non-primitives.
      * Note that it doesn't consider whether it already has nullness annotations;
      * for that see [hasNullnessInfo].
      */
-    fun requiresNullnessInfo(): Boolean {
-        return false
-    }
+    fun requiresNullnessInfo(): Boolean = false
+
+    /**
+     * Returns true if this item requires nullness information and supplies it
+     * (for all items, e.g. if a method is partially annotated this method would
+     * still return false)
+     */
+    fun hasNullnessInfo(): Boolean = false
 
     /**
      * Whether this item was loaded from the classpath (e.g. jar dependencies)
@@ -137,41 +145,12 @@
      */
     fun isFromClassPath(): Boolean = false
 
-
     /** Is this element declared in Java (rather than Kotlin) ? */
     fun isJava(): Boolean = true
 
     /** Is this element declared in Kotlin (rather than Java) ? */
     fun isKotlin() = !isJava()
 
-    /**
-     * Returns true if this item requires nullness information and supplies it
-     * (for all items, e.g. if a method is partially annotated this method would
-     * still return false)
-     */
-    fun hasNullnessInfo(): Boolean {
-        when (this) {
-            is ParameterItem -> {
-                return !type().primitive
-            }
-
-            is MethodItem -> {
-                val returnType = returnType()
-                if (returnType != null && !returnType.primitive) {
-                    return true
-                }
-                for (parameter in parameters()) {
-                    if (!parameter.type().primitive) {
-                        return true
-                    }
-                }
-                return false
-            }
-        }
-
-        return false
-    }
-
     fun hasShowAnnotation(): Boolean = modifiers.hasShowAnnotation()
     fun hasHideAnnotation(): Boolean = modifiers.hasHideAnnotations()
 
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 726f32e..03eb387 100644
--- a/src/main/java/com/android/tools/metalava/model/MethodItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/MethodItem.kt
@@ -37,6 +37,32 @@
     /** Returns the super methods that this method is overriding */
     fun superMethods(): List<MethodItem>
 
+    /**
+     * Like [internalName] but is the desc-portion of the internal signature,
+     * e.g. for the method "void create(int x, int y)" the internal name of
+     * the constructor is "create" and the desc is "(II)V"
+     */
+    fun internalDesc(voidConstructorTypes: Boolean = false): String {
+        val sb = StringBuilder()
+        sb.append("(")
+
+        // Non-static inner classes get an implicit constructor parameter for the
+        // outer type
+        if (isConstructor() && containingClass().containingClass() != null &&
+            !containingClass().modifiers.isStatic()
+        ) {
+            sb.append(containingClass().containingClass()?.toType()?.internalName() ?: "")
+        }
+
+        for (parameter in parameters()) {
+            sb.append(parameter.type().internalName())
+        }
+
+        sb.append(")")
+        sb.append(if (voidConstructorTypes && isConstructor()) "V" else returnType()?.internalName() ?: "V")
+        return sb.toString()
+    }
+
     fun allSuperMethods(): Sequence<MethodItem> {
         val original = superMethods().firstOrNull() ?: return emptySequence()
         return generateSequence(original) { item ->
@@ -72,6 +98,9 @@
     }
 
     fun filteredThrowsTypes(predicate: Predicate<Item>): Collection<ClassItem> {
+        if (throwsTypes().isEmpty()) {
+            return emptyList()
+        }
         return filteredThrowsTypes(predicate, LinkedHashSet())
     }
 
@@ -87,7 +116,7 @@
                 // Excluded, but it may have super class throwables that are included; if so, include those
                 var curr = cls.publicSuperClass()
                 while (curr != null) {
-                    if (predicate.test(cls)) {
+                    if (predicate.test(curr)) {
                         classes.add(curr)
                         break
                     }
@@ -106,7 +135,7 @@
      * may think the method required and not yet implemented, e.g. the class must be
      * abstract.)
      */
-    var inheritedInterfaceMethod: Boolean
+    var inheritedMethod: Boolean
 
     /**
      * Duplicates this field item. Used when we need to insert inherited fields from
@@ -284,7 +313,6 @@
                     if (pt1.toErasedTypeString() != pt2.toErasedTypeString()) {
                         return false
                     }
-
                 } else {
                     if (pt1 != pt2) {
                         return false
@@ -350,6 +378,10 @@
     }
 
     override fun hasNullnessInfo(): Boolean {
+        if (!requiresNullnessInfo()) {
+            return true
+        }
+
         if (!isConstructor() && returnType()?.primitive != true) {
             if (!modifiers.hasNullnessInfo()) {
                 return false
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 c05362b..435baf8 100644
--- a/src/main/java/com/android/tools/metalava/model/ModifierList.kt
+++ b/src/main/java/com/android/tools/metalava/model/ModifierList.kt
@@ -75,7 +75,7 @@
         if (isVolatile() != other.isVolatile()) return false
 
         // Default does not require an override to "remove" it
-        //if (isDefault() != other.isDefault()) return false
+        // if (isDefault() != other.isDefault()) return false
 
         return true
     }
@@ -183,7 +183,9 @@
             omitCommonPackages: Boolean = false,
             removeAbstract: Boolean = false,
             removeFinal: Boolean = false,
-            addPublic: Boolean = false
+            addPublic: Boolean = false,
+            onlyIncludeSignatureAnnotations: Boolean = true
+
         ) {
 
             val list = if (removeAbstract || removeFinal || addPublic) {
@@ -211,10 +213,15 @@
                     skipNullnessAnnotations = skipNullnessAnnotations,
                     omitCommonPackages = omitCommonPackages,
                     separateLines = false,
-                    writer = writer
+                    writer = writer,
+                    onlyIncludeSignatureAnnotations = onlyIncludeSignatureAnnotations
                 )
             }
 
+            if (compatibility.doubleSpaceForPackagePrivate && item.isPackagePrivate && item is MemberItem) {
+                writer.write(" ")
+            }
+
             // Kotlin order:
             //   https://kotlinlang.org/docs/reference/coding-conventions.html#modifiers
 
@@ -262,15 +269,15 @@
                     writer.write("operator ")
                 }
 
-                val isInterface = classItem?.isInterface() == true
-                        || (methodItem?.containingClass()?.isInterface() == true &&
+                val isInterface = classItem?.isInterface() == true ||
+                    (methodItem?.containingClass()?.isInterface() == true &&
                         !list.isDefault() && !list.isStatic())
 
-                if ((compatibility.abstractInInterfaces && isInterface
-                            || list.isAbstract() &&
-                            (classItem?.isEnum() != true &&
-                                    (compatibility.abstractInAnnotations || classItem?.isAnnotationType() != true)))
-                    && (!isInterface || compatibility.abstractInInterfaces)
+                if ((compatibility.abstractInInterfaces && isInterface ||
+                        list.isAbstract() &&
+                        (classItem?.isEnum() != true &&
+                            (compatibility.abstractInAnnotations || classItem?.isAnnotationType() != true))) &&
+                    (!isInterface || compatibility.abstractInInterfaces)
                 ) {
                     writer.write("abstract ")
                 }
@@ -310,15 +317,15 @@
                     list.isPrivate() -> writer.write("private ")
                 }
 
-                val isInterface = classItem?.isInterface() == true
-                        || (methodItem?.containingClass()?.isInterface() == true &&
+                val isInterface = classItem?.isInterface() == true ||
+                    (methodItem?.containingClass()?.isInterface() == true &&
                         !list.isDefault() && !list.isStatic())
 
-                if ((compatibility.abstractInInterfaces && isInterface
-                            || list.isAbstract() &&
-                            (classItem?.isEnum() != true &&
-                                    (compatibility.abstractInAnnotations || classItem?.isAnnotationType() != true)))
-                    && (!isInterface || compatibility.abstractInInterfaces)
+                if ((compatibility.abstractInInterfaces && isInterface ||
+                        list.isAbstract() &&
+                        (classItem?.isEnum() != true &&
+                            (compatibility.abstractInAnnotations || classItem?.isAnnotationType() != true))) &&
+                    (!isInterface || compatibility.abstractInInterfaces)
                 ) {
                     writer.write("abstract ")
                 }
@@ -378,18 +385,39 @@
             skipNullnessAnnotations: Boolean = false,
             omitCommonPackages: Boolean = false,
             separateLines: Boolean = false,
-            writer: Writer
+            filterDuplicates: Boolean = false,
+            writer: Writer,
+            onlyIncludeSignatureAnnotations: Boolean = true
         ) {
-            if (list.annotations().isNotEmpty()) {
-                for (annotation in list.annotations()) {
+            val annotations = list.annotations()
+            if (annotations.isNotEmpty()) {
+                var index = -1
+                for (annotation in annotations) {
+                    index++
                     if ((annotation.isNonNull() || annotation.isNullable())) {
                         if (skipNullnessAnnotations) {
                             continue
                         }
-                    } else if (!annotation.isSignificant()) {
+                    } else if (onlyIncludeSignatureAnnotations && !annotation.isSignificant()) {
                         continue
                     }
 
+                    // Optionally filter out duplicates
+                    if (index > 0 && filterDuplicates) {
+                        val qualifiedName = annotation.qualifiedName()
+                        var found = false
+                        for (i in 0 until index) {
+                            val prev = annotations[i]
+                            if (prev.qualifiedName() == qualifiedName) {
+                                found = true
+                                break
+                            }
+                        }
+                        if (found) {
+                            continue
+                        }
+                    }
+
                     val source = annotation.toSource()
                     if (omitCommonPackages) {
                         writer.write(AnnotationItem.shortenAnnotation(source))
@@ -406,4 +434,3 @@
         }
     }
 }
-
diff --git a/src/main/java/com/android/tools/metalava/model/PackageItem.kt b/src/main/java/com/android/tools/metalava/model/PackageItem.kt
index ed6e31c..ad4190a 100644
--- a/src/main/java/com/android/tools/metalava/model/PackageItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/PackageItem.kt
@@ -79,7 +79,6 @@
             return
         }
 
-
         if (visitor.skip(this)) {
             return
         }
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 fe2c400..5d1eaa8 100644
--- a/src/main/java/com/android/tools/metalava/model/TypeItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/TypeItem.kt
@@ -142,11 +142,20 @@
      */
     fun asTypeParameter(context: MemberItem? = null): TypeParameterItem?
 
+    /**
+     * Mark nullness annotations in the type as recent.
+     * TODO: This isn't very clean; we should model individual annotations.
+     */
+    fun markRecent()
+
     companion object {
         /** Shortens types, if configured */
         fun shortenTypes(type: String): String {
             if (options.omitCommonPackages) {
                 var cleaned = type
+                if (cleaned.contains("@androidx.annotation.")) {
+                    cleaned = cleaned.replace("@androidx.annotation.", "@")
+                }
                 if (cleaned.contains("@android.support.annotation.")) {
                     cleaned = cleaned.replace("@android.support.annotation.", "@")
                 }
@@ -209,9 +218,8 @@
             // <T extends java.lang.Object> is the same as <T>
             //  but NOT for <T extends Object & java.lang.Comparable> -- you can't
             //  shorten this to <T & java.lang.Comparable
-            //return type.replace(" extends java.lang.Object", "")
+            // return type.replace(" extends java.lang.Object", "")
             return signature.replace(" extends java.lang.Object>", ">")
-
         }
 
         val comparator: Comparator<TypeItem> = Comparator { type1, type2 ->
diff --git a/src/main/java/com/android/tools/metalava/model/psi/Javadoc.kt b/src/main/java/com/android/tools/metalava/model/psi/Javadoc.kt
index 784c80a..2a6d702 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/Javadoc.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/Javadoc.kt
@@ -72,7 +72,7 @@
     // we don't have to search for raw substrings like "@return" which
     // can incorrectly find matches in escaped code snippets etc.
     val factory = JavaPsiFacade.getElementFactory(psiElement.project)
-            ?: error("Invalid tool configuration; did not find JavaPsiFacade factory")
+        ?: error("Invalid tool configuration; did not find JavaPsiFacade factory")
     val docComment = factory.createDocCommentFromText(doc)
 
     if (tagSection == "@return") {
@@ -91,15 +91,13 @@
             // Add text to the existing @return tag
             val offset = if (append)
                 findTagEnd(returnTag)
-            else
-                returnTag.textRange.startOffset + returnTag.name.length + 1
+            else returnTag.textRange.startOffset + returnTag.name.length + 1
             return insertInto(doc, newText, offset)
         }
     } else if (tagSection != null) {
         val parameter = if (tagSection.startsWith("@"))
             docComment.findTagByName(tagSection.substring(1))
-        else
-            findParamTag(docComment, tagSection)
+        else findParamTag(docComment, tagSection)
         if (parameter == null) {
             // Add new parameter or tag
             // TODO: Decide whether to place it alphabetically or place it by parameter order
@@ -114,7 +112,7 @@
             val offset = when {
                 returnTag != null -> returnTag.textRange.startOffset
                 anchor != null -> findTagEnd(anchor)
-                else -> doc.length - 2  // "*/
+                else -> doc.length - 2 // "*/
             }
             val tagName = if (tagSection.startsWith("@")) tagSection else "@param $tagSection"
             return insertInto(doc, "$tagName $newText", offset)
@@ -122,8 +120,7 @@
             // Add to existing tag/parameter
             val offset = if (append)
                 findTagEnd(parameter)
-            else
-                parameter.textRange.startOffset + parameter.name.length + 1
+            else parameter.textRange.startOffset + parameter.name.length + 1
             return insertInto(doc, newText, offset)
         }
     } else {
@@ -132,7 +129,7 @@
         val startOffset =
             if (!append) {
                 4 // "/** ".length
-            } else firstTag?.textRange?.startOffset ?: doc.length-2
+            } else firstTag?.textRange?.startOffset ?: doc.length - 2
         return insertInto(doc, newText, startOffset)
     }
 }
@@ -171,13 +168,13 @@
     }
 
     return existingDoc.substring(0, index + 1) +
-            existingDoc.substring(index + 1).trimIndent().split('\n').joinToString(separator = "\n") {
-                if (!it.startsWith(" ")) {
-                    " ${it.trimEnd()}"
-                } else {
-                    it.trimEnd()
-                }
+        existingDoc.substring(index + 1).trimIndent().split('\n').joinToString(separator = "\n") {
+            if (!it.startsWith(" ")) {
+                " ${it.trimEnd()}"
+            } else {
+                it.trimEnd()
             }
+        }
 }
 
 fun insertInto(existingDoc: String, newText: String, initialOffset: Int): String {
@@ -190,7 +187,7 @@
     }
     val index = existingDoc.indexOf('\n')
     val prefixWithStar = index == -1 || existingDoc[index + 1] == '*' ||
-            existingDoc[index + 1] == ' ' && existingDoc[index + 2] == '*'
+        existingDoc[index + 1] == ' ' && existingDoc[index + 2] == '*'
 
     val prefix = existingDoc.substring(0, offset)
     val suffix = existingDoc.substring(offset)
@@ -200,7 +197,7 @@
 
     val middle = if (prefixWithStar) {
         startSeparator + newText.split('\n').joinToString(separator = "\n") { " * $it" } +
-                endSeparator
+            endSeparator
     } else {
         "$startSeparator$newText$endSeparator"
     }
@@ -208,7 +205,7 @@
     // Going from single-line to multi-line?
     return if (existingDoc.indexOf('\n') == -1 && existingDoc.startsWith("/** ")) {
         prefix.substring(0, 3) + "\n *" + prefix.substring(3) + middle +
-                if (suffix == "*/") " */" else suffix
+            if (suffix == "*/") " */" else suffix
     } else {
         prefix + middle + suffix
     }
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 b8ebb45..4d78346 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
@@ -55,7 +55,7 @@
 
         val attributes = psiAnnotation.parameterList.attributes
         if (attributes.isEmpty()) {
-            return "@" + qualifiedName
+            return "@$qualifiedName"
         }
 
         val sb = StringBuilder(30)
@@ -299,7 +299,8 @@
         // TODO: Inline this such that instead of constructing XmlBackedAnnotationItem
         // and then producing source and parsing it, produce source directly
         fun create(
-            codebase: Codebase, xmlAnnotation: XmlBackedAnnotationItem,
+            codebase: Codebase,
+            xmlAnnotation: XmlBackedAnnotationItem,
             context: Item? = null
         ): PsiAnnotationItem {
             if (codebase is PsiBasedCodebase) {
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt
index 94e9d16..b8b2504 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt
@@ -287,7 +287,7 @@
         val topLevelClasses = ArrayList<ClassItem>(CLASS_ESTIMATE)
 
         try {
-            ZipFile(jarFile).use({ jar ->
+            ZipFile(jarFile).use { jar ->
                 val enumeration = jar.entries()
                 while (enumeration.hasMoreElements()) {
                     val entry = enumeration.nextElement()
@@ -324,7 +324,7 @@
                         }
                     }
                 }
-            })
+            }
         } catch (e: IOException) {
             reporter.report(Errors.IO_ERROR, jarFile, e.message ?: e.toString())
         }
@@ -365,8 +365,8 @@
     fun dumpStats() {
         options.stdout.println(
             "INTERNAL STATS: Size of classMap=${classMap.size} and size of " +
-                    "methodMap=${methodMap.size} and size of packageMap=${packageMap.size}, and the " +
-                    "typemap size is ${typeMap.size}, and the packageClasses size is ${packageClasses.size} "
+                "methodMap=${methodMap.size} and size of packageMap=${packageMap.size}, and the " +
+                "typemap size is ${typeMap.size}, and the packageClasses size is ${packageClasses.size} "
         )
     }
 
@@ -451,9 +451,9 @@
             val pkgName = getPackageName(clz)
             val pkg = findPackage(pkgName)
             if (pkg == null) {
-                //val packageHtml: String? = packageDocs?.packageDocs!![pkgName]
+                // val packageHtml: String? = packageDocs?.packageDocs!![pkgName]
                 // dynamically discovered packages should NOT be included
-                //val packageHtml = "/** @hide */"
+                // val packageHtml = "/** @hide */"
                 val packageHtml = null
                 val psiPackage = JavaPsiFacade.getInstance(project).findPackage(pkgName)
                 if (psiPackage != null) {
@@ -522,7 +522,6 @@
                 inner!! // should be there now
                 return inner
             }
-
         }
 
         return existing ?: return createClass(psiClass)
@@ -633,6 +632,9 @@
     fun createPsiMethod(s: String, parent: PsiElement? = null): PsiMethod =
         getFactory().createMethodFromText(s, parent)
 
+    fun createConstructor(s: String, parent: PsiElement? = null): PsiMethod =
+        getFactory().createConstructor(s, parent)
+
     fun createPsiType(s: String, parent: PsiElement? = null): PsiType =
         getFactory().createTypeFromText(s, parent)
 
@@ -644,7 +646,8 @@
     private fun getFactory() = JavaPsiFacade.getElementFactory(project)
 
     override fun createAnnotation(
-        @Language("JAVA") source: String, context: Item?,
+        @Language("JAVA") source: String,
+        context: Item?,
         mapName: Boolean
     ): PsiAnnotationItem {
         val psiAnnotation = createPsiAnnotation(source, context?.psi())
@@ -737,7 +740,7 @@
                                 reporter.report(
                                     Errors.HIDDEN_SUPERCLASS, originalClass.psiClass,
                                     "$cls has a super class " +
-                                            "that is excluded via filters: $superClassName"
+                                        "that is excluded via filters: $superClassName"
                                 )
                                 null
                             }
@@ -807,8 +810,8 @@
                             } else {
                                 reporter.report(
                                     Errors.HIDDEN_SUPERCLASS, psiClass, "$method has a super method " +
-                                            "in a class that is excluded via filters: " +
-                                            "${superConstructor.containingClass().qualifiedName()} "
+                                        "in a class that is excluded via filters: " +
+                                        "${superConstructor.containingClass().qualifiedName()} "
                                 )
                             }
                         } else {
@@ -817,8 +820,8 @@
                             if (newSuperConstructor == null) {
                                 reporter.report(
                                     Errors.HIDDEN_SUPERCLASS, psiClass, "$method has a super method " +
-                                            "in a class that is not matched via filters: " +
-                                            "${superConstructor.containingClass().qualifiedName()} "
+                                        "in a class that is not matched via filters: " +
+                                        "${superConstructor.containingClass().qualifiedName()} "
                                 )
                             } else {
                                 val constructorItem = newSuperConstructor as PsiConstructorItem
@@ -849,8 +852,8 @@
                                 } else {
                                     reporter.report(
                                         Errors.HIDDEN_SUPERCLASS, psiClass, "$method has a super method " +
-                                                "in a class that is excluded via filters: " +
-                                                "${superMethod.containingClass().qualifiedName()} "
+                                            "in a class that is excluded via filters: " +
+                                            "${superMethod.containingClass().qualifiedName()} "
                                     )
                                 }
                             } else {
@@ -859,8 +862,8 @@
                                 if (newSuperMethod == null) {
                                     reporter.report(
                                         Errors.HIDDEN_SUPERCLASS, psiClass, "$method has a super method " +
-                                                "in a class that is not matched via filters: " +
-                                                "${superMethod.containingClass().qualifiedName()} "
+                                            "in a class that is not matched via filters: " +
+                                            "${superMethod.containingClass().qualifiedName()} "
                                     )
                                 } else {
                                     list.add(newSuperMethod)
@@ -889,7 +892,7 @@
                                 } else {
                                     reporter.report(
                                         Errors.HIDDEN_SUPERCLASS, psiClass, "$newCls has a throws class " +
-                                                "that is excluded via filters: ${it.qualifiedName()}"
+                                            "that is excluded via filters: ${it.qualifiedName()}"
                                     )
                                 }
                             } else {
@@ -949,7 +952,7 @@
     init {
         constructors = cls.constructors().asSequence().filter { filterEmit.test(it) }
         methods = cls.methods().asSequence().filter { filterEmit.test(it) }
-        //fields = cls.fields().asSequence().filter { filterEmit.test(it) }
+        // fields = cls.fields().asSequence().filter { filterEmit.test(it) }
 
         fields = cls.filteredFields(filterEmit).asSequence()
         innerClasses = cls.innerClasses()
@@ -987,8 +990,8 @@
 
 class LockedPsiBasedCodebase(description: String = "Unknown") : PsiBasedCodebase(description) {
     // Not yet locked
-    //override fun findClass(psiClass: PsiClass): PsiClassItem {
+    // override fun findClass(psiClass: PsiClass): PsiClassItem {
     //    val qualifiedName: String = psiClass.qualifiedName ?: psiClass.name!!
     //    return classMap[qualifiedName] ?: error("Attempted to register ${psiClass.name} in locked codebase")
-    //}
+    // }
 }
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiClassItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiClassItem.kt
index c5dc287..b1cfb48 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiClassItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiClassItem.kt
@@ -75,6 +75,7 @@
     }
 
     override var defaultConstructor: ConstructorItem? = null
+    override var artifact: String? = null
 
     private var containingClass: PsiClassItem? = null
     override fun containingClass(): PsiClassItem? = containingClass
@@ -165,7 +166,7 @@
         if (psiClass.hasTypeParameters()) {
             return PsiTypeParameterList(
                 codebase, psiClass.typeParameterList
-                        ?: return TypeParameterList.NONE
+                    ?: return TypeParameterList.NONE
             )
         } else {
             return TypeParameterList.NONE
@@ -315,7 +316,7 @@
             val stub = method.toStub(replacementMap)
             val psiMethod = codebase.createPsiMethod(stub, psiClass)
             newMethod = PsiMethodItem.create(codebase, this, psiMethod)
-            newMethod.inheritedInterfaceMethod = method.inheritedInterfaceMethod
+            newMethod.inheritedMethod = method.inheritedMethod
             newMethod.documentation = method.documentation
         }
 
@@ -409,8 +410,11 @@
 
             if (classType == ClassType.INTERFACE) {
                 // All members are implicitly public, fields are implicitly static, non-static methods are abstract
+                // (except in Java 1.9, where they can be private
                 for (method in methods) {
-                    method.mutableModifiers().setPublic(true)
+                    if (!method.isPrivate) {
+                        method.mutableModifiers().setPublic(true)
+                    }
                 }
                 for (method in fields) {
                     val m = method.mutableModifiers()
@@ -467,14 +471,12 @@
                 PsiMethodItem.create(codebase, newClass, it as PsiMethodItem)
             }.toMutableList()
 
-
             newClass.fields = classFilter.fields.asSequence()
                 // Preserve sorting order for enums
                 .sortedBy { it.sortingRank }.map {
                     PsiFieldItem.create(codebase, newClass, it as PsiFieldItem)
                 }.toMutableList()
 
-
             newClass.innerClasses = classFilter.innerClasses.map {
                 val newInnerClass = codebase.findClass(it.cls.qualifiedName) ?: it.create(codebase)
                 newInnerClass.containingClass = newClass
@@ -511,6 +513,9 @@
                     psiClass, result,
                     "public static final ${psiClass.qualifiedName}[] values() { return null; }"
                 )
+                // Also add a private constructor; used when emitting the private API
+                val psiMethod = codebase.createConstructor("private ${psiClass.name}", psiClass)
+                result.add(PsiConstructorItem.create(codebase, classItem, psiMethod))
             }
         }
 
@@ -518,7 +523,8 @@
             codebase: PsiBasedCodebase,
             classItem: PsiClassItem,
             psiClass: PsiClass,
-            result: MutableList<PsiMethodItem>, source: String
+            result: MutableList<PsiMethodItem>,
+            source: String
         ) {
             val psiMethod = codebase.createPsiMethod(source, psiClass)
             result.add(PsiMethodItem.create(codebase, classItem, psiMethod))
@@ -542,7 +548,6 @@
                         curr.containingClass
                     } else {
                         break
-
                     }
                 }
                 return list.asReversed().asSequence().joinToString(separator = ".") { it }
@@ -684,5 +689,5 @@
 fun PsiModifierListOwner.isPackagePrivate(): Boolean {
     val modifiers = modifierList ?: return false
     return !(modifiers.hasModifierProperty(PsiModifier.PUBLIC) ||
-            modifiers.hasModifierProperty(PsiModifier.PROTECTED))
+        modifiers.hasModifierProperty(PsiModifier.PROTECTED))
 }
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiCompilationUnit.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiCompilationUnit.kt
index f70d21c..843d3a0 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiCompilationUnit.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiCompilationUnit.kt
@@ -84,9 +84,7 @@
             for (psiClass in file.classes) {
                 val classItem = codebase.findClass(psiClass) ?: continue
                 if (predicate.test(classItem)) {
-
                 }
-
             }
         } else if (file is KtFile) {
             for (importDirective in file.importDirectives) {
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiConstructorItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiConstructorItem.kt
index 4ee2455..cc14c10 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiConstructorItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiConstructorItem.kt
@@ -60,6 +60,7 @@
     override fun isImplicitConstructor(): Boolean = implicitConstructor
     override fun isConstructor(): Boolean = true
     override var superConstructor: ConstructorItem? = null
+    override fun isCloned(): Boolean = false
 
     private var _superMethods: List<MethodItem>? = null
     override fun superMethods(): List<MethodItem> {
@@ -133,7 +134,8 @@
 
     companion object {
         fun create(
-            codebase: PsiBasedCodebase, containingClass: PsiClassItem,
+            codebase: PsiBasedCodebase,
+            containingClass: PsiClassItem,
             psiMethod: PsiMethod
         ): PsiConstructorItem {
             assert(psiMethod.isConstructor)
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiFieldItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiFieldItem.kt
index 1a65079..f04647a 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiFieldItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiFieldItem.kt
@@ -19,9 +19,11 @@
 import com.android.tools.metalava.model.ClassItem
 import com.android.tools.metalava.model.FieldItem
 import com.android.tools.metalava.model.TypeItem
+import com.intellij.psi.PsiClass
 import com.intellij.psi.PsiEnumConstant
 import com.intellij.psi.PsiField
 import com.intellij.psi.impl.JavaConstantExpressionEvaluator
+import org.jetbrains.uast.UClass
 
 class PsiFieldItem(
     override val codebase: PsiBasedCodebase,
@@ -63,6 +65,18 @@
     override fun name(): String = name
     override fun containingClass(): ClassItem = containingClass
 
+    override fun isCloned(): Boolean {
+        val psiClass = run {
+            val p = containingClass().psi() as? PsiClass ?: return false
+            if (p is UClass) {
+                p.sourcePsi as? PsiClass ?: return false
+            } else {
+                p
+            }
+        }
+        return psiField.containingClass != psiClass
+    }
+
     override fun duplicate(targetContainingClass: ClassItem): PsiFieldItem {
         val duplicated = create(codebase, targetContainingClass as PsiClassItem, psiField)
 
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiItem.kt
index d8621a7..591bcd7 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiItem.kt
@@ -49,20 +49,22 @@
     @Suppress("LeakingThis")
     override var removed = documentation.contains("@removed")
     @Suppress("LeakingThis")
-    override var hidden = (documentation.contains("@hide") || documentation.contains("@pending")
-            || modifiers.hasHideAnnotations()) && !modifiers.hasShowAnnotation()
+    override var hidden = (documentation.contains("@hide") || documentation.contains("@pending") ||
+        modifiers.hasHideAnnotations()) && !modifiers.hasShowAnnotation()
 
     override fun psi(): PsiElement? = element
 
     // TODO: Consider only doing this in tests!
     override fun isFromClassPath(): Boolean {
         return if (element is UElement) {
-            element.psi is PsiCompiledElement
+            (element.sourcePsi ?: element.javaPsi) is PsiCompiledElement
         } else {
             element is PsiCompiledElement
         }
     }
 
+    override fun isCloned(): Boolean = false
+
     /** Get a mutable version of modifiers for this item */
     override fun mutableModifiers(): MutableModifierList = modifiers
 
@@ -137,8 +139,8 @@
         }
 
         if (!(documentation.contains("@link") || // includes @linkplain
-                    documentation.contains("@see") ||
-                    documentation.contains("@throws"))
+                documentation.contains("@see") ||
+                documentation.contains("@throws"))
         ) {
             // No relevant tags that need to be expanded/rewritten
             return documentation
@@ -317,7 +319,6 @@
                     if (first is KDoc) {
                         return first.text
                     }
-
                 }
             }
 
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 c84ad8f..a54dc24 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
@@ -23,12 +23,14 @@
 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.PsiClass
 import com.intellij.psi.PsiMethod
 import com.intellij.psi.util.PsiTypesUtil
 import com.intellij.psi.util.TypeConversionUtil
 import org.intellij.lang.annotations.Language
 import org.jetbrains.kotlin.psi.KtNamedFunction
 import org.jetbrains.kotlin.psi.KtProperty
+import org.jetbrains.uast.UClass
 import org.jetbrains.uast.UElement
 import org.jetbrains.uast.UMethod
 import org.jetbrains.uast.UThrowExpression
@@ -70,7 +72,7 @@
      */
     internal var source: PsiMethodItem? = null
 
-    override var inheritedInterfaceMethod: Boolean = false
+    override var inheritedMethod: Boolean = false
 
     override fun name(): String = name
     override fun containingClass(): PsiClassItem = containingClass
@@ -118,7 +120,7 @@
         if (psiMethod.hasTypeParameters()) {
             return PsiTypeParameterList(
                 codebase, psiMethod.typeParameterList
-                        ?: return TypeParameterList.NONE
+                    ?: return TypeParameterList.NONE
             )
         } else {
             return TypeParameterList.NONE
@@ -138,11 +140,23 @@
 
     override fun throwsTypes(): List<ClassItem> = throwsTypes
 
+    override fun isCloned(): Boolean {
+        val psiClass = run {
+            val p = containingClass().psi() as? PsiClass ?: return false
+            if (p is UClass) {
+                p.sourcePsi as? PsiClass ?: return false
+            } else {
+                p
+            }
+        }
+        return psiMethod.containingClass != psiClass
+    }
+
     override fun isExtensionMethod(): Boolean {
         if (isKotlin()) {
             val ktParameters =
                 ((psiMethod as? KotlinUMethod)?.sourcePsi as? KtNamedFunction)?.valueParameters
-                        ?: return false
+                    ?: return false
             return ktParameters.size < parameters.size
         }
 
@@ -235,7 +249,8 @@
         val modifierString = StringWriter()
         ModifierList.write(
             modifierString, method.modifiers, method, removeAbstract = false,
-            removeFinal = false, addPublic = true
+            removeFinal = false, addPublic = true,
+            onlyIncludeSignatureAnnotations = true
         )
         sb.append(modifierString.toString())
 
@@ -341,7 +356,7 @@
             )
             method.modifiers.setOwner(method)
             method.source = original
-            method.inheritedInterfaceMethod = original.inheritedInterfaceMethod
+            method.inheritedMethod = original.inheritedMethod
 
             return method
         }
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiModifierItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiModifierItem.kt
index d52a677..324625e 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiModifierItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiModifierItem.kt
@@ -207,11 +207,11 @@
     }
 
     override fun isPackagePrivate(): Boolean {
-        return flags and (PUBLIC or PROTECTED or PRIVATE) == 0
+        return flags and (PUBLIC or PROTECTED or PRIVATE or INTERNAL) == 0
     }
 
     fun getAccessFlags(): Int {
-        return flags and (PUBLIC or PROTECTED or PRIVATE)
+        return flags and (PUBLIC or PROTECTED or PRIVATE or INTERNAL)
     }
 
     // Rename? It's not a full equality, it's whether an override's modifier set is significant
@@ -222,8 +222,8 @@
 
             // Skipping the "default" flag
             // TODO: Compatibility: skipNativeModifier and skipStrictFpModifier modifier flags!
-            //if (!compatibility.skipNativeModifier && isNative() != other.isNative()) return false
-            //if (!compatibility.skipStrictFpModifier && isStrictFp() != other.isStrictFp()) return false
+            // if (!compatibility.skipNativeModifier && isNative() != other.isNative()) return false
+            // if (!compatibility.skipStrictFpModifier && isStrictFp() != other.isStrictFp()) return false
             return flags and mask == flags2 and mask
         }
         return false
@@ -255,8 +255,8 @@
          * to consider whether an override of a method is different from its super implementation
          */
         private const val EQUIVALENCE_MASK = PUBLIC or PROTECTED or PRIVATE or STATIC or ABSTRACT or
-                FINAL or TRANSIENT or VOLATILE or SYNCHRONIZED or DEPRECATED or VARARG or
-                SEALED or INTERNAL or INFIX or OPERATOR
+            FINAL or TRANSIENT or VOLATILE or SYNCHRONIZED or DEPRECATED or VARARG or
+            SEALED or INTERNAL or INFIX or OPERATOR
 
         fun create(codebase: PsiBasedCodebase, element: PsiModifierListOwner, documentation: String?): PsiModifierItem {
             val modifiers = create(
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiParameterItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiParameterItem.kt
index a6a4be3..a15e083 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiParameterItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiParameterItem.kt
@@ -72,7 +72,7 @@
     private fun getKtParameter(): KtParameter? {
         val ktParameters =
             ((containingMethod.psiMethod as? KotlinUMethod)?.sourcePsi as? KtNamedFunction)?.valueParameters
-                    ?: return null
+                ?: return null
 
         // Perform matching based on parameter names, because indices won't work in the
         // presence of @JvmOverloads where UAST generates multiple permutations of the
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 9a986e1..248d047 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
@@ -16,7 +16,7 @@
 
 package com.android.tools.metalava.model.psi
 
-import com.android.tools.lint.detector.api.LintUtils
+import com.android.tools.lint.detector.api.getInternalName
 import com.android.tools.metalava.compatibility
 import com.android.tools.metalava.doclava1.ApiPredicate
 import com.android.tools.metalava.model.AnnotationItem
@@ -265,6 +265,11 @@
 
     override fun hasTypeArguments(): Boolean = psiType is PsiClassType && psiType.hasParameters()
 
+    override fun markRecent() {
+        toAnnotatedString = toTypeString(false, true, false).replace(".NonNull", ".RecentlyNonNull")
+        toInnerAnnotatedString = toTypeString(true, true, false).replace(".NonNull", ".RecentlyNonNull")
+    }
+
     companion object {
         private fun getPrimitiveSignature(typeName: String): String? = when (typeName) {
             "boolean" -> "Z"
@@ -310,7 +315,7 @@
             signature: StringBuilder,
             outerClass: PsiClass
         ): Boolean {
-            val className = LintUtils.getInternalName(outerClass) ?: return false
+            val className = getInternalName(outerClass) ?: return false
             signature.append('L').append(className).append(';')
             return true
         }
@@ -341,7 +346,6 @@
                     return TextTypeItem.eraseAnnotations(typeString, false, true)
                 }
                 return typeString
-
             } else {
                 return type.canonicalText
             }
@@ -434,9 +438,9 @@
                             ci--
                         }
                         return typeString.substring(0, ci) +
-                                annotation + " " +
-                                typeString.substring(ci, index + 1) +
-                                typeString.substring(end + 1)
+                            annotation + " " +
+                            typeString.substring(ci, index + 1) +
+                            typeString.substring(end + 1)
                     } else {
                         return typeString.substring(0, index + 1) + typeString.substring(end + 1)
                     }
diff --git a/src/main/java/com/android/tools/metalava/model/text/TextBackedAnnotationItem.kt b/src/main/java/com/android/tools/metalava/model/text/TextBackedAnnotationItem.kt
index 4a8b138..4911c56 100644
--- a/src/main/java/com/android/tools/metalava/model/text/TextBackedAnnotationItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/text/TextBackedAnnotationItem.kt
@@ -34,13 +34,12 @@
         val index = source.indexOf("(")
         val annotationClass = if (index == -1)
             source.substring(1) // Strip @
-        else
-            source.substring(1, index)
+        else source.substring(1, index)
 
         qualifiedName = if (mapName) AnnotationItem.mapName(codebase, annotationClass) else annotationClass
         full = when {
             qualifiedName == null -> ""
-            index == -1 -> "@" + qualifiedName
+            index == -1 -> "@$qualifiedName"
             else -> "@" + qualifiedName + source.substring(index)
         }
 
diff --git a/src/main/java/com/android/tools/metalava/model/text/TextClassItem.kt b/src/main/java/com/android/tools/metalava/model/text/TextClassItem.kt
index 27a30c9..7fbfe59 100644
--- a/src/main/java/com/android/tools/metalava/model/text/TextClassItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/text/TextClassItem.kt
@@ -64,6 +64,8 @@
 
     override val isTypeParameter: Boolean = false
 
+    override var artifact: String? = null
+
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (other !is ClassItem) return false
@@ -119,8 +121,7 @@
         if (typeParameterList().toString().isNotEmpty())
 // TODO: No, handle List<String>[], though this is highly unlikely in a class
             qualifiedName() + "<" + typeParameterList() + ">"
-        else
-            qualifiedName()
+        else qualifiedName()
     )
 
     override fun hasTypeVariables(): Boolean {
@@ -227,7 +228,8 @@
             }
 
         private fun addStubPackage(
-            name: String, codebase: TextCodebase,
+            name: String,
+            codebase: TextCodebase,
             textClassItem: TextClassItem
         ) {
             val endIndex = name.lastIndexOf('.')
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 fe0114f..4262188 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
@@ -48,5 +48,3 @@
 
     override fun isConstructor(): Boolean = true
 }
-
-
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 732c6c4..50acde8 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
@@ -30,7 +30,8 @@
     isProtected: Boolean,
     isPrivate: Boolean,
     isInternal: Boolean,
-    isFinal: Boolean, isStatic: Boolean,
+    isFinal: Boolean,
+    isStatic: Boolean,
     isTransient: Boolean,
     isVolatile: Boolean,
     private val type: TextTypeItem,
diff --git a/src/main/java/com/android/tools/metalava/model/text/TextItem.kt b/src/main/java/com/android/tools/metalava/model/text/TextItem.kt
index 0acb645..72968bd 100644
--- a/src/main/java/com/android/tools/metalava/model/text/TextItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/text/TextItem.kt
@@ -43,6 +43,8 @@
     override val deprecated
         get() = mutableDeprecated
 
+    override fun isCloned(): Boolean = false
+
     fun setDeprecated(deprecated: Boolean) {
         mutableDeprecated = deprecated
     }
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 8fb461e..d187adc 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
@@ -183,12 +183,10 @@
 
     override fun isExtensionMethod(): Boolean = codebase.unsupported()
 
-    override var inheritedInterfaceMethod: Boolean = false
+    override var inheritedMethod: Boolean = false
 
     override fun toString(): String =
         "${if (isConstructor()) "Constructor" else "Method"} ${containingClass().qualifiedName()}.${name()}(${parameters().joinToString {
             it.type().toSimpleType()
         }})"
 }
-
-
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 9ac8ceb..a627199 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
@@ -144,8 +144,8 @@
 
     override fun owner(): Item = owner!! // Must be set after construction
     override fun isEmpty(): Boolean {
-        return !(public || protected || private || static || abstract || final || native || synchronized
-                || strictfp || transient || volatile || default)
+        return !(public || protected || private || static || abstract || final || native || synchronized ||
+            strictfp || transient || volatile || default)
     }
 
     override fun annotations(): List<AnnotationItem> {
diff --git a/src/main/java/com/android/tools/metalava/model/text/TextTypeItem.kt b/src/main/java/com/android/tools/metalava/model/text/TextTypeItem.kt
index c4e9e8c..306be6f 100644
--- a/src/main/java/com/android/tools/metalava/model/text/TextTypeItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/text/TextTypeItem.kt
@@ -40,7 +40,7 @@
         innerAnnotations: Boolean,
         erased: Boolean
     ): String {
-        return Companion.toTypeString(type, outerAnnotations, innerAnnotations, erased)
+        return toTypeString(type, outerAnnotations, innerAnnotations, erased)
     }
 
     override fun asClass(): ClassItem? {
@@ -129,7 +129,6 @@
             }
 
             typeParameter
-
         } else {
             null
         }
@@ -144,6 +143,8 @@
         return TextTypeItem(codebase, convertTypeString(replacementMap))
     }
 
+    override fun markRecent() = codebase.unsupported()
+
     companion object {
         // heuristic to guess if a given type parameter is a type variable
         fun isLikelyTypeParameter(typeString: String): Boolean {
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 3ee9389..56d8375 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
@@ -52,8 +52,15 @@
     /** The filter to use to determine if we should emit an item */
     val filterEmit: Predicate<Item>,
     /** The filter to use to determine if we should emit a reference to an item */
-    val filterReference: Predicate<Item>
+    val filterReference: Predicate<Item>,
 
+    /**
+     * Whether the visitor should include visiting top-level classes that have
+     * nothing other than non-empty inner classes within.
+     * Typically these are not included in signature files, but when generating
+     * stubs we need to include them.
+     */
+    val includeEmptyOuterClasses: Boolean = false
 ) : ItemVisitor(visitConstructorsAsMethods, nestInnerClasses) {
     constructor(
         codebase: Codebase,
@@ -71,6 +78,7 @@
         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 */
@@ -89,11 +97,9 @@
         ApiPredicate(codebase, ignoreShown = true, ignoreRemoved = remove)
     )
 
-
     // The API visitor lazily visits packages only when there's a match within at least one class;
     // this property keeps track of whether we've already visited the current package
     var visitingPackage = false
 
     open fun include(cls: ClassItem): Boolean = cls.emit
 }
-
diff --git a/src/main/resources/version.properties b/src/main/resources/version.properties
index be11ad6..dd2d971 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.6
+metalavaVersion=0.9.12
diff --git a/src/test/java/com/android/tools/metalava/AnnotationStatisticsTest.kt b/src/test/java/com/android/tools/metalava/AnnotationStatisticsTest.kt
index dc749c3..f62c805 100644
--- a/src/test/java/com/android/tools/metalava/AnnotationStatisticsTest.kt
+++ b/src/test/java/com/android/tools/metalava/AnnotationStatisticsTest.kt
@@ -22,14 +22,46 @@
 
 class AnnotationStatisticsTest : DriverTest() {
     @Test
-
     fun `Test emitting annotation statistics`() {
         check(
             extraArguments = arrayOf("--annotation-coverage-stats"),
             expectedOutput = """
                 Nullness Annotation Coverage Statistics:
-                4 out of 6 methods were annotated (66%)
-                0 out of 0 fields were annotated (0%)
+                0 out of 0 methods were annotated (100%)
+                0 out of 1 fields were annotated (0%)
+                0 out of 0 parameters were annotated (100%)
+                """,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+
+                    @SuppressWarnings("ALL")
+                    public class Foo {
+                        public final static String foo1 = "constant";
+                        public final static String foo2 = System.getProperty("not.constant");
+                        public void test() {
+                            String foo1 = foo1();
+                            String foo2 = foo2();
+                            test();
+
+                        }
+                    }
+                    """
+                )
+            ),
+            compatibilityMode = false
+        )
+    }
+
+    @Test
+    fun `Static final initialized fields are not nullable`() {
+        check(
+            extraArguments = arrayOf("--annotation-coverage-stats"),
+            expectedOutput = """
+                Nullness Annotation Coverage Statistics:
+                4 out of 5 methods were annotated (80%)
+                0 out of 0 fields were annotated (100%)
                 4 out of 5 parameters were annotated (80%)
                 """,
             compatibilityMode = false,
@@ -38,10 +70,10 @@
                   public class MyTest {
                     ctor public MyTest();
                     method public java.lang.Double convert0(java.lang.Float);
-                    method @android.support.annotation.Nullable public java.lang.Double convert1(@android.support.annotation.NonNull java.lang.Float);
-                    method @android.support.annotation.Nullable public java.lang.Double convert2(@android.support.annotation.NonNull java.lang.Float);
-                    method @android.support.annotation.Nullable public java.lang.Double convert3(@android.support.annotation.NonNull java.lang.Float);
-                    method @android.support.annotation.Nullable public java.lang.Double convert4(@android.support.annotation.NonNull java.lang.Float);
+                    method @androidx.annotation.Nullable public java.lang.Double convert1(@androidx.annotation.NonNull java.lang.Float);
+                    method @androidx.annotation.Nullable public java.lang.Double convert2(@androidx.annotation.NonNull java.lang.Float);
+                    method @androidx.annotation.Nullable public java.lang.Double convert3(@androidx.annotation.NonNull java.lang.Float);
+                    method @androidx.annotation.Nullable public java.lang.Double convert4(@androidx.annotation.NonNull java.lang.Float);
                   }
                 }
                 """
@@ -78,18 +110,18 @@
                     "libs/api-usage.jar",
                     base64gzip(
                         "test/pkg/ApiUsage.class", "" +
-                                "H4sIAAAAAAAAAH1Ta28SQRQ9Q4Fd1qW0VPD9KNZKWe0WaH3VmBiTRpKNfqiW" +
-                                "+HGgIw4uu4RdTPzqPzJRSDTxB/ijjHcGWqqlZjNn5945c86du7O/fn//CaCO" +
-                                "xxZyuG7ghoUEbmYIVjNYREmFt0ysqfdtBesK7igoK9hQUDHgGLjLYPQ+7Unh" +
-                                "HzLkvS7/yF2fBx335bDXEoNdhvQTGcj4KcNCeeOAIfk8PBQMOU8GYsJ5zVu+" +
-                                "UJvDNvcP+ECqeJpMxu9lxLDixSKK3f6HjvusL99EvCNIOTVUEwaL9+X+cPCO" +
-                                "tyko/EWdpols7YfDQVvsSSWbPVLZVAXbyGOFTOZsVEv3bGxi2caSgjxcMn4h" +
-                                "fD+0sYWqjRrqNraxY+M+Hth4qHKPUGVYPlUzw9KsQa9aXdGOGYpl79/kbkN1" +
-                                "KtuTUSSDjm4u6RXmEBXP4kEQxjwWirQ+j3Q6xWBO1c8SbswotbOKPMGpK5nG" +
-                                "f522Z9MdrNI9y9ElZDSosYQJGvQdKHOeZl2k9NpWZQxW+YHEW2aOsfAVyW9I" +
-                                "6XCMdN4YwWweRWyETPOLVioQFkkBSNKTIcUUSkjDhUF5wJ5o4wIu6houHft+" +
-                                "Jr6qpHZs6TkTG0frO8wcwWo6hOd0ym7q9ewJ5xJM7WEhSydbJBf6y+iUaxRV" +
-                                "6IxVcivqCrXTtAoLZVzGFaqD4arWuvYH9nECI6kDAAA="
+                            "H4sIAAAAAAAAAH1Ta28SQRQ9Q4Fd1qW0VPD9KNZKWe0WaH3VmBiTRpKNfqiW" +
+                            "+HGgIw4uu4RdTPzqPzJRSDTxB/ijjHcGWqqlZjNn5945c86du7O/fn//CaCO" +
+                            "xxZyuG7ghoUEbmYIVjNYREmFt0ysqfdtBesK7igoK9hQUDHgGLjLYPQ+7Unh" +
+                            "HzLkvS7/yF2fBx335bDXEoNdhvQTGcj4KcNCeeOAIfk8PBQMOU8GYsJ5zVu+" +
+                            "UJvDNvcP+ECqeJpMxu9lxLDixSKK3f6HjvusL99EvCNIOTVUEwaL9+X+cPCO" +
+                            "tyko/EWdpols7YfDQVvsSSWbPVLZVAXbyGOFTOZsVEv3bGxi2caSgjxcMn4h" +
+                            "fD+0sYWqjRrqNraxY+M+Hth4qHKPUGVYPlUzw9KsQa9aXdGOGYpl79/kbkN1" +
+                            "KtuTUSSDjm4u6RXmEBXP4kEQxjwWirQ+j3Q6xWBO1c8SbswotbOKPMGpK5nG" +
+                            "f522Z9MdrNI9y9ElZDSosYQJGvQdKHOeZl2k9NpWZQxW+YHEW2aOsfAVyW9I" +
+                            "6XCMdN4YwWweRWyETPOLVioQFkkBSNKTIcUUSkjDhUF5wJ5o4wIu6houHft+" +
+                            "Jr6qpHZs6TkTG0frO8wcwWo6hOd0ym7q9ewJ5xJM7WEhSydbJBf6y+iUaxRV" +
+                            "6IxVcivqCrXTtAoLZVzGFaqD4arWuvYH9nECI6kDAAA="
                     )
                 )
             ),
@@ -98,8 +130,8 @@
                     """
                     package test.pkg;
 
-                    import android.support.annotation.NonNull;
-                    import android.support.annotation.Nullable;
+                    import androidx.annotation.NonNull;
+                    import androidx.annotation.Nullable;
 
                     public class ApiSurface {
                         ApiSurface(Object param) {
@@ -135,8 +167,11 @@
                 supportNullableSource
             ),
             expectedOutput = """
-                6 methods and fields were missing nullness annotations out of 7 total API references.
-                API nullness coverage is 14%
+                6 methods and fields were missing nullness annotations out of 8 total API references.
+                API nullness coverage is 25%
+
+
+                Top referenced un-annotated classes:
 
                 | Qualified Class Name                                         |      Usage Count |
                 |--------------------------------------------------------------|-----------------:|
diff --git a/src/test/java/com/android/tools/metalava/AnnotationsDifferTest.kt b/src/test/java/com/android/tools/metalava/AnnotationsDifferTest.kt
new file mode 100644
index 0000000..0d367d1
--- /dev/null
+++ b/src/test/java/com/android/tools/metalava/AnnotationsDifferTest.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.metalava.doclava1.ApiFile
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+
+class AnnotationsDifferTest {
+    @get:Rule
+    var temporaryFolder = TemporaryFolder()
+
+    @Test
+    fun `Write diff`() {
+        val codebase = ApiFile.parseApi("old.txt", """
+                package test.pkg {
+                  public interface Appendable {
+                    method public test.pkg.Appendable append(java.lang.CharSequence?);
+                    method public test.pkg.Appendable append2(java.lang.CharSequence?);
+                    method public java.lang.String! reverse(java.lang.String!);
+                  }
+                  public interface RandomClass {
+                    method public test.pkg.Appendable append(java.lang.CharSequence);
+                  }
+                }
+        """.trimIndent(), true, true)
+
+        val codebase2 = ApiFile.parseApi("new.txt", """
+        package test.pkg {
+          public interface Appendable {
+            method @androidx.annotation.NonNull public test.pkg.Appendable append(@androidx.annotation.Nullable java.lang.CharSequence);
+            method public test.pkg.Appendable append2(java.lang.CharSequence);
+          }
+        }
+        """.trimIndent(), false, false)
+
+        val apiFile = temporaryFolder.newFile("diff.txt")
+        AnnotationsDiffer(codebase, codebase2).writeDiffSignature(apiFile)
+        assertTrue(apiFile.exists())
+        val actual = apiFile.readText(Charsets.UTF_8)
+        assertEquals("""
+            package test.pkg {
+              public abstract interface Appendable {
+                method public abstract test.pkg.Appendable append2(java.lang.CharSequence);
+              }
+            }
+        """.trimIndent(), actual.trim())
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/metalava/AnnotationsMergerTest.kt b/src/test/java/com/android/tools/metalava/AnnotationsMergerTest.kt
index 129f41e..654ed1a 100644
--- a/src/test/java/com/android/tools/metalava/AnnotationsMergerTest.kt
+++ b/src/test/java/com/android/tools/metalava/AnnotationsMergerTest.kt
@@ -36,10 +36,10 @@
                     """
                     package test.pkg;
 
-                    import android.support.annotation.NonNull;
-                    import android.support.annotation.Nullable;
+                    import androidx.annotation.NonNull;
+                    import androidx.annotation.Nullable;
                     import android.annotation.IntRange;
-                    import android.support.annotation.UiThread;
+                    import androidx.annotation.UiThread;
 
                     @UiThread
                     public class MyTest {
@@ -56,15 +56,16 @@
             // Skip the annotations themselves from the output
             extraArguments = arrayOf(
                 "--hide-package", "android.annotation",
+                "--hide-package", "androidx.annotation",
                 "--hide-package", "android.support.annotation"
             ),
             api = """
                 package test.pkg {
-                  @android.support.annotation.UiThread public class MyTest {
+                  @androidx.annotation.UiThread public class MyTest {
                     ctor public MyTest();
-                    method @android.support.annotation.IntRange(from=10, to=20) public int clamp(int);
-                    method @android.support.annotation.Nullable public java.lang.Double convert(@android.support.annotation.NonNull java.lang.Float);
-                    field @android.support.annotation.Nullable public java.lang.Number myNumber;
+                    method @androidx.annotation.IntRange(from=10, to=20) public int clamp(int);
+                    method @androidx.annotation.Nullable public java.lang.Double convert(@androidx.annotation.NonNull java.lang.Float);
+                    field @androidx.annotation.Nullable public java.lang.Number myNumber;
                   }
                 }
                 """
@@ -90,7 +91,7 @@
             compatibilityMode = false,
             outputKotlinStyleNulls = false,
             omitCommonPackages = false,
-            mergeAnnotations = """<?xml version="1.0" encoding="UTF-8"?>
+            mergeXmlAnnotations = """<?xml version="1.0" encoding="UTF-8"?>
                 <root>
                   <item name="test.pkg.MyTest">
                     <annotation name="android.support.annotation.UiThread" />
@@ -110,15 +111,101 @@
                       <val name="to" val="20" />
                     </annotation>
                   </item>
+                  <item name="test.pkg.MyTest int clamp(int) 0">
+                    <annotation name='org.jetbrains.annotations.Range'>
+                      <val name="from" val="-1"/>
+                      <val name="to" val="java.lang.Integer.MAX_VALUE"/>
+                    </annotation>
+                  </item>
                   </root>
                 """,
             api = """
                 package test.pkg {
-                  @android.support.annotation.UiThread public class MyTest {
+                  @androidx.annotation.UiThread public class MyTest {
                     ctor public MyTest();
-                    method @android.support.annotation.IntRange(from=10, to=20) public int clamp(int);
-                    method @android.support.annotation.Nullable public java.lang.Double convert(@android.support.annotation.NonNull java.lang.Float);
-                    field @android.support.annotation.Nullable public java.lang.Number myNumber;
+                    method @androidx.annotation.IntRange(from=10, to=20) public int clamp(@androidx.annotation.IntRange(from=-1L, to=java.lang.Integer.MAX_VALUE) int);
+                    method @androidx.annotation.Nullable public java.lang.Double convert(@androidx.annotation.NonNull java.lang.Float);
+                    field @androidx.annotation.Nullable public java.lang.Number myNumber;
+                  }
+                }
+                """
+        )
+    }
+
+    @Test
+    fun `Merge jaif files`() {
+        check(
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+
+                    public interface Appendable {
+                        Appendable append(CharSequence csq) throws IOException;
+                        String reverse(String s);
+                    }
+                    """
+                )
+            ),
+            compatibilityMode = false,
+            outputKotlinStyleNulls = false,
+            omitCommonPackages = false,
+            mergeJaifAnnotations = """
+                //
+                // Copyright (C) 2017 The Android Open Source Project
+                //
+                package test.pkg:
+                class Appendable:
+                    method append(Ljava/lang/CharSequence;)Ltest/pkg/Appendable;:
+                        parameter #0:
+                          type: @libcore.util.Nullable
+                        // 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);
+                  }
+                }
+                """
+        )
+    }
+
+    @Test
+    fun `Merge signature files`() {
+        check(
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+
+                    public interface Appendable {
+                        Appendable append(CharSequence csq) throws IOException;
+                    }
+                    """
+                )
+            ),
+            compatibilityMode = false,
+            outputKotlinStyleNulls = false,
+            omitCommonPackages = false,
+            mergeSignatureAnnotations = """
+                package test.pkg {
+                  public interface Appendable {
+                    method public test.pkg.Appendable append(java.lang.CharSequence?);
+                    method public test.pkg.Appendable append2(java.lang.CharSequence?);
+                    method public java.lang.String! reverse(java.lang.String!);
+                  }
+                  public interface RandomClass {
+                    method public test.pkg.Appendable append(java.lang.CharSequence);
+                  }
+                }
+                """,
+            api = """
+                package test.pkg {
+                  public interface Appendable {
+                    method @androidx.annotation.NonNull public test.pkg.Appendable append(@androidx.annotation.Nullable java.lang.CharSequence);
                   }
                 }
                 """
diff --git a/src/test/java/com/android/tools/metalava/ApiFileTest.kt b/src/test/java/com/android/tools/metalava/ApiFileTest.kt
index 330a1e2..abd3c1d 100644
--- a/src/test/java/com/android/tools/metalava/ApiFileTest.kt
+++ b/src/test/java/com/android/tools/metalava/ApiFileTest.kt
@@ -18,8 +18,6 @@
 
 package com.android.tools.metalava
 
-import com.android.tools.lint.checks.infrastructure.TestFiles.kotlin
-import org.junit.Ignore
 import org.junit.Test
 
 class ApiFileTest : DriverTest() {
@@ -90,7 +88,7 @@
                 java(
                     """
                     package test.pkg;
-                    import android.support.annotation.ParameterName;
+                    import androidx.annotation.ParameterName;
 
                     public class Foo {
                         public void foo(int javaParameter1, @ParameterName("publicParameterName") int javaParameter2) {
@@ -108,7 +106,7 @@
                       }
                     }
                  """,
-            extraArguments = arrayOf("--hide-package", "android.support.annotation"),
+            extraArguments = arrayOf("--hide-package", "androidx.annotation"),
             checkDoclava1 = false /* doesn't support parameter names */
         )
     }
@@ -122,7 +120,7 @@
                 java(
                     """
                     package test.pkg;
-                    import android.support.annotation.DefaultValue;
+                    import androidx.annotation.DefaultValue;
 
                     public class Foo {
                         public void foo(
@@ -143,7 +141,7 @@
                   }
                 }
                  """,
-            extraArguments = arrayOf("--hide-package", "android.support.annotation"),
+            extraArguments = arrayOf("--hide-package", "androidx.annotation"),
             checkDoclava1 = false /* doesn't support default Values */
         )
     }
@@ -172,7 +170,7 @@
                   }
                 }
                 """,
-            extraArguments = arrayOf("--hide-package", "android.support.annotation"),
+            extraArguments = arrayOf("--hide-package", "androidx.annotation"),
             checkDoclava1 = false /* doesn't support default Values */
         )
     }
@@ -248,7 +246,7 @@
                   public static final class Kotlin.Companion {
                     ctor private Kotlin.Companion();
                   }
-                   internal static final class Kotlin.myHiddenClass extends kotlin.Unit {
+                  internal static final class Kotlin.myHiddenClass extends kotlin.Unit {
                     ctor public Kotlin.myHiddenClass();
                     method internal test.pkg.Kotlin.myHiddenClass copy();
                   }
@@ -258,7 +256,6 @@
         )
     }
 
-    @Ignore("Still broken: UAST is missing reified methods, and some missing symbol resolution")
     @Test
     fun `Kotlin Reified Methods`() {
         check(
@@ -292,7 +289,7 @@
                   }
                   public final class _java_Kt {
                     ctor public _java_Kt();
-                    method public static final error.NonExistentClass systemService2(test.pkg.Context);
+                    method public static java.lang.String systemService2(test.pkg.Context);
                   }
                 }
                 """,
@@ -342,8 +339,8 @@
                     """
                     // Platform nullability Pair in Java
                     package androidx.util;
-                    import android.support.annotation.NonNull;
-                    import android.support.annotation.Nullable;
+                    import androidx.annotation.NonNull;
+                    import androidx.annotation.Nullable;
 
                     @SuppressWarnings("WeakerAccess")
                     public class NullableJavaPair<F, S> {
@@ -362,7 +359,7 @@
                     // Platform nullability Pair in Java
                     package androidx.util;
 
-                    import android.support.annotation.NonNull;
+                    import androidx.annotation.NonNull;
 
                     @SuppressWarnings("WeakerAccess")
                     public class NonNullableJavaPair<F, S> {
@@ -420,7 +417,7 @@
                   }
                 }
                 """,
-            extraArguments = arrayOf("--hide-package", "android.support.annotation"),
+            extraArguments = arrayOf("--hide-package", "androidx.annotation"),
             checkDoclava1 = false /* doesn't support Kotlin... */
         )
     }
@@ -472,7 +469,7 @@
                   }
                 }
                 """,
-            extraArguments = arrayOf("--hide-package", "android.support.annotation"),
+            extraArguments = arrayOf("--hide-package", "androidx.annotation"),
             checkDoclava1 = false /* doesn't support default Values */
         )
     }
@@ -1535,7 +1532,7 @@
         check(
             checkDoclava1 = false, // doclava1 does not include method2, which it should
             compatibilityMode = true,
-            extraArguments = arrayOf("--include-public-methods-from-hidden-super-classes=true"),
+            extraArguments = arrayOf("--skip-inherited-methods=false"),
             sourceFiles =
             *arrayOf(
                 java(
@@ -1891,7 +1888,16 @@
                     field public int removed;
                   }
                 }
-                """
+                """,
+            removedDexApi = "" +
+                "Ltest/pkg/Bar;-><init>()V\n" +
+                "Ltest/pkg/Bar;->removedMethod()V\n" +
+                "Ltest/pkg/Bar;->removedField:I\n" +
+                "Ltest/pkg/Bar\$Inner;\n" +
+                "Ltest/pkg/Bar\$Inner;-><init>()V\n" +
+                "Ltest/pkg/Bar\$Inner2\$Inner3\$Inner4;\n" +
+                "Ltest/pkg/Bar\$Inner2\$Inner3\$Inner4;-><init>()V\n" +
+                "Ltest/pkg/Bar\$Inner5\$Inner6\$Inner7;->removed:I"
         )
     }
 
@@ -2021,7 +2027,15 @@
                         ctor public Parent();
                       }
                     }
-                    """
+                    """,
+            dexApi = """
+                Ltest/pkg/Child;
+                Ltest/pkg/Child;-><init>()V
+                Ltest/pkg/Child;->toString()Ljava/lang/String;
+                Ltest/pkg/Parent;
+                Ltest/pkg/Parent;-><init>()V
+                Ltest/pkg/Parent;->toString()Ljava/lang/String;
+            """
         )
     }
 
@@ -2036,8 +2050,9 @@
                     """
                     @file:JvmName("-Foo")
 
-                    package test.pkg;
+                    package test.pkg
 
+                    @Suppress("unused")
                     inline fun String.printHelloWorld() { println("Hello World") }
                     """
                 )
@@ -2163,7 +2178,7 @@
                 java(
                     """
                         package test.pkg;
-                        public class Class1 {
+                        public class Class1 implements MyInterface {
                             Class1(int arg) { }
                             /** @hide */
                             public void method1() { }
@@ -2205,23 +2220,34 @@
                             public void method5() { }
                         }
                     """
+                ),
+
+                java(
+                    """
+                        package test.pkg;
+                        /** @hide */
+                        @SuppressWarnings("UnnecessaryInterfaceModifier")
+                        public interface MyInterface {
+                            public static final String MY_CONSTANT = "5";
+                        }
+                    """
                 )
             ),
             privateApi = """
                 package test.pkg {
-                  public class Class1 {
-                    ctor Class1(int);
+                  public class Class1 implements test.pkg.MyInterface {
+                    ctor  Class1(int);
                     method public void method1();
-                    method void method2();
+                    method  void method2();
                     method private void method3();
-                    method void myVarargsMethod(int, java.lang.String...);
-                    field int field3;
-                    field float[][] field4;
-                    field long[] field5;
+                    method  void myVarargsMethod(int, java.lang.String...);
+                    field  int field3;
+                    field  float[][] field4;
+                    field  long[] field5;
                     field private int field6;
                   }
                    class Class2 {
-                    ctor Class2();
+                    ctor  Class2();
                     method public void method4();
                   }
                   private class Class2.Class3 {
@@ -2229,9 +2255,12 @@
                     method public void method5();
                   }
                    class Class4 {
-                    ctor Class4();
+                    ctor  Class4();
                     method public void method5();
                   }
+                  public abstract interface MyInterface {
+                    field public static final java.lang.String MY_CONSTANT = "5";
+                  }
                 }
                 """,
             privateDexApi = """
@@ -2253,6 +2282,112 @@
                 Ltest/pkg/Class4;
                 Ltest/pkg/Class4;-><init>()V
                 Ltest/pkg/Class4;->method5()V
+                Ltest/pkg/MyInterface;
+                Ltest/pkg/MyInterface;->MY_CONSTANT:Ljava/lang/String;
+                """
+        )
+    }
+
+    @Test
+    fun `Private API signature corner cases`() {
+        // Some corner case scenarios exposed by differences in output from doclava and metalava
+        check(
+            checkDoclava1 = false,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                        package test.pkg;
+                        import android.os.Parcel;
+                        import android.os.Parcelable;
+                        import java.util.concurrent.FutureTask;
+
+                        public class Class1 extends PrivateParent implements MyInterface {
+                            Class1(int arg) { }
+
+                            @Override public String toString() {
+                                return "Class1";
+                            }
+
+                            private abstract class AmsTask extends FutureTask<String> {
+                                @Override
+                                protected void set(String bundle) {
+                                    super.set(bundle);
+                                }
+                            }
+
+                            /** @hide */
+                            public abstract static class TouchPoint implements Parcelable {
+                            }
+                        }
+                    """
+                ),
+
+                java(
+                    """
+                        package test.pkg;
+                        class PrivateParent {
+                            final String getValue() {
+                                return "";
+                            }
+                        }
+                    """
+                ),
+
+                java(
+                    """
+                        package test.pkg;
+                        /** @hide */
+                        public enum MyEnum {
+                            FOO, BAR
+                        }
+                    """
+                ),
+
+                java(
+                    """
+                        package test.pkg;
+                        @SuppressWarnings("UnnecessaryInterfaceModifier")
+                        public interface MyInterface {
+                            public static final String MY_CONSTANT = "5";
+                        }
+                    """
+                )
+            ),
+            privateApi = """
+                package test.pkg {
+                  public class Class1 extends test.pkg.PrivateParent implements test.pkg.MyInterface {
+                    ctor  Class1(int);
+                  }
+                  private abstract class Class1.AmsTask extends java.util.concurrent.FutureTask {
+                  }
+                  public static abstract class Class1.TouchPoint implements android.os.Parcelable {
+                    ctor public Class1.TouchPoint();
+                  }
+                  public final class MyEnum extends java.lang.Enum {
+                    ctor private MyEnum();
+                    enum_constant public static final test.pkg.MyEnum BAR;
+                    enum_constant public static final test.pkg.MyEnum FOO;
+                  }
+                   class PrivateParent {
+                    ctor  PrivateParent();
+                    method  final java.lang.String getValue();
+                  }
+                }
+                """,
+            privateDexApi = """
+                Ltest/pkg/Class1;-><init>(I)V
+                Ltest/pkg/Class1${"$"}AmsTask;
+                Ltest/pkg/Class1${"$"}TouchPoint;
+                Ltest/pkg/Class1${"$"}TouchPoint;-><init>()V
+                Ltest/pkg/MyEnum;
+                Ltest/pkg/MyEnum;-><init>()V
+                Ltest/pkg/MyEnum;->valueOf(Ljava/lang/String;)Ltest/pkg/MyEnum;
+                Ltest/pkg/MyEnum;->values()[Ltest/pkg/MyEnum;
+                Ltest/pkg/MyEnum;->BAR:Ltest/pkg/MyEnum;
+                Ltest/pkg/MyEnum;->FOO:Ltest/pkg/MyEnum;
+                Ltest/pkg/PrivateParent;
+                Ltest/pkg/PrivateParent;-><init>()V
+                Ltest/pkg/PrivateParent;->getValue()Ljava/lang/String;
                 """
         )
     }
diff --git a/src/test/java/com/android/tools/metalava/ApiFromTextTest.kt b/src/test/java/com/android/tools/metalava/ApiFromTextTest.kt
index fe63f8b..7e9dcbd 100644
--- a/src/test/java/com/android/tools/metalava/ApiFromTextTest.kt
+++ b/src/test/java/com/android/tools/metalava/ApiFromTextTest.kt
@@ -44,7 +44,6 @@
 
     @Test
     fun `Infer fully qualified names from shorter names`() {
-
         check(
             compatibilityMode = true,
             extraArguments = arrayOf("--annotations-in-signatures"),
@@ -62,7 +61,7 @@
                   public class MyTest {
                     ctor public MyTest();
                     method public int clamp(int);
-                    method public double convert(@android.support.annotation.Nullable java.lang.Float, byte[], java.lang.Iterable<java.io.File>);
+                    method public double convert(@androidx.annotation.Nullable java.lang.Float, byte[], java.lang.Iterable<java.io.File>);
                   }
                 }
                 """
@@ -224,9 +223,9 @@
         @Language("TEXT")
         val source = """
                 package test.pkg {
-                  @android.support.annotation.UiThread public class MyTest {
+                  @androidx.annotation.UiThread public class MyTest {
                     ctor public MyTest();
-                    method @android.support.annotation.IntRange(from=10, to=20) public int clamp(int);
+                    method @androidx.annotation.IntRange(from=10, to=20) public int clamp(int);
                     method public java.lang.Double? convert(java.lang.Float myPublicName);
                     field public java.lang.Number? myNumber;
                   }
@@ -355,5 +354,4 @@
             api = source
         )
     }
-
 }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/metalava/ArtifactTaggerTest.kt b/src/test/java/com/android/tools/metalava/ArtifactTaggerTest.kt
new file mode 100644
index 0000000..940447c
--- /dev/null
+++ b/src/test/java/com/android/tools/metalava/ArtifactTaggerTest.kt
@@ -0,0 +1,112 @@
+/*
+ * 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 org.junit.Test
+
+class ArtifactTaggerTest : DriverTest() {
+
+    @Test
+    fun `Tag API`() {
+        check(
+            checkDoclava1 = false,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg.foo;
+                    /** My Foo class documentation. */
+                    public class Foo { // registered in both the foo and bar libraries: should get duplicate warnings
+                        public class Inner {
+                        }
+                    }
+                    """
+                ),
+                java(
+                    """
+                    package test.pkg.bar;
+                    /** My Bar class documentation. */
+                    public class Bar {
+                        public class Inner {
+                        }
+                    }
+                    """
+                ),
+                java(
+                    """
+                    package test.pkg.baz;
+                    /** Extra class not registered in artifact files: should be flagged */
+                    public class Missing {
+                    }
+                    """
+                )
+            ),
+            artifacts = mapOf(
+                "my.library.group:foo:1.0.0" to """
+                    package test.pkg.foo {
+                      public class Foo {
+                        ctor public Foo();
+                      }
+                      public class Foo.Inner {
+                        ctor public Foo.Inner();
+                      }
+                    }
+                """,
+                "my.library.group:bar:3.1.4" to """
+                    package test.pkg.bar {
+                      public class Bar {
+                        ctor public Bar();
+                      }
+                      public class Bar.Inner {
+                        ctor public Bar.Inner();
+                      }
+                    }
+                    package test.pkg.foo {
+                      public class Foo { // duplicate registration: should generate warning
+                      }
+                    }
+                """
+            ),
+            extraArguments = arrayOf("--error", "NoArtifactData,BrokenArtifactFile"),
+            warnings = """
+                src/test/pkg/foo/Foo.java:2: error: Class test.pkg.foo.Foo belongs to multiple artifacts: my.library.group:foo:1.0.0 and my.library.group:bar:3.1.4 [BrokenArtifactFile:130]
+                src/test/pkg/foo/Foo.java:4: error: Class test.pkg.foo.Foo.Inner belongs to multiple artifacts: my.library.group:foo:1.0.0 and my.library.group:bar:3.1.4 [BrokenArtifactFile:130]
+                src/test/pkg/baz/Missing.java:2: error: No registered artifact signature file referenced class test.pkg.baz.Missing [NoArtifactData:129]
+            """,
+            stubs = arrayOf(
+                """
+                package test.pkg.foo;
+                /**
+                 * My Foo class documentation.
+                 * @artifactId my.library.group:foo:1.0.0
+                 */
+                @SuppressWarnings({"unchecked", "deprecation", "all"})
+                public class Foo {
+                public Foo() { throw new RuntimeException("Stub!"); }
+                /**
+                 * @artifactId my.library.group:foo:1.0.0
+                 */
+                @SuppressWarnings({"unchecked", "deprecation", "all"})
+                public class Inner {
+                public Inner() { throw new RuntimeException("Stub!"); }
+                }
+                }
+                """
+            )
+
+        )
+    }
+}
diff --git a/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt b/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt
index ecbb319..3b06bb9 100644
--- a/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt
+++ b/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.tools.metalava
 
+import org.junit.Ignore
 import org.junit.Test
 import java.io.File
 
@@ -243,7 +244,7 @@
                     """
                     @Suppress("all")
                     package test.pkg;
-                    import android.support.annotation.ParameterName;
+                    import androidx.annotation.ParameterName;
 
                     public class JavaClass {
                         public String method1(String newName) { return null; }
@@ -253,7 +254,7 @@
                 ),
                 supportParameterName
             ),
-            extraArguments = arrayOf("--hide-package", "android.support.annotation")
+            extraArguments = arrayOf("--hide-package", "androidx.annotation")
         )
     }
 
@@ -1297,12 +1298,13 @@
                 package androidx.content {
                   public final class ContentValuesKt {
                     ctor public ContentValuesKt();
-                    method public static error.NonExistentClass contentValuesOf(kotlin.Pair<String,?>... pairs);
+                    method public static android.content.ContentValues contentValuesOf(kotlin.Pair<String,?>... pairs);
                   }
                 }
                 """,
             sourceFiles = *arrayOf(
-                kotlin("src/androidx/content/ContentValues.kt",
+                kotlin(
+                    "src/androidx/content/ContentValues.kt",
                     """
                     package androidx.content
 
@@ -1334,6 +1336,7 @@
         )
     }
 
+    @Ignore("Not currently working: we're getting the wrong PSI results; I suspect caching across the two codebases")
     @Test
     fun `Test All Android API levels`() {
         // Checks API across Android SDK versions and makes sure the results are
@@ -1450,8 +1453,8 @@
                     "--omit-locations",
                     "--hide",
                     suppressLevels[apiLevel]
-                            ?: "AddedPackage,AddedClass,AddedMethod,AddedInterface,AddedField,ChangedDeprecated,RemovedField,RemovedClass,RemovedDeprecatedClass"
-                            +(if ((apiLevel == 19 || apiLevel == 20) && loadPrevAsSignature) ",ChangedType" else "")
+                        ?: "AddedPackage,AddedClass,AddedMethod,AddedInterface,AddedField,ChangedDeprecated,RemovedField,RemovedClass,RemovedDeprecatedClass" +
+                        (if ((apiLevel == 19 || apiLevel == 20) && loadPrevAsSignature) ",ChangedType" else "")
 
                 ),
                 warnings = expected[apiLevel]?.trimIndent() ?: "",
@@ -1464,14 +1467,13 @@
                 // Check signature file checks. We have .txt files for API level 14 and up, but there are a
                 // BUNCH of problems in older signature files that make the comparisons not work --
                 // missing type variables in class declarations, missing generics in method signatures, etc.
-                val signatureFile = File("../../prebuilts/sdk/api/${apiLevel - 1}.txt")
+                val signatureFile = File("../../prebuilts/sdk/${apiLevel - 1}/public/api/android.txt")
                 if (!(signatureFile.isFile)) {
                     println("Couldn't find $signatureFile: Check that pwd for test is correct. Skipping this test.")
                     return
                 }
                 val previousSignatureApi = signatureFile.readText(Charsets.UTF_8)
 
-
                 check(
                     checkDoclava1 = false,
                     checkCompatibility = true,
@@ -1479,7 +1481,7 @@
                         "--omit-locations",
                         "--hide",
                         suppressLevels[apiLevel]
-                                ?: "AddedPackage,AddedClass,AddedMethod,AddedInterface,AddedField,ChangedDeprecated,RemovedField,RemovedClass,RemovedDeprecatedClass"
+                            ?: "AddedPackage,AddedClass,AddedMethod,AddedInterface,AddedField,ChangedDeprecated,RemovedField,RemovedClass,RemovedDeprecatedClass"
                     ),
                     warnings = expected[apiLevel]?.trimIndent() ?: "",
                     previousApi = previousSignatureApi,
@@ -1489,8 +1491,7 @@
         }
     }
 
-
     // TODO: Check method signatures changing incompatibly (look especially out for adding new overloaded
     // methods and comparator getting confused!)
     //   ..equals on the method items should actually be very useful!
-}
\ 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 4f6572f..f8ad6ec 100644
--- a/src/test/java/com/android/tools/metalava/DocAnalyzerTest.kt
+++ b/src/test/java/com/android/tools/metalava/DocAnalyzerTest.kt
@@ -35,7 +35,7 @@
                 nonNullSource,
                 nullableSource
             ),
-            checkCompilation = false, // needs android.support annotations in classpath
+            checkCompilation = false, // needs androidx.annotations in classpath
             checkDoclava1 = false,
             stubs = arrayOf(
                 """
@@ -49,19 +49,19 @@
                  * @param factor2 This value must never be {@code null}.
                  * @return This value may be {@code null}.
                  */
-                @android.support.annotation.Nullable public java.lang.Double method1(@android.support.annotation.NonNull java.lang.Double factor1, @android.support.annotation.NonNull java.lang.Double factor2) { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.Nullable public java.lang.Double method1(@androidx.annotation.NonNull java.lang.Double factor1, @androidx.annotation.NonNull java.lang.Double factor2) { throw new RuntimeException("Stub!"); }
                 /**
                  * These are the docs for method2. It can sometimes return null.
                  * @param factor1 This value must never be {@code null}.
                  * @param factor2 This value must never be {@code null}.
                  */
-                @android.support.annotation.Nullable public java.lang.Double method2(@android.support.annotation.NonNull java.lang.Double factor1, @android.support.annotation.NonNull java.lang.Double factor2) { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.Nullable public java.lang.Double method2(@androidx.annotation.NonNull java.lang.Double factor1, @androidx.annotation.NonNull java.lang.Double factor2) { throw new RuntimeException("Stub!"); }
                 /**
                  * @param factor1 This value must never be {@code null}.
                  * @param factor2 This value must never be {@code null}.
                  * @return This value may be {@code null}.
                  */
-                @android.support.annotation.Nullable public java.lang.Double method3(@android.support.annotation.NonNull java.lang.Double factor1, @android.support.annotation.NonNull java.lang.Double factor2) { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.Nullable public java.lang.Double method3(@androidx.annotation.NonNull java.lang.Double factor1, @androidx.annotation.NonNull java.lang.Double factor2) { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -124,7 +124,7 @@
             ),
             checkCompilation = true,
             checkDoclava1 = false,
-            warnings = "src/test/pkg/Foo.java:2: lint: Replaced Andriod with Android in documentation for class test.pkg.Foo [Typo:131]",
+            warnings = "src/test/pkg/Foo.java:2: warning: Replaced Andriod with Android in documentation for class test.pkg.Foo [Typo:131]",
             stubs = arrayOf(
                 """
                 package test.pkg;
@@ -165,6 +165,10 @@
                         @RequiresPermission(allOf = {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCOUNT_MANAGER})
                         public void test4() {
                         }
+
+                        @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) // b/73559440
+                        public void test5() {
+                        }
                     }
                     """
                 ),
@@ -177,13 +181,14 @@
                             public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
                             public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
                             public static final String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
+                            public static final String WATCH_APPOPS = "android.permission.WATCH_APPOPS";
                         }
                     }
                     """
                 ),
                 requiresPermissionSource
             ),
-            checkCompilation = false, // needs android.support annotations in classpath
+            checkCompilation = false, // needs androidx.annotations in classpath
             checkDoclava1 = false,
             stubs = arrayOf(
                 """
@@ -195,19 +200,20 @@
                 /**
                  * Requires {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
                  */
-                @android.support.annotation.RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void test1() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void test1() { throw new RuntimeException("Stub!"); }
                 /**
                  * Requires {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
                  */
-                @android.support.annotation.RequiresPermission(allOf=android.Manifest.permission.ACCESS_COARSE_LOCATION) public void test2() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.RequiresPermission(allOf=android.Manifest.permission.ACCESS_COARSE_LOCATION) public void test2() { throw new RuntimeException("Stub!"); }
                 /**
                  * Requires {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
                  */
-                @android.support.annotation.RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void test3() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void test3() { throw new RuntimeException("Stub!"); }
                 /**
                  * Requires {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} and {@link android.Manifest.permission#ACCOUNT_MANAGER}
                  */
-                @android.support.annotation.RequiresPermission(allOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCOUNT_MANAGER}) public void test4() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.RequiresPermission(allOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCOUNT_MANAGER}) public void test4() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true) public void test5() { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -251,15 +257,15 @@
                  * @param range2 Value is 20 or greater
                  * @return Value is 10 or greater
                  */
-                @android.support.annotation.IntRange(from=10) public int test1(@android.support.annotation.IntRange(from=20) int range2) { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.IntRange(from=10) public int test1(@androidx.annotation.IntRange(from=20) int range2) { throw new RuntimeException("Stub!"); }
                 /**
                  * @return Value is between 10 and 20 inclusive
                  */
-                @android.support.annotation.IntRange(from=10, to=20) public int test2() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.IntRange(from=10, to=20) public int test2() { throw new RuntimeException("Stub!"); }
                 /**
                  * @return Value is 100 or less
                  */
-                @android.support.annotation.IntRange(to=100) public int test3() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.IntRange(to=100) public int test3() { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -273,8 +279,8 @@
                 java(
                     """
                     package test.pkg;
-                    import android.support.annotation.UiThread;
-                    import android.support.annotation.WorkerThread;
+                    import androidx.annotation.UiThread;
+                    import androidx.annotation.WorkerThread;
                     @UiThread
                     public class RangeTest {
                         @WorkerThread
@@ -294,11 +300,11 @@
                  *            this UI element, unless otherwise noted. This is typically the
                  *            main thread of your app. * */
                 @SuppressWarnings({"unchecked", "deprecation", "all"})
-                @android.support.annotation.UiThread public class RangeTest {
+                @androidx.annotation.UiThread public class RangeTest {
                 public RangeTest() { throw new RuntimeException("Stub!"); }
                 /** This method may take several seconds to complete, so it should
                  *            only be called from a worker thread. */
-                @android.support.annotation.WorkerThread public int test1() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.WorkerThread public int test1() { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -312,8 +318,8 @@
                 java(
                     """
                     package test.pkg;
-                    import android.support.annotation.UiThread;
-                    import android.support.annotation.WorkerThread;
+                    import androidx.annotation.UiThread;
+                    import androidx.annotation.WorkerThread;
                     public class RangeTest {
                         @UiThread @WorkerThread
                         public int test1() { }
@@ -337,7 +343,7 @@
                  * This method may take several seconds to complete, so it should
                  *  *            only be called from a worker thread.
                  */
-                @android.support.annotation.UiThread @android.support.annotation.WorkerThread public int test1() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.UiThread @androidx.annotation.WorkerThread public int test1() { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -498,7 +504,7 @@
                 /**
                  * Requires {@link test.pkg.RangeTest#ACCESS_COARSE_LOCATION}
                  */
-                @android.support.annotation.RequiresPermission(test.pkg.RangeTest.ACCESS_COARSE_LOCATION) public void test1() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.RequiresPermission(test.pkg.RangeTest.ACCESS_COARSE_LOCATION) public void test1() { throw new RuntimeException("Stub!"); }
                 public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
                 }
                 """
@@ -535,7 +541,7 @@
                 /**
                  * Requires "MyPermission"
                  */
-                @android.support.annotation.RequiresPermission("MyPermission") public void test1() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.RequiresPermission("MyPermission") public void test1() { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -573,7 +579,7 @@
                  * This is the existing documentation.
                  * Requires {@link test.pkg.RangeTest#ACCESS_COARSE_LOCATION}
                  */
-                @android.support.annotation.RequiresPermission(test.pkg.RangeTest.ACCESS_COARSE_LOCATION) public int test1() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.RequiresPermission(test.pkg.RangeTest.ACCESS_COARSE_LOCATION) public int test1() { throw new RuntimeException("Stub!"); }
                 public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
                 }
                 """
@@ -616,7 +622,7 @@
                  * Multiple lines of it.
                  * Requires {@link test.pkg.RangeTest#ACCESS_COARSE_LOCATION}
                  */
-                @android.support.annotation.RequiresPermission(test.pkg.RangeTest.ACCESS_COARSE_LOCATION) public int test1() { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.RequiresPermission(test.pkg.RangeTest.ACCESS_COARSE_LOCATION) public int test1() { throw new RuntimeException("Stub!"); }
                 public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
                 }
                 """
@@ -650,7 +656,7 @@
                 /**
                  * @param parameter2 Value is 10 or greater
                  */
-                public int test1(int parameter1, @android.support.annotation.IntRange(from=10) int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
+                public int test1(int parameter1, @androidx.annotation.IntRange(from=10) int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -698,7 +704,7 @@
                  * @param parameter3 docs for parameter2
                  * @return return value documented here
                  */
-                @android.support.annotation.RequiresPermission(test.pkg.RangeTest.ACCESS_COARSE_LOCATION) public int test1(int parameter1, int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.RequiresPermission(test.pkg.RangeTest.ACCESS_COARSE_LOCATION) public int test1(int parameter1, int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
                 public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
                 }
                 """
@@ -738,7 +744,7 @@
                  * @param parameter2 Value is 10 or greater
                  * @return return value documented here
                  */
-                public int test1(int parameter1, @android.support.annotation.IntRange(from=10) int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
+                public int test1(int parameter1, @androidx.annotation.IntRange(from=10) int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -781,7 +787,7 @@
                  * @param parameter2 Value is 10 or greater
                  * @return return value documented here
                  */
-                public int test1(int parameter1, @android.support.annotation.IntRange(from=10) int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
+                public int test1(int parameter1, @androidx.annotation.IntRange(from=10) int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -826,7 +832,7 @@
                  * @param parameter3 docs for parameter2
                  * @return return value documented here
                  */
-                public int test1(int parameter1, @android.support.annotation.IntRange(from=10) int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
+                public int test1(int parameter1, @androidx.annotation.IntRange(from=10) int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -860,7 +866,7 @@
                 /**
                  * @return Value is 10 or greater
                  */
-                @android.support.annotation.IntRange(from=10) public int test1(int parameter1, int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.IntRange(from=10) public int test1(int parameter1, int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -900,7 +906,7 @@
                  * @return return value documented here
                  * Value is 10 or greater
                  */
-                @android.support.annotation.IntRange(from=10) public int test1(int parameter1, int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
+                @androidx.annotation.IntRange(from=10) public int test1(int parameter1, int parameter2, int parameter3) { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -1045,7 +1051,6 @@
         )
     }
 
-
     @Test
     fun `Generate overview html docs`() {
         // If a codebase provides overview.html files in the a public package,
@@ -1124,6 +1129,40 @@
     }
 
     @Test
+    fun `Check RequiresApi handling`() {
+        check(
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    import androidx.annotation.RequiresApi;
+                    @RequiresApi(value = 21)
+                    public class MyClass1 {
+                    }
+                    """
+                ),
+
+                requiresApiSource
+            ),
+            checkCompilation = true,
+            checkDoclava1 = false,
+            stubs = arrayOf(
+                """
+                package test.pkg;
+                /**
+                 * Requires API level 21
+                 * @since 5.0 Lollipop (21)
+                 */
+                @SuppressWarnings({"unchecked", "deprecation", "all"})
+                @androidx.annotation.RequiresApi(21) public class MyClass1 {
+                public MyClass1() { throw new RuntimeException("Stub!"); }
+                }
+                """
+            )
+        )
+    }
+
+    @Test
     fun `Invoke external documentation tool`() {
         val jdkPath = getJdkPath()
         if (jdkPath == null) {
diff --git a/src/test/java/com/android/tools/metalava/DriverTest.kt b/src/test/java/com/android/tools/metalava/DriverTest.kt
index 2cd3e75..13ad8cd 100644
--- a/src/test/java/com/android/tools/metalava/DriverTest.kt
+++ b/src/test/java/com/android/tools/metalava/DriverTest.kt
@@ -20,7 +20,6 @@
 import com.android.SdkConstants.DOT_JAVA
 import com.android.SdkConstants.DOT_KT
 import com.android.SdkConstants.VALUE_TRUE
-import com.android.annotations.NonNull
 import com.android.ide.common.process.DefaultProcessExecutor
 import com.android.ide.common.process.LoggedProcessOutputHandler
 import com.android.ide.common.process.ProcessException
@@ -33,8 +32,11 @@
 import com.android.tools.lint.checks.infrastructure.stripComments
 import com.android.tools.metalava.doclava1.Errors
 import com.android.utils.FileUtils
+import com.android.utils.SdkUtils
 import com.android.utils.StdLogger
 import com.google.common.base.Charsets
+import com.google.common.io.ByteStreams
+import com.google.common.io.Closeables
 import com.google.common.io.Files
 import org.intellij.lang.annotations.Language
 import org.junit.Assert.assertEquals
@@ -46,6 +48,7 @@
 import java.io.File
 import java.io.PrintWriter
 import java.io.StringWriter
+import java.net.URL
 
 const val CHECK_OLD_DOCLAVA_TOO = false
 const val CHECK_STUB_COMPILATION = false
@@ -124,14 +127,21 @@
         exactApi: String? = null,
         /** The removed API (corresponds to --removed-api) */
         removedApi: String? = null,
+        /** The removed dex API (corresponds to --removed-dex-api) */
+        removedDexApi: String? = null,
         /** The private API (corresponds to --private-api) */
         privateApi: String? = null,
         /** The private DEX API (corresponds to --private-dex-api) */
         privateDexApi: String? = null,
+        /** The DEX API (corresponds to --dex-api) */
+        dexApi: String? = null,
         /** Expected stubs (corresponds to --stubs) */
         @Language("JAVA") stubs: Array<String> = emptyArray(),
         /** Stub source file list generated */
         stubsSourceList: String? = null,
+        /** Whether the stubs should be written as documentation stubs instead of plain stubs. Decides
+         * whether the stubs include @doconly elements, uses rewritten/migration annotations, etc */
+        docStubs: Boolean = false,
         /** Whether to run in doclava1 compat mode */
         compatibilityMode: Boolean = true,
         /** Whether to trim the output (leading/trailing whitespace removal) */
@@ -143,8 +153,12 @@
         /** Whether to run doclava1 on the test output and assert that the output is identical */
         checkDoclava1: Boolean = compatibilityMode,
         checkCompilation: Boolean = false,
-        /** Annotations to merge in */
-        @Language("XML") mergeAnnotations: String? = null,
+        /** Annotations to merge in (in .xml format) */
+        @Language("XML") mergeXmlAnnotations: String? = null,
+        /** Annotations to merge in (in .jaif format) */
+        @Language("TEXT") mergeJaifAnnotations: String? = null,
+        /** Annotations to merge in (in .txt/.signature format) */
+        @Language("TEXT") mergeSignatureAnnotations: String? = null,
         /** An optional API signature file content to load **instead** of Java/Kotlin source files */
         @Language("TEXT") signatureSource: String? = null,
         /** An optional API jar file content to load **instead** of Java/Kotlin source files */
@@ -201,17 +215,33 @@
         /** Corresponds to SDK constants file features.txt */
         sdk_features: String? = null,
         /** Corresponds to SDK constants file widgets.txt */
-        sdk_widgets: String? = null
+        sdk_widgets: String? = null,
+        /** 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
     ) {
         System.setProperty("METALAVA_TESTS_RUNNING", VALUE_TRUE)
 
-        if (compatibilityMode && mergeAnnotations != null) {
+        if (compatibilityMode && mergeXmlAnnotations != null) {
             fail(
                 "Can't specify both compatibilityMode and mergeAnnotations: there were no " +
-                        "annotations output in doclava1"
+                    "annotations output in doclava1"
+            )
+        }
+        if (compatibilityMode && mergeJaifAnnotations != null) {
+            fail(
+                "Can't specify both compatibilityMode and mergeJaifAnnotations: there were no " +
+                    "annotations output in doclava1"
             )
         }
 
+        if (compatibilityMode && mergeSignatureAnnotations != null) {
+            fail(
+                "Can't specify both compatibilityMode and mergeSignatureAnnotations: there were no " +
+                    "annotations output in doclava1"
+            )
+        }
         Errors.resetLevels()
 
         /** Expected output if exiting with an error code */
@@ -233,7 +263,7 @@
         val sourceList =
             if (signatureSource != null) {
                 sourcePathDir.mkdirs()
-                assert(sourceFiles.isEmpty(), { "Shouldn't combine sources with signature file loads" })
+                assert(sourceFiles.isEmpty()) { "Shouldn't combine sources with signature file loads" }
                 val signatureFile = File(project, "load-api.txt")
                 Files.asCharSink(signatureFile, Charsets.UTF_8).write(signatureSource.trimIndent())
                 if (includeStrippedSuperclassWarnings) {
@@ -247,7 +277,7 @@
                 }
             } else if (apiJar != null) {
                 sourcePathDir.mkdirs()
-                assert(sourceFiles.isEmpty(), { "Shouldn't combine sources with API jar file loads" })
+                assert(sourceFiles.isEmpty()) { "Shouldn't combine sources with API jar file loads" }
                 arrayOf(apiJar.path)
             } else {
                 sourceFiles.asSequence().map { File(project, it.targetPath).path }.toList().toTypedArray()
@@ -260,9 +290,25 @@
             }
         }
 
-        val mergeAnnotationsArgs = if (mergeAnnotations != null) {
+        val mergeAnnotationsArgs = if (mergeXmlAnnotations != null) {
             val merged = File(project, "merged-annotations.xml")
-            Files.asCharSink(merged, Charsets.UTF_8).write(mergeAnnotations.trimIndent())
+            Files.asCharSink(merged, Charsets.UTF_8).write(mergeXmlAnnotations.trimIndent())
+            arrayOf("--merge-annotations", merged.path)
+        } else {
+            emptyArray()
+        }
+
+        val jaifAnnotationsArgs = if (mergeJaifAnnotations != null) {
+            val merged = File(project, "merged-annotations.jaif")
+            Files.asCharSink(merged, Charsets.UTF_8).write(mergeJaifAnnotations.trimIndent())
+            arrayOf("--merge-annotations", merged.path)
+        } else {
+            emptyArray()
+        }
+
+        val signatureAnnotationsArgs = if (mergeSignatureAnnotations != null) {
+            val merged = File(project, "merged-annotations.txt")
+            Files.asCharSink(merged, Charsets.UTF_8).write(mergeSignatureAnnotations.trimIndent())
             arrayOf("--merge-annotations", merged.path)
         } else {
             emptyArray()
@@ -348,6 +394,10 @@
                 args.add("--show-annotation")
                 args.add("android.annotation.SystemApi")
             }
+            if (includeSystemApiAnnotations && !args.contains("android.annotation.SystemService")) {
+                args.add("--show-annotation")
+                args.add("android.annotation.SystemService")
+            }
             args.toTypedArray()
         } else {
             emptyArray()
@@ -368,9 +418,17 @@
             emptyArray()
         }
 
+        var removedDexApiFile: File? = null
+        val removedDexArgs = if (removedDexApi != null) {
+            removedDexApiFile = temporaryFolder.newFile("removed-dex.txt")
+            arrayOf("--removed-dex-api", removedDexApiFile.path)
+        } else {
+            emptyArray()
+        }
+
         var apiFile: File? = null
         val apiArgs = if (api != null) {
-            apiFile = temporaryFolder.newFile("api.txt")
+            apiFile = temporaryFolder.newFile("public-api.txt")
             arrayOf("--api", apiFile.path)
         } else {
             emptyArray()
@@ -392,6 +450,14 @@
             emptyArray()
         }
 
+        var dexApiFile: File? = null
+        val dexApiArgs = if (dexApi != null) {
+            dexApiFile = temporaryFolder.newFile("public-dex.txt")
+            arrayOf("--dex-api", dexApiFile.path)
+        } else {
+            emptyArray()
+        }
+
         var privateDexApiFile: File? = null
         val privateDexApiArgs = if (privateDexApi != null) {
             privateDexApiFile = temporaryFolder.newFile("private-dex.txt")
@@ -403,7 +469,11 @@
         var stubsDir: File? = null
         val stubsArgs = if (stubs.isNotEmpty()) {
             stubsDir = temporaryFolder.newFolder("stubs")
-            arrayOf("--stubs", stubsDir.path)
+            if (docStubs) {
+                arrayOf("--doc-stubs", stubsDir.path)
+            } else {
+                arrayOf("--stubs", stubsDir.path)
+            }
         } else {
             emptyArray()
         }
@@ -465,6 +535,32 @@
             sdkFilesDir = null
         }
 
+        val artifactArgs = if (artifacts != null) {
+            val args = mutableListOf<String>()
+            var index = 1
+            for ((artifactId, signatures) in artifacts) {
+                val signatureFile = temporaryFolder.newFile("signature-file-$index.txt")
+                Files.asCharSink(signatureFile, Charsets.UTF_8).write(signatures.trimIndent())
+                index++
+
+                args.add("--register-artifact")
+                args.add(signatureFile.path)
+                args.add(artifactId)
+            }
+            args.toTypedArray()
+        } else {
+            emptyArray()
+        }
+
+        val extractedAnnotationsZip: File?
+        val extractAnnotationsArgs = if (extractAnnotations != null) {
+            extractedAnnotationsZip = temporaryFolder.newFile("extracted-annotations.zip")
+            arrayOf("--extract-annotations", extractedAnnotationsZip.path)
+        } else {
+            extractedAnnotationsZip = null
+            emptyArray()
+        }
+
         val actualOutput = runDriver(
             "--no-color",
             "--no-banner",
@@ -472,7 +568,7 @@
             // For the tests we want to treat references to APIs like java.io.Closeable
             // as a class that is part of the API surface, not as a hidden class as would
             // be the case when analyzing a complete API surface
-            //"--unhide-classpath-classes",
+            // "--unhide-classpath-classes",
             "--allow-referencing-unknown-classes",
 
             // Annotation generation temporarily turned off by default while integrating with
@@ -485,9 +581,11 @@
             androidJar.path,
             *kotlinPathArgs,
             *removedArgs,
+            *removedDexArgs,
             *apiArgs,
             *exactApiArgs,
             *privateApiArgs,
+            *dexApiArgs,
             *privateDexApiArgs,
             *stubsArgs,
             *stubsSourceListArgs,
@@ -498,6 +596,8 @@
             *coverageStats,
             *quiet,
             *mergeAnnotationsArgs,
+            *jaifAnnotationsArgs,
+            *signatureAnnotationsArgs,
             *previousApiArgs,
             *migrateNullsArguments,
             *checkCompatibilityArguments,
@@ -509,6 +609,8 @@
             *sdkFilesArgs,
             *importedPackageArgs.toTypedArray(),
             *skipEmitPackagesArgs.toTypedArray(),
+            *artifactArgs,
+            *extractAnnotationsArgs,
             *sourceList,
             *extraArguments,
             expectedFail = expectedFail
@@ -533,6 +635,15 @@
             assertEquals(stripComments(removedApi, stripLineComments = false).trimIndent(), expectedText)
         }
 
+        if (removedDexApi != null && removedDexApiFile != null) {
+            assertTrue(
+                "${removedDexApiFile.path} does not exist even though --removed-dex-api was used",
+                removedDexApiFile.exists()
+            )
+            val expectedText = readFile(removedDexApiFile, stripBlankLines, trim)
+            assertEquals(stripComments(removedDexApi, stripLineComments = false).trimIndent(), expectedText)
+        }
+
         if (exactApi != null && exactApiFile != null) {
             assertTrue(
                 "${exactApiFile.path} does not exist even though --exact-api was used",
@@ -551,6 +662,15 @@
             assertEquals(stripComments(privateApi, stripLineComments = false).trimIndent(), expectedText)
         }
 
+        if (dexApi != null && dexApiFile != null) {
+            assertTrue(
+                "${dexApiFile.path} does not exist even though --dex-api was used",
+                dexApiFile.exists()
+            )
+            val expectedText = readFile(dexApiFile, stripBlankLines, trim)
+            assertEquals(stripComments(dexApi, stripLineComments = false).trimIndent(), expectedText)
+        }
+
         if (privateDexApi != null && privateDexApiFile != null) {
             assertTrue(
                 "${privateDexApiFile.path} does not exist even though --private-dex-api was used",
@@ -609,6 +729,16 @@
             )
         }
 
+        if (extractAnnotations != null && extractedAnnotationsZip != null) {
+            assertTrue(
+                "Using --extract-annotations but $extractedAnnotationsZip was not created",
+                extractedAnnotationsZip.isFile
+            )
+            for ((pkg, xml) in extractAnnotations) {
+                assertPackageXml(pkg, extractedAnnotationsZip, xml)
+            }
+        }
+
         if (stubs.isNotEmpty() && stubsDir != null) {
             for (i in 0 until stubs.size) {
                 val stub = stubs[i]
@@ -638,13 +768,6 @@
             val generated = gatherSources(listOf(stubsDir)).map { it.path }.toList().toTypedArray()
 
             // Also need to include on the compile path annotation classes referenced in the stubs
-            val supportAnnotationsDir = File("../../frameworks/support/annotations/src/main/java/")
-            if (!supportAnnotationsDir.isDirectory) {
-                fail("Couldn't find $supportAnnotationsDir: Is the pwd set to the root of the metalava source code?")
-            }
-            val supportAnnotations =
-                gatherSources(listOf(supportAnnotationsDir)).map { it.path }.toList().toTypedArray()
-
             val extraAnnotationsDir = File("stub-annotations/src/main/java")
             if (!extraAnnotationsDir.isDirectory) {
                 fail("Couldn't find $extraAnnotationsDir: Is the pwd set to the root of the metalava source code?")
@@ -652,11 +775,9 @@
             }
             val extraAnnotations = gatherSources(listOf(extraAnnotationsDir)).map { it.path }.toList().toTypedArray()
 
-
             if (!runCommand(
                     "${getJdkPath()}/bin/javac", arrayOf(
-                        "-d", project.path, *generated,
-                        *supportAnnotations, *extraAnnotations
+                        "-d", project.path, *generated, *extraAnnotations
                     )
                 )
             ) {
@@ -668,7 +789,7 @@
         if (checkDoclava1 && !CHECK_OLD_DOCLAVA_TOO) {
             println(
                 "This test requested diffing with doclava1, but doclava1 testing was disabled with the " +
-                        "DriverTest#CHECK_OLD_DOCLAVA_TOO = false"
+                    "DriverTest#CHECK_OLD_DOCLAVA_TOO = false"
             )
         }
 
@@ -714,8 +835,8 @@
             )
         }
 
-        if (CHECK_OLD_DOCLAVA_TOO && checkDoclava1 && signatureSource == null
-            && removedApi != null && removedApiFile != null
+        if (CHECK_OLD_DOCLAVA_TOO && checkDoclava1 && signatureSource == null &&
+            removedApi != null && removedApiFile != null
         ) {
             removedApiFile.delete()
             checkSignaturesWithDoclava1(
@@ -819,6 +940,48 @@
                 showUnannotated = showUnannotated
             )
         }
+
+        if (CHECK_OLD_DOCLAVA_TOO && checkDoclava1 && signatureSource == null &&
+            dexApi != null && dexApiFile != null
+        ) {
+            dexApiFile.delete()
+            checkSignaturesWithDoclava1(
+                api = dexApi,
+                argument = "-dexApi",
+                output = dexApiFile,
+                expected = dexApiFile,
+                sourceList = sourceList,
+                sourcePath = sourcePath,
+                packages = packages,
+                androidJar = androidJar,
+                trim = trim,
+                stripBlankLines = stripBlankLines,
+                showAnnotationArgs = showAnnotationArguments,
+                stubImportPackages = importedPackages,
+                // Workaround: -dexApi is a no-op if you don't also provide -api
+                extraArguments = arrayOf("-api", File(dexApiFile.parentFile, "dummy-api.txt").path),
+                showUnannotated = showUnannotated
+            )
+        }
+    }
+
+    /** Checks that the given zip annotations file contains the given XML package contents */
+    private fun assertPackageXml(pkg: String, output: File, @Language("XML") expected: String) {
+        assertNotNull(output)
+        assertTrue(output.exists())
+        val url = URL(
+            "jar:" + SdkUtils.fileToUrlString(output) + "!/" + pkg.replace('.', '/') +
+                "/annotations.xml"
+        )
+        val stream = url.openStream()
+        try {
+            val bytes = ByteStreams.toByteArray(stream)
+            assertNotNull(bytes)
+            val xml = String(bytes, Charsets.UTF_8).replace("\r\n", "\n")
+            assertEquals(expected.trimIndent().trim(), xml.trimIndent().trim())
+        } finally {
+            Closeables.closeQuietly(stream)
+        }
     }
 
     private fun checkSignaturesWithDoclava1(
@@ -931,11 +1094,9 @@
             output.path
         )
 
-
         val message = "\n${args.joinToString(separator = "\n") { "\"$it\"," }}"
         println("Running doclava1 with the following args:\n$message")
 
-
         if (!runCommand(
                 "$jdkPath/bin/java",
                 arrayOf(
@@ -982,11 +1143,11 @@
         private val sdk: File
             get() = File(
                 System.getenv("ANDROID_HOME")
-                        ?: error("You must set \$ANDROID_HOME before running tests")
+                    ?: error("You must set \$ANDROID_HOME before running tests")
             )
 
         fun getAndroidJar(apiLevel: Int): File? {
-            val localFile = File("../../prebuilts/sdk/$apiLevel/android.jar")
+            val localFile = File("../../prebuilts/sdk/$apiLevel/public/android.jar")
             if (localFile.exists()) {
                 return localFile
             }
@@ -1058,6 +1219,23 @@
     @Retention(SOURCE)
     @Target({ANNOTATION_TYPE})
     public @interface IntDef {
+        int[] value() default {};
+        boolean flag() default false;
+    }
+    """
+).indented()
+
+val longDefAnnotationSource: TestFile = java(
+    """
+    package android.annotation;
+    import java.lang.annotation.Retention;
+    import java.lang.annotation.RetentionPolicy;
+    import java.lang.annotation.Target;
+    import static java.lang.annotation.ElementType.*;
+    import static java.lang.annotation.RetentionPolicy.SOURCE;
+    @Retention(SOURCE)
+    @Target({ANNOTATION_TYPE})
+    public @interface LongDef {
         long[] value() default {};
         boolean flag() default false;
     }
@@ -1088,6 +1266,37 @@
     """
 ).indented()
 
+val libcoreNonNullSource: TestFile = DriverTest.java(
+    """
+    package libcore.util;
+    import static java.lang.annotation.ElementType.*;
+    import static java.lang.annotation.RetentionPolicy.SOURCE;
+    import java.lang.annotation.*;
+    @Documented
+    @Retention(SOURCE)
+    @Target({TYPE_USE})
+    public @interface NonNull {
+       int from() default Integer.MIN_VALUE;
+       int to() default Integer.MAX_VALUE;
+    }
+    """
+).indented()
+
+val libcoreNullableSource: TestFile = DriverTest.java(
+    """
+    package libcore.util;
+    import static java.lang.annotation.ElementType.*;
+    import static java.lang.annotation.RetentionPolicy.SOURCE;
+    import java.lang.annotation.*;
+    @Documented
+    @Retention(SOURCE)
+    @Target({TYPE_USE})
+    public @interface Nullable {
+       int from() default Integer.MIN_VALUE;
+       int to() default Integer.MAX_VALUE;
+    }
+    """
+).indented()
 val requiresPermissionSource: TestFile = java(
     """
     package android.annotation;
@@ -1119,6 +1328,21 @@
             """
 ).indented()
 
+val requiresApiSource: TestFile = java(
+    """
+    package androidx.annotation;
+    import java.lang.annotation.*;
+    import static java.lang.annotation.ElementType.*;
+    import static java.lang.annotation.RetentionPolicy.SOURCE;
+    @Retention(SOURCE)
+    @Target({TYPE,FIELD,METHOD,CONSTRUCTOR})
+    public @interface RequiresApi {
+        int value() default 1;
+        int api() default 1;
+    }
+            """
+).indented()
+
 val sdkConstantSource: TestFile = java(
     """
     package android.annotation;
@@ -1127,7 +1351,7 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface SdkConstant {
         enum SdkConstantType {
-            ACTIVITY_INTENT_ACTION, BROADCAST_INTENT_ACTION, SERVICE_ACTION, INTENT_CATEGORY, FEATURE;
+            ACTIVITY_INTENT_ACTION, BROADCAST_INTENT_ACTION, SERVICE_ACTION, INTENT_CATEGORY, FEATURE
         }
         SdkConstantType value();
     }
@@ -1172,7 +1396,7 @@
 
 val supportNonNullSource: TestFile = java(
     """
-    package android.support.annotation;
+    package androidx.annotation;
     import java.lang.annotation.*;
     import static java.lang.annotation.ElementType.*;
     import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -1186,7 +1410,35 @@
 
 val supportNullableSource: TestFile = java(
     """
-package android.support.annotation;
+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 {
+}
+                """
+)
+
+val androidxNonNullSource: 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 NonNull {
+    }
+    """
+).indented()
+
+val androidxNullableSource: TestFile = java(
+    """
+package androidx.annotation;
 import java.lang.annotation.*;
 import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -1200,7 +1452,7 @@
 
 val supportParameterName: TestFile = java(
     """
-    package android.support.annotation;
+    package androidx.annotation;
     import java.lang.annotation.*;
     import static java.lang.annotation.ElementType.*;
     import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -1215,7 +1467,7 @@
 
 val supportDefaultValue: TestFile = java(
     """
-    package android.support.annotation;
+    package androidx.annotation;
     import java.lang.annotation.*;
     import static java.lang.annotation.ElementType.*;
     import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -1230,7 +1482,7 @@
 
 val uiThreadSource: TestFile = java(
     """
-    package android.support.annotation;
+    package androidx.annotation;
     import java.lang.annotation.*;
     import static java.lang.annotation.ElementType.*;
     import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -1254,7 +1506,7 @@
 
 val workerThreadSource: TestFile = java(
     """
-    package android.support.annotation;
+    package androidx.annotation;
     import java.lang.annotation.*;
     import static java.lang.annotation.ElementType.*;
     import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -1313,6 +1565,18 @@
     """
 ).indented()
 
+val testApiSource: TestFile = java(
+    """
+    package android.annotation;
+    import static java.lang.annotation.ElementType.*;
+    import java.lang.annotation.*;
+    @Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TestApi {
+    }
+    """
+).indented()
+
 val widgetSource: TestFile = java(
     """
     package android.annotation;
@@ -1323,4 +1587,3 @@
     }
     """
 ).indented()
-
diff --git a/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt b/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt
index 517abd7..427e41d 100644
--- a/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt
+++ b/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt
@@ -16,417 +16,206 @@
 
 package com.android.tools.metalava
 
-import com.android.utils.SdkUtils.fileToUrlString
-import com.google.common.base.Charsets
-import com.google.common.io.ByteStreams
-import com.google.common.io.Closeables
-import com.google.common.io.Files
-import org.intellij.lang.annotations.Language
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertTrue
+import org.junit.Ignore
 import org.junit.Test
-import java.io.File
-import java.net.URL
 
 @SuppressWarnings("ALL") // Sample code
 class ExtractAnnotationsTest : DriverTest() {
 
     @Test
-    fun `Include class retention`() {
-        val androidJar = getPlatformFile("android.jar")
+    fun `Check java typedef extraction and warning about non-source retention of typedefs`() {
+        check(
+            sourceFiles = *arrayOf(
+                java(
+            """
+                    package test.pkg;
 
-        val project = createProject(
-            packageTest,
-            genericTest,
-            intDefTest,
-            permissionsTest,
-            manifest,
-            intDefAnnotation,
-            intRangeAnnotation,
-            permissionAnnotation,
-            nullableAnnotation
-        )
+                    import android.annotation.IntDef;
+                    import android.annotation.IntRange;
 
-        val output = temporaryFolder.newFile("annotations.zip")
+                    import java.lang.annotation.Retention;
+                    import java.lang.annotation.RetentionPolicy;
 
-        runDriver(
-            "--sources",
-            File(project, "src").path,
-            "--classpath",
-            androidJar.path,
-            "--extract-annotations",
-            output.path
-        )
+                    @SuppressWarnings({"UnusedDeclaration", "WeakerAccess"})
+                    public class IntDefTest {
+                        @IntDef({STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT})
+                        @IntRange(from = 20)
+                        private @interface DialogStyle {}
 
-        // Check extracted annotations
-        checkPackageXml(
-            "test.pkg", output, """<?xml version="1.0" encoding="UTF-8"?>
-<root>
-  <item name="test.pkg">
-    <annotation name="android.support.annotation.IntRange">
-      <val name="from" val="20" />
-    </annotation>
-  </item>
-  <item name="test.pkg.IntDefTest void setFlags(java.lang.Object, int) 1">
-    <annotation name="android.support.annotation.IntDef">
-      <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 4}" />
-      <val name="flag" val="true" />
-    </annotation>
-  </item>
-  <item name="test.pkg.IntDefTest void setStyle(int, int) 0">
-    <annotation name="android.support.annotation.IntDef">
-      <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT}" />
-    </annotation>
-    <annotation name="android.support.annotation.IntRange">
-      <val name="from" val="20" />
-    </annotation>
-  </item>
-  <item name="test.pkg.IntDefTest.Inner void setInner(int) 0">
-    <annotation name="android.support.annotation.IntDef">
-      <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 4}" />
-      <val name="flag" val="true" />
-    </annotation>
-  </item>
-  <item name="test.pkg.MyEnhancedList">
-    <annotation name="android.support.annotation.IntRange">
-      <val name="from" val="0" />
-    </annotation>
-  </item>
-  <item name="test.pkg.MyEnhancedList E getReversed(java.util.List&lt;java.lang.String&gt;, java.util.Comparator&lt;? super E&gt;)">
-    <annotation name="android.support.annotation.IntRange">
-      <val name="from" val="10" />
-    </annotation>
-  </item>
-  <item name="test.pkg.MyEnhancedList java.lang.String getPrefix()">
-    <annotation name="android.support.annotation.Nullable" />
-  </item>
-  <item name="test.pkg.PermissionsTest CONTENT_URI">
-    <annotation name="android.support.annotation.RequiresPermission.Read">
-      <val name="value" val="&quot;android.permission.MY_READ_PERMISSION_STRING&quot;" />
-    </annotation>
-    <annotation name="android.support.annotation.RequiresPermission.Write">
-      <val name="value" val="&quot;android.permission.MY_WRITE_PERMISSION_STRING&quot;" />
-    </annotation>
-  </item>
-  <item name="test.pkg.PermissionsTest void myMethod()">
-    <annotation name="android.support.annotation.RequiresPermission">
-      <val name="value" val="&quot;android.permission.MY_PERMISSION_STRING&quot;" />
-    </annotation>
-  </item>
-  <item name="test.pkg.PermissionsTest void myMethod2()">
-    <annotation name="android.support.annotation.RequiresPermission">
-      <val name="anyOf" val="{&quot;android.permission.MY_PERMISSION_STRING&quot;, &quot;android.permission.MY_PERMISSION_STRING2&quot;}" />
-    </annotation>
-  </item>
-</root>
+                        public static final int STYLE_NORMAL = 0;
+                        public static final int STYLE_NO_TITLE = 1;
+                        public static final int STYLE_NO_FRAME = 2;
+                        public static final int STYLE_NO_INPUT = 3;
+                        public static final int UNRELATED = 3;
 
-"""
+                        public void setStyle(@DialogStyle int style, int theme) {
+                        }
+
+                        public void testIntDef(int arg) {
+                        }
+                        @IntDef(value = {STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT, 3, 3 + 1}, flag=true)
+                        @Retention(RetentionPolicy.SOURCE)
+                        private @interface DialogFlags {}
+
+                        public void setFlags(Object first, @DialogFlags int flags) {
+                        }
+
+                        public static final String TYPE_1 = "type1";
+                        public static final String TYPE_2 = "type2";
+                        public static final String UNRELATED_TYPE = "other";
+
+                        public static class Inner {
+                            public void setInner(@DialogFlags int flags) {
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                intDefAnnotationSource,
+                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 """
+                <?xml version="1.0" encoding="UTF-8"?>
+                <root>
+                  <item name="test.pkg.IntDefTest void setFlags(java.lang.Object, int) 1">
+                    <annotation name="androidx.annotation.IntDef">
+                      <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 4}" />
+                      <val name="flag" val="true" />
+                    </annotation>
+                  </item>
+                  <item name="test.pkg.IntDefTest void setStyle(int, int) 0">
+                    <annotation name="androidx.annotation.IntDef">
+                      <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT}" />
+                    </annotation>
+                  </item>
+                  <item name="test.pkg.IntDefTest.Inner void setInner(int) 0">
+                    <annotation name="androidx.annotation.IntDef">
+                      <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 4}" />
+                      <val name="flag" val="true" />
+                    </annotation>
+                  </item>
+                </root>
+                """
+            )
         )
     }
 
     @Test
-    fun `Skip class retention`() {
-        val androidJar = getPlatformFile("android.jar")
+    fun `Check Kotlin and referencing hidden constants from typedef`() {
+        check(
+            sourceFiles = *arrayOf(
+                kotlin(
+                    """
+                    @file:Suppress("unused", "UseExpressionBody")
 
-        val project = createProject(
-            intDefTest,
-            permissionsTest,
-            manifest,
-            intDefAnnotation,
-            intRangeAnnotation,
-            permissionAnnotation
-        )
+                    package test.pkg
 
-        val output = temporaryFolder.newFile("annotations.zip")
+                    import android.annotation.LongDef
 
-        runDriver(
-            "--sources",
-            File(project, "src").path,
-            "--classpath",
-            androidJar.path,
-            "--skip-class-retention",
-            "--extract-annotations",
-            output.path
-        )
+                    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
 
-        // Check external annotations
-        checkPackageXml(
-            "test.pkg", output,
-            """<?xml version="1.0" encoding="UTF-8"?>
-<root>
-  <item name="test.pkg.IntDefTest void setFlags(java.lang.Object, int) 1">
-    <annotation name="android.support.annotation.IntDef">
-      <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 4}" />
-      <val name="flag" val="true" />
-    </annotation>
-  </item>
-  <item name="test.pkg.IntDefTest void setStyle(int, int) 0">
-    <annotation name="android.support.annotation.IntDef">
-      <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT}" />
-    </annotation>
-    <annotation name="android.support.annotation.IntRange">
-      <val name="from" val="20" />
-    </annotation>
-  </item>
-  <item name="test.pkg.IntDefTest.Inner void setInner(int) 0">
-    <annotation name="android.support.annotation.IntDef">
-      <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 4}" />
-      <val name="flag" val="true" />
-    </annotation>
-  </item>
-</root>
+                    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>
+                """
+            )
         )
     }
 
+    @Ignore("Not working reliably")
     @Test
-    fun `Test writing jar recipe file`() {
-        val androidJar = getPlatformFile("android.jar")
-
-        val project = createProject(
-            intDefTest,
-            permissionsTest,
-            manifest,
-            intDefAnnotation,
-            intRangeAnnotation,
-            permissionAnnotation
-        )
-
-        val output = temporaryFolder.newFile("annotations.zip")
-        val typedefFile = temporaryFolder.newFile("typedefs.txt")
-
-        runDriver(
-            "--sources",
-            File(project, "src").path,
-            "--classpath",
-            androidJar.path,
-
-            "--extract-annotations",
-            output.path,
-            "--typedef-file",
-            typedefFile.path
-        )
-
-        // Check recipe
-        assertEquals(
-            """D test/pkg/IntDefTest${"$"}DialogFlags
-D test/pkg/IntDefTest${"$"}DialogStyle
-""",
-            Files.asCharSource(typedefFile, Charsets.UTF_8).read()
-        )
-    }
-
-    @SuppressWarnings("all") // sample code
-    private val intDefAnnotation = java(
-        """
-                package android.support.annotation;
-                import java.lang.annotation.Retention;
-                import java.lang.annotation.RetentionPolicy;
-                import java.lang.annotation.Target;
-                import static java.lang.annotation.ElementType.*;
-                import static java.lang.annotation.RetentionPolicy.SOURCE;
-                @Retention(SOURCE)
-                @Target({ANNOTATION_TYPE})
-                public @interface IntDef {
-                    long[] value() default {};
-                    boolean flag() default false;
-                }
-                """
-    ).indented()
-
-    @SuppressWarnings("all") // sample code
-    private val intRangeAnnotation = java(
-        """
-                package android.support.annotation;
-
-                import java.lang.annotation.Retention;
-                import java.lang.annotation.Target;
-
-                import static java.lang.annotation.ElementType.*;
-                import static java.lang.annotation.RetentionPolicy.CLASS;
-
-                @Retention(CLASS)
-                @Target({CONSTRUCTOR,METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE})
-                public @interface IntRange {
-                    long from() default Long.MIN_VALUE;
-                    long to() default Long.MAX_VALUE;
-                }
-                """
-    ).indented()
-
-    @SuppressWarnings("all") // sample code
-    private val permissionAnnotation = java(
-        """
-                package android.support.annotation;
-                import java.lang.annotation.Retention;
-                import java.lang.annotation.RetentionPolicy;
-                import java.lang.annotation.Target;
-                import static java.lang.annotation.ElementType.*;
-                import static java.lang.annotation.RetentionPolicy.*;
-                @Retention(CLASS)
-                @Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD})
-                public @interface RequiresPermission {
-                    String value() default "";
-                    String[] allOf() default {};
-                    String[] anyOf() default {};
-                    boolean conditional() default false;
-                    @Target(FIELD)
-                    @interface Read {
-                        RequiresPermission value();
-                    }
-                    @Target(FIELD)
-                    @interface Write {
-                        RequiresPermission value();
-                    }
-                }"""
-    ).indented()
-
-    @SuppressWarnings("all") // sample code
-    private val nullableAnnotation = java(
-        """
-                package android.support.annotation;
-                import java.lang.annotation.*;
-                import static java.lang.annotation.ElementType.*;
-                import static java.lang.annotation.RetentionPolicy.*;
-                @Retention(CLASS)
-                @Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-                public @interface Nullable {
-                }"""
-    ).indented()
-
-    @SuppressWarnings("all") // sample code
-    private val packageTest = java(
-        """
-                @IntRange(from = 20)
-                package test.pkg;
-
-                import android.support.annotation.IntRange;"""
-    ).indented()
-
-    @SuppressWarnings("all") // sample code
-    private val genericTest = java(
-        """
-                package test.pkg;
-
-                import android.support.annotation.IntRange;
-                import android.support.annotation.Nullable;
-
-                import java.util.Comparator;
-                import java.util.List;
-
-                @IntRange(from = 0)
-                public interface MyEnhancedList<E> extends List<E> {
-                    @IntRange(from = 10)
-                    E getReversed(List<String> filter, Comparator<? super E> comparator);
-                    @Nullable String getPrefix();
-                }
-                """
-    )
-
-    @SuppressWarnings("all") // sample code
-    private val intDefTest = java(
-        """
-                package test.pkg;
-
-                import android.support.annotation.IntDef;
-                import android.support.annotation.IntRange;
-                import android.support.annotation.Keep;
-
-                import java.lang.annotation.Retention;
-                import java.lang.annotation.RetentionPolicy;
-
-                @SuppressWarnings({"UnusedDeclaration", "WeakerAccess"})
-                public class IntDefTest {
-                    @IntDef({STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT})
-                    @IntRange(from = 20)
-                    @Retention(RetentionPolicy.SOURCE)
-                    private @interface DialogStyle {}
-
-                    public static final int STYLE_NORMAL = 0;
-                    public static final int STYLE_NO_TITLE = 1;
-                    public static final int STYLE_NO_FRAME = 2;
-                    public static final int STYLE_NO_INPUT = 3;
-                    public static final int UNRELATED = 3;
-
-                    public void setStyle(@DialogStyle int style, int theme) {
-                    }
-
-                    @Keep    public void testIntDef(int arg) {
-                    }
-                    @IntDef(value = {STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT, 3, 3 + 1}, flag=true)
-                    @Retention(RetentionPolicy.SOURCE)
-                    private @interface DialogFlags {}
-
-                    public void setFlags(Object first, @DialogFlags int flags) {
-                    }
-
-                    public static final String TYPE_1 = "type1";
-                    public static final String TYPE_2 = "type2";
-                    public static final String UNRELATED_TYPE = "other";
-
-                    public static class Inner {
-                        public void setInner(@DialogFlags int flags) {
-                        }
-                    }
-                }"""
-    ).indented()
-
-    @SuppressWarnings("all") // sample code
-    private val permissionsTest = java(
-        """
+    fun `Include merged annotations in exported source annotations`() {
+        check(
+            compatibilityMode = false,
+            outputKotlinStyleNulls = false,
+            includeSystemApiAnnotations = false,
+            omitCommonPackages = false,
+            warnings = "error: Unexpected reference to Nonexistent.Field [AnnotationExtraction:146]",
+            sourceFiles = *arrayOf(
+                java(
+                    """
                     package test.pkg;
 
-                    import android.support.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 = "";
-                    }
-                    """
-    )
-
-    @SuppressWarnings("all") // sample code
-    private val manifest = 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()
-
-    private fun checkPackageXml(pkg: String, output: File, @Language("XML") expected: String) {
-        assertNotNull(output)
-        assertTrue(output.exists())
-        val url = URL(
-            "jar:" + fileToUrlString(output) + "!/" + pkg.replace('.', '/') +
-                    "/annotations.xml"
+                    public class MyTest {
+                        public void test(int arg) { }
+                    }"""
+                )
+            ),
+            mergeXmlAnnotations = """<?xml version="1.0" encoding="UTF-8"?>
+                <root>
+                  <item name="test.pkg.MyTest void test(int) 0">
+                    <annotation name="org.intellij.lang.annotations.MagicConstant">
+                      <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, Nonexistent.Field}" />
+                    </annotation>
+                  </item>
+                </root>
+                """,
+            extractAnnotations = mapOf("test.pkg" to """
+                <?xml version="1.0" encoding="UTF-8"?>
+                <root>
+                  <item name="test.pkg.MyTest void test(int) 0">
+                    <annotation name="androidx.annotation.IntDef">
+                      <val name="value" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR}" />
+                    </annotation>
+                  </item>
+                </root>
+                """
+            )
         )
-        val stream = url.openStream()
-        try {
-            val bytes = ByteStreams.toByteArray(stream)
-            assertNotNull(bytes)
-            val xml = String(bytes, Charsets.UTF_8).replace("\r\n", "\n")
-            assertEquals(expected, xml)
-        } finally {
-            Closeables.closeQuietly(stream)
-        }
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/metalava/Java9LanguageFeaturesTest.kt b/src/test/java/com/android/tools/metalava/Java9LanguageFeaturesTest.kt
new file mode 100644
index 0000000..e5233fa
--- /dev/null
+++ b/src/test/java/com/android/tools/metalava/Java9LanguageFeaturesTest.kt
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("ALL")
+
+package com.android.tools.metalava
+
+import org.junit.Test
+
+class Java9LanguageFeaturesTest : DriverTest() {
+    @Test
+    fun `Private Interface Method`() {
+        // Basic class; also checks that default constructor is made explicit
+        check(
+            checkCompilation = false, // Not compiling with JDK 9 yet
+            checkDoclava1 = false, // Not handling JDK 9
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+
+                    public interface Person {
+                        String name();
+                        private String reverse(String s) {
+                            return new StringBuilder(s).reverse().toString();
+                        }
+                    }
+                    """
+                )
+            ),
+            api = """
+                package test.pkg {
+                  public abstract interface Person {
+                    method public abstract java.lang.String name();
+                  }
+                }
+                """,
+            extraArguments = arrayOf("--java-source", "1.9")
+        )
+    }
+
+    @Test
+    fun `Basic class signature extraction`() {
+        // Basic class; also checks that default constructor is made explicit
+        check(
+            checkCompilation = false, // Not compiling with JDK 9 yet
+            checkDoclava1 = false, // Not handling JDK 9
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package libcore.internal;
+
+                    import java.io.ByteArrayInputStream;
+                    import java.io.ByteArrayOutputStream;
+                    import java.io.IOException;
+                    import java.io.InputStream;
+                    import java.util.ArrayList;
+                    import java.util.Arrays;
+                    import java.util.List;
+                    import java.util.Objects;
+                    import java.util.concurrent.atomic.AtomicReference;
+
+                    public class Java9LanguageFeatures {
+
+                        public interface Person {
+                            String name();
+
+                            default boolean isPalindrome() {
+                                return name().equals(reverse(name()));
+                            }
+
+                            default boolean isPalindromeIgnoreCase() {
+                                return name().equalsIgnoreCase(reverse(name()));
+                            }
+
+                            // Language feature: private interface method
+                            private String reverse(String s) {
+                                return new StringBuilder(s).reverse().toString();
+                            }
+                        }
+
+                        @SafeVarargs
+                        public static<T> String toListString(T... values) {
+                            return toString(values).toString();
+                        }
+
+                        // Language feature: @SafeVarargs on private methods
+                        @SafeVarargs
+                        private static<T> List<String> toString(T... values) {
+                            List<String> result = new ArrayList<>();
+                            for (T value : values) {
+                                result.add(value.toString());
+                            }
+                            return result;
+                        }
+
+                        public <T> AtomicReference<T> createReference(T content) {
+                            // Language feature: <> on anonymous class
+                            //noinspection unchecked
+                            return new AtomicReference<>(content) { };
+                        }
+
+                        public static byte[] copy(byte[] bytes) throws IOException {
+                            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+                            InputStream inputStream = new ByteArrayInputStream(bytes);
+                            try (inputStream) { // Language feature: try on effectively-final variable
+                                int value;
+                                while ((value = inputStream.read()) != -1) {
+                                    byteArrayOutputStream.write(value);
+                                }
+                            }
+                            return byteArrayOutputStream.toByteArray();
+                        }
+                    }
+                    """
+                )
+            ),
+            api = """
+                package libcore.internal {
+                  public class Java9LanguageFeatures {
+                    ctor public Java9LanguageFeatures();
+                    method public static byte[] copy(byte[]) throws java.io.IOException;
+                    method public <T> java.util.concurrent.atomic.AtomicReference<T> createReference(T);
+                    method public static <T> java.lang.String toListString(T...);
+                  }
+                  public static abstract interface Java9LanguageFeatures.Person {
+                    method public default boolean isPalindrome();
+                    method public default boolean isPalindromeIgnoreCase();
+                    method public abstract java.lang.String name();
+                  }
+                }
+                """,
+            extraArguments = arrayOf("--java-source", "1.9")
+        )
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt b/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt
index 575ad58..2360fb2 100644
--- a/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt
+++ b/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt
@@ -32,7 +32,7 @@
                 java(
                     """
                     package test.pkg;
-                    import android.support.annotation.ParameterName;
+                    import androidx.annotation.ParameterName;
 
                     public class Test {
                         public void fun() { }
@@ -183,14 +183,14 @@
                         }
 
                         @Throws(FileNotFoundException::class)
-                        fun ok_hasThrows(x: Int) {
+                        fun ok_hasThrows1(x: Int) {
                             if (x < 0) {
                                 throw java.io.FileNotFoundException("Something")
                             }
                         }
 
                         @Throws(UnsupportedOperationException::class, FileNotFoundException::class)
-                        fun ok_hasThrows(x: Int) {
+                        fun ok_hasThrows2(x: Int) {
                             if (x < 0) {
                                 throw java.io.FileNotFoundException("Something")
                             }
diff --git a/src/test/java/com/android/tools/metalava/NullnessMigrationTest.kt b/src/test/java/com/android/tools/metalava/NullnessMigrationTest.kt
index c4e25e2..0557168 100644
--- a/src/test/java/com/android/tools/metalava/NullnessMigrationTest.kt
+++ b/src/test/java/com/android/tools/metalava/NullnessMigrationTest.kt
@@ -51,7 +51,7 @@
     }
 
     @Test
-    fun `Method which is now marked null should be marked as newly migrated null`() {
+    fun `Method which is now marked null should be marked as recently migrated null`() {
         check(
             migrateNulls = true,
             outputKotlinStyleNulls = false,
@@ -73,7 +73,7 @@
             api = """
                 package test.pkg {
                   public abstract class MyTest {
-                    method @NewlyNullable public Double convert1(Float);
+                    method @RecentlyNullable public Double convert1(Float);
                   }
                 }
                 """
@@ -81,7 +81,7 @@
     }
 
     @Test
-    fun `Parameter which is now marked null should be marked as newly migrated null`() {
+    fun `Parameter which is now marked null should be marked as recently migrated null`() {
         check(
             migrateNulls = true,
             outputKotlinStyleNulls = false,
@@ -103,7 +103,7 @@
             api = """
                 package test.pkg {
                   public abstract class MyTest {
-                    method public Double convert1(@NewlyNonNull Float);
+                    method public Double convert1(@RecentlyNonNull Float);
                   }
                 }
                 """
@@ -134,7 +134,7 @@
                     ctor public MyTest();
                     method public Double convert0(Float);
                     method public Double convert1(Float);
-                    method @NewlyNullable public Double convert2(@NewlyNonNull Float);
+                    method @RecentlyNullable public Double convert2(@RecentlyNonNull Float);
                     method @RecentlyNullable public Double convert3(@RecentlyNonNull Float);
                     method @Nullable public Double convert4(@NonNull Float);
                   }
@@ -145,8 +145,8 @@
                   public class MyTest {
                     ctor public MyTest();
                     method public Double convert0(Float);
-                    method @NewlyNullable public Double convert1(@NewlyNonNull Float);
-                    method @RecentlyNullable public Double convert2(@RecentlyNonNull Float);
+                    method @RecentlyNullable public Double convert1(@RecentlyNonNull Float);
+                    method @Nullable public Double convert2(@NonNull Float);
                     method @Nullable public Double convert3(@NonNull Float);
                     method @Nullable public Double convert4(@NonNull Float);
                   }
@@ -179,7 +179,7 @@
                     ctor public MyTest();
                     method public Double convert0(Float);
                     method public Double convert1(Float);
-                    method @NewlyNullable public Double convert2(@NewlyNonNull Float);
+                    method @RecentlyNullable public Double convert2(@RecentlyNonNull Float);
                     method @RecentlyNullable public Double convert3(@RecentlyNonNull Float);
                     method @Nullable public Double convert4(@NonNull Float);
                   }
@@ -260,7 +260,7 @@
                 java(
                     """
                     package test.pkg;
-                    import android.support.annotation.Nullable;
+                    import androidx.annotation.Nullable;
                     import java.util.List;
                     public class Test {
                         public @Nullable Integer compute1(@Nullable java.util.List<@Nullable String> list) {
@@ -276,7 +276,7 @@
                 supportNonNullSource,
                 supportNullableSource
             ),
-            extraArguments = arrayOf("--hide-package", "android.support.annotation"),
+            extraArguments = arrayOf("--hide-package", "androidx.annotation"),
             api = """
                 package test.pkg {
                   public class Test {
@@ -288,4 +288,142 @@
                 """
         )
     }
+
+    @Test
+    fun `Check androidx package annotation`() {
+        check(
+            outputKotlinStyleNulls = false,
+            compatibilityMode = false,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    import androidx.annotation.Nullable;
+                    import androidx.annotation.NonNull;
+                    import java.util.List;
+                    public class Test {
+                        public @Nullable Integer compute1(@Nullable java.util.List<@Nullable String> list) {
+                            return 5;
+                        }
+                        public @Nullable Integer compute2(@NonNull java.util.List<@NonNull List<?>> list) {
+                            return 5;
+                        }
+                    }
+                    """
+                ),
+                androidxNonNullSource,
+                androidxNullableSource
+            ),
+            extraArguments = arrayOf("--hide-package", "androidx.annotation"),
+            api = """
+                package test.pkg {
+                  public class Test {
+                    ctor public Test();
+                    method @Nullable public Integer compute1(@Nullable java.util.List<@Nullable java.lang.String>);
+                    method @Nullable public Integer compute2(@NonNull java.util.List<@NonNull java.util.List<?>>);
+                  }
+                }
+                """
+        )
+    }
+
+    @Test
+    fun `Migrate nullness for type-use annotations`() {
+        check(
+            outputKotlinStyleNulls = false,
+            compatibilityMode = false,
+            migrateNulls = true,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    import androidx.annotation.Nullable;
+                    import androidx.annotation.NonNull;
+                    public class Foo {
+                       public static char @NonNull [] toChars(int codePoint) { return new char[0]; }
+                       public static int codePointAt(char @NonNull [] a, int index) { throw new RuntimeException("Stub!"); }
+                       public <T> T @NonNull [] toArray(T @NonNull [] a);
+                    }
+                    """
+                ),
+                androidxNonNullSource,
+                androidxNullableSource
+            ),
+            extraArguments = arrayOf("--hide-package", "androidx.annotation"),
+            // TODO: Handle multiple nullness annotations
+            previousApi =
+            """
+                package test.pkg {
+                  public class Foo {
+                    ctor public Foo();
+                    method public static int codePointAt(char[], int);
+                    method public <T> T[] toArray(T[]);
+                    method public static char[] toChars(int);
+                  }
+                }
+                """,
+            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!"); }
+                }
+                """
+            )
+        )
+    }
+
+    @Test
+    fun `Do not migrate type-use annotations when not changed`() {
+        check(
+            outputKotlinStyleNulls = false,
+            compatibilityMode = false,
+            migrateNulls = true,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    import androidx.annotation.Nullable;
+                    import androidx.annotation.NonNull;
+                    public class Foo {
+                       public static char @NonNull [] toChars(int codePoint) { return new char[0]; }
+                       public static int codePointAt(char @NonNull [] a, int index) { throw new RuntimeException("Stub!"); }
+                       public <T> T @NonNull [] toArray(T @NonNull [] a);
+                    }
+                    """
+                ),
+                androidxNonNullSource,
+                androidxNullableSource
+            ),
+            extraArguments = arrayOf("--hide-package", "androidx.annotation"),
+            // TODO: Handle multiple nullness annotations
+            previousApi =
+            """
+                package test.pkg {
+                  public class Foo {
+                    ctor public Foo();
+                    method public static int codePointAt(char[], int);
+                    method public <T> T[] toArray(T[]);
+                    method public static char[] toChars(int);
+                  }
+                }
+                """,
+            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!"); }
+                }
+                """
+            )
+        )
+    }
 }
\ 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 8adf2af..7c79caa 100644
--- a/src/test/java/com/android/tools/metalava/OptionsTest.kt
+++ b/src/test/java/com/android/tools/metalava/OptionsTest.kt
@@ -53,7 +53,8 @@
                                        when parsing the source files
 --merge-annotations <file>             An external annotations file (using IntelliJ's
                                        external annotations database format) to merge and
-                                       overlay the sources
+                                       overlay the sources. A subset of .jaif files is
+                                       also supported.
 --input-api-jar <file>                 A .jar file to read APIs from directly
 --manifest <file>                      A manifest file, used to for check permissions to
                                        cross check APIs
@@ -62,6 +63,8 @@
 --show-annotation <annotation class>   Include the given annotation in the API analysis
 --show-unannotated                     Include un-annotated public APIs in the signature
                                        file as well
+--java-source <level>                  Sets the source level for Java source files;
+                                       default is 1.8.
 
 Documentation:
 --public                               Only include elements that are public
@@ -76,6 +79,8 @@
 --api <file>                           Generate a signature descriptor file
 --private-api <file>                   Generate a signature descriptor file listing the
                                        exact private APIs
+--dex-api <file>                       Generate a DEX signature descriptor file listing
+                                       the APIs
 --private-dex-api <file>               Generate a DEX signature descriptor file listing
                                        the exact private APIs
 --removed-api <file>                   Generate a signature descriptor file for APIs that
@@ -100,10 +105,31 @@
 
 Generating Stubs:
 --stubs <dir>                          Generate stub source files for the API
+--doc-stubs <dir>                      Generate documentation stub source files for the
+                                       API. Documentation stub files are similar to
+                                       regular stub files, but there are some differences.
+                                       For example, in the stub files, we'll use special
+                                       annotations like @RecentlyNonNull instead of
+                                       @NonNull to indicate that an element is recently
+                                       marked as non null, whereas in the documentation
+                                       stubs we'll just list this as @NonNull. Another
+                                       difference is that @doconly elements are included
+                                       in documentation stubs, but not regular stubs,
+                                       etc.
 --exclude-annotations                  Exclude annotations such as @Nullable from the stub
                                        files
 --write-stubs-source-list <file>       Write the list of generated stub files into the
+                                       given source list file. If generating documentation
+                                       stubs and you haven't also specified
+                                       --write-doc-stubs-source-list, this list will refer
+                                       to the documentation stubs; otherwise it's the
+                                       non-documentation stubs.
+--write-doc-stubs-source-list <file>   Write the list of generated doc stub files into the
                                        given source list file
+--register-artifact <api-file> <id>    Registers the given id for the packages found in
+                                       the given signature file. metalava will inject an
+                                       @artifactId <id> tag into every top level stub
+                                       class in that API.
 
 Diffs and Checks:
 --previous-api <signature file>        A signature file for the previous version of this
@@ -116,6 +142,9 @@
 --check-compatibility                  Check compatibility with the previous API
 --check-kotlin-interop                 Check API intended to be used from both Kotlin and
                                        Java for interoperability issues
+--current-api <signature file>         A signature file for the current version of this
+                                       API to check compatibility with. If not specified,
+                                       --previous-api will be used instead.
 --migrate-nullness                     Compare nullness information with the previous API
                                        and mark newly annotated APIs as under migration.
 --warnings-as-errors                   Promote all warnings to errors
@@ -139,20 +168,14 @@
 --skip-java-in-coverage-report         In the coverage annotation report, skip java.** and
                                        kotlin.** to narrow the focus down to the Android
                                        framework APIs.
+--write-class-coverage-to <path>       Specifies a file to write the annotation coverage
+                                       report for classes to.
+--write-member-coverage-to <path>      Specifies a file to write the annotation coverage
+                                       report for members to.
 
 Extracting Annotations:
---extract-annotations <zipfile>        Extracts annotations from the source files and
-                                       writes them into the given zip file
---api-filter <file>                    Applies the given signature file as a filter (which
-                                       means no classes,methods or fields not found in the
-                                       filter will be included.)
---hide-filtered                        Omit listing APIs that were skipped because of the
-                                       --api-filter
---skip-class-retention                 Do not extract annotations that have class file
-                                       retention
---rmtypedefs                           Delete all the typedef .class files
---typedef-file <file>                  Writes an typedef annotation class names into the
-                                       given file
+--extract-annotations <zipfile>        Extracts source annotations from the source files
+                                       and writes them into the given zip file
 
 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/ShowAnnotationTest.kt b/src/test/java/com/android/tools/metalava/ShowAnnotationTest.kt
index 37e3c68..e66c35d 100644
--- a/src/test/java/com/android/tools/metalava/ShowAnnotationTest.kt
+++ b/src/test/java/com/android/tools/metalava/ShowAnnotationTest.kt
@@ -124,4 +124,43 @@
                 """
         )
     }
+
+    @Test
+    fun `Check @TestApi handling`() {
+        check(
+            includeSystemApiAnnotations = true,
+            checkDoclava1 = true,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    import android.annotation.TestApi;
+
+                    /**
+                     * Blah blah blah
+                     * @hide
+                     */
+                    @TestApi
+                    public class Bar {
+                    }
+                    """
+                ),
+                testApiSource
+            ),
+
+            extraArguments = arrayOf(
+                "--show-annotation", "android.annotation.TestApi",
+                "--hide-package", "android.annotation",
+                "--hide-package", "android.support.annotation"
+            ),
+
+            api = """
+                package test.pkg {
+                  public class Bar {
+                    ctor public Bar();
+                  }
+                }
+                """
+        )
+    }
 }
\ 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 71d35fb..5d7f7df 100644
--- a/src/test/java/com/android/tools/metalava/StubsTest.kt
+++ b/src/test/java/com/android/tools/metalava/StubsTest.kt
@@ -34,17 +34,21 @@
         checkDoclava1: Boolean = false,
         api: String? = null,
         extraArguments: Array<String> = emptyArray(),
+        docStubs: Boolean = false,
+        showAnnotations: Array<String> = emptyArray(),
         vararg sourceFiles: TestFile
     ) {
         check(
             *sourceFiles,
+            showAnnotations = showAnnotations,
             stubs = arrayOf(source),
             compatibilityMode = compatibilityMode,
             warnings = warnings,
             checkDoclava1 = checkDoclava1,
             checkCompilation = true,
             api = api,
-            extraArguments = extraArguments
+            extraArguments = extraArguments,
+            docStubs = docStubs
         )
     }
 
@@ -711,7 +715,7 @@
         checkStubs(
             // Note that doclava1 includes fields here that it doesn't include in the
             // signature file.
-            //checkDoclava1 = true,
+            // checkDoclava1 = true,
             compatibilityMode = false,
             sourceFiles =
             *arrayOf(
@@ -1041,7 +1045,7 @@
                      * @param size Value is between 0 and (1 << MeasureSpec.MODE_SHIFT) - 1 inclusive
                      * @param mode Value is {@link android.view.View.View.MeasureSpec#UNSPECIFIED}, {@link android.view.View.View.MeasureSpec#EXACTLY}, or {@link android.view.View.View.MeasureSpec#AT_MOST}
                      */
-                    public static int makeMeasureSpec(@android.support.annotation.IntRange(from=0, to=0x40000000 - 1) int size, int mode) { throw new RuntimeException("Stub!"); }
+                    public static int makeMeasureSpec(@androidx.annotation.IntRange(from=0, to=0x40000000 - 1) int size, int mode) { throw new RuntimeException("Stub!"); }
                     public static final int AT_MOST = -2147483648; // 0x80000000
                     public static final int EXACTLY = 1073741824; // 0x40000000
                     public static final int UNSPECIFIED = 0; // 0x0
@@ -1127,7 +1131,7 @@
                     /**
                      * Requires {@link android.Manifest.permission#INTERACT_ACROSS_USERS} and {@link android.Manifest.permission#BROADCAST_STICKY}
                      */
-                    @android.support.annotation.RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcast(@android.support.annotation.RequiresPermission java.lang.Object intent);
+                    @androidx.annotation.RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcast(@androidx.annotation.RequiresPermission java.lang.Object intent);
                     }
                 """
         )
@@ -1260,15 +1264,15 @@
                     /** My class doc */
                     @SuppressWarnings({"unchecked", "deprecation", "all"})
                     public final class Kotlin extends test.pkg.Parent {
-                    public Kotlin(@android.support.annotation.NonNull java.lang.String property1, int arg2) { throw new RuntimeException("Stub!"); }
-                    @android.support.annotation.NonNull public java.lang.String method() { throw new RuntimeException("Stub!"); }
+                    public Kotlin(@androidx.annotation.NonNull java.lang.String property1, int arg2) { throw new RuntimeException("Stub!"); }
+                    @androidx.annotation.NonNull public java.lang.String method() { throw new RuntimeException("Stub!"); }
                     /** My method doc */
                     public void otherMethod(boolean ok, int times) { throw new RuntimeException("Stub!"); }
                     /** property doc */
-                    @android.support.annotation.Nullable public java.lang.String getProperty2() { throw new RuntimeException("Stub!"); }
+                    @androidx.annotation.Nullable public java.lang.String getProperty2() { throw new RuntimeException("Stub!"); }
                     /** property doc */
-                    public void setProperty2(@android.support.annotation.Nullable java.lang.String p) { throw new RuntimeException("Stub!"); }
-                    @android.support.annotation.NonNull public java.lang.String getProperty1() { throw new RuntimeException("Stub!"); }
+                    public void setProperty2(@androidx.annotation.Nullable java.lang.String p) { throw new RuntimeException("Stub!"); }
+                    @androidx.annotation.NonNull public java.lang.String getProperty1() { throw new RuntimeException("Stub!"); }
                     public int someField2;
                     }
                 """,
@@ -1285,7 +1289,7 @@
                 java(
                     """
                     package test.pkg;
-                    import android.support.annotation.ParameterName;
+                    import androidx.annotation.ParameterName;
 
                     public class Foo {
                         public void foo(int javaParameter1, @ParameterName("publicParameterName") int javaParameter2) {
@@ -1442,12 +1446,94 @@
         )
     }
 
+    @Test
+    fun `Arguments to super constructors with showAnnotations`() {
+        // When overriding constructors we have to supply arguments
+        checkStubs(
+            showAnnotations = arrayOf("android.annotation.SystemApi"),
+            sourceFiles =
+            *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+
+                    @SuppressWarnings("WeakerAccess")
+                    public class Constructors {
+                        public class Parent {
+                            public Parent(String s, int i, long l, boolean b, short sh) {
+                            }
+                        }
+
+                        public class Child extends Parent {
+                            public Child(String s, int i, long l, boolean b, short sh) {
+                                super(s, i, l, b, sh);
+                            }
+
+                            private Child(String s) {
+                                super(s, 0, 0, false, 0);
+                            }
+                        }
+
+                        public class Child2 extends Parent {
+                            Child2(String s) {
+                                super(s, 0, 0, false, 0);
+                            }
+                        }
+
+                        public class Child3 extends Child2 {
+                            private Child3(String s) {
+                                super("something");
+                            }
+                        }
+
+                        public class Child4 extends Parent {
+                            Child4(String s, HiddenClass hidden) {
+                                super(s, 0, 0, true, 0);
+                            }
+                        }
+                        /** @hide */
+                        public class HiddenClass {
+                        }
+                    }
+                    """
+                )
+            ),
+            source = """
+                    package test.pkg;
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class Constructors {
+                    public Constructors() { throw new RuntimeException("Stub!"); }
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class Child extends test.pkg.Constructors.Parent {
+                    public Child(java.lang.String s, int i, long l, boolean b, short sh) { super(null, 0, 0, false, (short)0); throw new RuntimeException("Stub!"); }
+                    }
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class Child2 extends test.pkg.Constructors.Parent {
+                    Child2(java.lang.String s) { super(null, 0, 0, false, (short)0); throw new RuntimeException("Stub!"); }
+                    }
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class Child3 extends test.pkg.Constructors.Child2 {
+                    Child3(java.lang.String s) { super(null); throw new RuntimeException("Stub!"); }
+                    }
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class Child4 extends test.pkg.Constructors.Parent {
+                    Child4() { super(null, 0, 0, false, (short)0); throw new RuntimeException("Stub!"); }
+                    }
+                    @SuppressWarnings({"unchecked", "deprecation", "all"})
+                    public class Parent {
+                    public Parent(java.lang.String s, int i, long l, boolean b, short sh) { throw new RuntimeException("Stub!"); }
+                    }
+                    }
+                    """
+        )
+    }
+
     // TODO: Add test to see what happens if I have Child4 in a different package which can't access the package private constructor of child3?
 
     @Test
     fun `DocOnly members should be omitted`() {
         // When marked @doconly don't include in stubs or signature files
-        // unless specifically asked for (which we do when generating docs).
+        // unless specifically asked for (which we do when generating docs-stubs).
         checkStubs(
             sourceFiles =
             *arrayOf(
@@ -1502,7 +1588,7 @@
         // When marked @doconly don't include in stubs or signature files
         // unless specifically asked for (which we do when generating docs).
         checkStubs(
-            extraArguments = arrayOf("--include-doconly"),
+            docStubs = true,
             sourceFiles =
             *arrayOf(
                 java(
@@ -1665,9 +1751,9 @@
             sourceFiles = *arrayOf(
                 java(
                     "package my.pkg;\n" +
-                            "public class String {\n" +
-                            "public String(char @libcore.util.NonNull [] value) { throw new RuntimeException(\"Stub!\"); }\n" +
-                            "}\n"
+                        "public class String {\n" +
+                        "public String(char @libcore.util.NonNull [] value) { throw new RuntimeException(\"Stub!\"); }\n" +
+                        "}\n"
                 )
             ),
             warnings = "",
@@ -1683,7 +1769,7 @@
                 package my.pkg;
                 @SuppressWarnings({"unchecked", "deprecation", "all"})
                 public class String {
-                public String(char @android.support.annotation.NonNull [] value) { throw new RuntimeException("Stub!"); }
+                public String(char @androidx.annotation.NonNull [] value) { throw new RuntimeException("Stub!"); }
                 }
                 """
             )
@@ -1865,6 +1951,7 @@
     @Test
     fun `Rewriting type parameters in interfaces from hidden super classes and in throws lists`() {
         checkStubs(
+            extraArguments = arrayOf("--skip-inherited-methods=false"),
             checkDoclava1 = false,
             sourceFiles =
             *arrayOf(
@@ -1914,7 +2001,7 @@
                       }
                       public class Generics.MyClass<X, Y extends java.lang.Number> extends test.pkg.Generics.PublicParent implements test.pkg.Generics.PublicInterface {
                         ctor public Generics.MyClass();
-                        method public java.util.Map<X, java.util.Map<Y, java.lang.String>> createMap(java.util.List<X>);
+                        method public java.util.Map<X, java.util.Map<Y, java.lang.String>> createMap(java.util.List<X>) throws test.pkg.Generics.MyThrowable;
                         method public java.util.List<X> foo();
                       }
                       public static abstract interface Generics.PublicInterface<A, B> {
@@ -1935,7 +2022,98 @@
                     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) { 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();
+                    }
+                    }
+                    """
+        )
+    }
+
+    @Test
+    fun `Picking super class throwables`() {
+        // Like previous test, but without compatibility mode: ensures that we
+        // use super classes of filtered throwables
+        checkStubs(
+            compatibilityMode = false,
+            sourceFiles =
+            *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+
+                    import java.io.IOException;
+                    import java.util.List;
+                    import java.util.Map;
+
+                    @SuppressWarnings({"RedundantThrows", "WeakerAccess"})
+                    public class Generics {
+                        public class MyClass<X, Y extends Number> extends HiddenParent<X, Y> implements PublicInterface<X, Y> {
+                        }
+
+                        class HiddenParent<M, N extends Number> extends PublicParent<M, N> {
+                            public Map<M, Map<N, String>> createMap(List<M> list) throws MyThrowable {
+                                return null;
+                            }
+
+                            protected List<M> foo() {
+                                return null;
+                            }
+
+                        }
+
+                        class MyThrowable extends IOException {
+                        }
+
+                        public abstract class PublicParent<A, B extends Number> {
+                            protected abstract List<A> foo();
+                        }
+
+                        public interface PublicInterface<A, B> {
+                            Map<A, Map<B, String>> createMap(List<A> list) throws IOException;
+                        }
+                    }
+                    """
+                )
+            ),
+            warnings = "",
+            api = """
+                package test.pkg {
+                  public class Generics {
+                    ctor public Generics();
+                  }
+                  public class Generics.MyClass<X, Y extends java.lang.Number> extends test.pkg.Generics.PublicParent<X,Y> implements test.pkg.Generics.PublicInterface<X,Y> {
+                    ctor public Generics.MyClass();
+                    method public java.util.Map<X,java.util.Map<Y,java.lang.String>>! createMap(java.util.List<X>!) throws java.io.IOException;
+                    method public java.util.List<X>! foo();
+                  }
+                  public static interface Generics.PublicInterface<A, B> {
+                    method public java.util.Map<A,java.util.Map<B,java.lang.String>>! createMap(java.util.List<A>!) throws java.io.IOException;
+                  }
+                  public abstract class Generics.PublicParent<A, B extends java.lang.Number> {
+                    ctor public Generics.PublicParent();
+                    method protected abstract java.util.List<A>! foo();
+                  }
+                }
+                    """,
+            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> {
@@ -1955,6 +2133,7 @@
     fun `Rewriting implements class references`() {
         // Checks some more subtle bugs around generics type variable renaming
         checkStubs(
+            extraArguments = arrayOf("--skip-inherited-methods=false"),
             checkDoclava1 = false,
             sourceFiles =
             *arrayOf(
@@ -2073,6 +2252,7 @@
                     import android.util.AttributeSet;
                     import org.xmlpull.v1.XmlPullParser;
 
+                    @SuppressWarnings("UnnecessaryInterfaceModifier")
                     public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable {
                         public void close();
                     }
@@ -2170,9 +2350,11 @@
                             public abstract FileDescriptor getFileDescriptor();
                         }
 
+                        @SuppressWarnings("UnnecessaryInterfaceModifier")
                         public static interface Closeable extends AutoCloseable {
                         }
 
+                        @SuppressWarnings("UnnecessaryInterfaceModifier")
                         public static interface AutoCloseable {
                         }
 
@@ -2783,7 +2965,7 @@
             *arrayOf(
                 java(
                     """
-                    @android.support.annotation.Nullable
+                    @androidx.annotation.Nullable
                     package test.pkg;
                     """
                 ),
@@ -2808,10 +2990,10 @@
                 }
             """, // WRONG: I should include package annotations!
             source = """
-                @android.support.annotation.Nullable
+                @androidx.annotation.Nullable
                 package test.pkg;
                 """,
-            extraArguments = arrayOf("--hide-package", "android.support.annotation")
+            extraArguments = arrayOf("--hide-package", "androidx.annotation")
         )
     }
 
diff --git a/src/test/java/com/android/tools/metalava/SystemServiceCheckTest.kt b/src/test/java/com/android/tools/metalava/SystemServiceCheckTest.kt
index 2c8fb78..de29f8f 100644
--- a/src/test/java/com/android/tools/metalava/SystemServiceCheckTest.kt
+++ b/src/test/java/com/android/tools/metalava/SystemServiceCheckTest.kt
@@ -221,8 +221,8 @@
     fun `Check SystemService -- must be system permission, not normal`() {
         check(
             warnings = "src/test/pkg/MyTest2.java:6: lint: Method 'test' must be protected with a system " +
-                    "permission; it currently allows non-system callers holding [foo.bar.PERMISSION1, " +
-                    "foo.bar.PERMISSION2] [RequiresPermission:125]",
+                "permission; it currently allows non-system callers holding [foo.bar.PERMISSION1, " +
+                "foo.bar.PERMISSION2] [RequiresPermission:125]",
             compatibilityMode = false,
             includeSystemApiAnnotations = true,
             sourceFiles = *arrayOf(
diff --git a/src/test/java/com/android/tools/metalava/apilevels/ApiGeneratorTest.kt b/src/test/java/com/android/tools/metalava/apilevels/ApiGeneratorTest.kt
index 778408e..8ea2750 100644
--- a/src/test/java/com/android/tools/metalava/apilevels/ApiGeneratorTest.kt
+++ b/src/test/java/com/android/tools/metalava/apilevels/ApiGeneratorTest.kt
@@ -51,7 +51,7 @@
                 "--android-jar-pattern",
                 "${oldSdkJars.path}/android-%/android.jar",
                 "--android-jar-pattern",
-                "${platformJars.path}/%/android.jar"
+                "${platformJars.path}/%/public/android.jar"
             ),
             checkDoclava1 = false,
             signatureSource = """
@@ -75,7 +75,5 @@
 
         val document = XmlUtils.parseDocumentSilently(xml, false)
         assertNotNull(document)
-
     }
-
-}
\ No newline at end of file
+}
diff --git a/src/test/java/com/android/tools/metalava/model/TextBackedAnnotationItemTest.kt b/src/test/java/com/android/tools/metalava/model/TextBackedAnnotationItemTest.kt
index cc4e121..f3c367a 100644
--- a/src/test/java/com/android/tools/metalava/model/TextBackedAnnotationItemTest.kt
+++ b/src/test/java/com/android/tools/metalava/model/TextBackedAnnotationItemTest.kt
@@ -41,10 +41,10 @@
     fun testSimple() {
         val annotation = TextBackedAnnotationItem(
             dummyCodebase,
-            "@android.support.annotation.Nullable"
+            "@androidx.annotation.Nullable"
         )
-        assertEquals("@android.support.annotation.Nullable", annotation.toSource())
-        assertEquals("android.support.annotation.Nullable", annotation.qualifiedName())
+        assertEquals("@androidx.annotation.Nullable", annotation.toSource())
+        assertEquals("androidx.annotation.Nullable", annotation.qualifiedName())
         assertTrue(annotation.attributes().isEmpty())
     }
 
@@ -52,10 +52,10 @@
     fun testIntRange() {
         val annotation = TextBackedAnnotationItem(
             dummyCodebase,
-            "@android.support.annotation.IntRange(from = 20, to = 40)"
+            "@androidx.annotation.IntRange(from = 20, to = 40)"
         )
-        assertEquals("@android.support.annotation.IntRange(from = 20, to = 40)", annotation.toSource())
-        assertEquals("android.support.annotation.IntRange", annotation.qualifiedName())
+        assertEquals("@androidx.annotation.IntRange(from = 20, to = 40)", annotation.toSource())
+        assertEquals("androidx.annotation.IntRange", annotation.qualifiedName())
         assertEquals(2, annotation.attributes().size)
         assertEquals("from", annotation.findAttribute("from")?.name)
         assertEquals("20", annotation.findAttribute("from")?.value.toString())
@@ -67,13 +67,13 @@
     fun testIntDef() {
         val annotation = TextBackedAnnotationItem(
             dummyCodebase,
-            "@android.support.annotation.IntDef({STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT})"
+            "@androidx.annotation.IntDef({STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT})"
         )
         assertEquals(
-            "@android.support.annotation.IntDef({STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT})",
+            "@androidx.annotation.IntDef({STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT})",
             annotation.toSource()
         )
-        assertEquals("android.support.annotation.IntDef", annotation.qualifiedName())
+        assertEquals("androidx.annotation.IntDef", annotation.qualifiedName())
         assertEquals(1, annotation.attributes().size)
         val attribute = annotation.findAttribute("value")
         assertNotNull(attribute)
diff --git a/stub-annotations/.gitignore b/stub-annotations/.gitignore
new file mode 100644
index 0000000..dd06f84
--- /dev/null
+++ b/stub-annotations/.gitignore
@@ -0,0 +1,8 @@
+*.iml
+.gradle
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/runConfigurations
+/out
+/build
diff --git a/stub-annotations/README.md b/stub-annotations/README.md
new file mode 100644
index 0000000..29d6921
--- /dev/null
+++ b/stub-annotations/README.md
@@ -0,0 +1,39 @@
+Stub Annotations
+
+The annotations in these packages are used to compile
+the stubs. They are mostly identical to the annotations
+in the support library, but
+
+(1) There are some annotations here which are not in
+   the support library, such as @RecentlyNullable and
+   @RecentlyNonNull. These are used *only* in the stubs
+   to automatically mark code as recently annotated
+   with null/non-null. We do *not* want these annotations
+   in the source code; the recent-ness is computed at
+   build time and injected into the stubs in place
+   of the normal null annotations.
+
+(2) There are some annotations in the support library
+   that do not apply here, such as @Keep,
+   @VisibleForTesting, etc.
+
+(3) Only class retention annotations are interesting for
+   the stubs; that means for example that we don't
+   include @IntDef and @StringDef.
+
+(4) We've tweaked the retention of some of the support
+   library annotations; some of them were accidentally
+   source retention, and here they are class retention.
+
+(5) We've tweaked the nullness annotations to include
+   TYPE_PARAMETER and TYPE_USE targets, and removed
+   package, local variable, annotation type, etc.
+
+(6) There are some other differences; for example, the
+   @RequiresPermission annotation here has an extra
+   "apis" field used for merged historical annotations
+   to express the applicable API range.
+
+Essentially, this is a curated list of exactly the
+set of annotations we allow injected into the stubs.
+
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNullable.java b/stub-annotations/src/main/java/android/support/annotation/NewlyNullable.java
deleted file mode 100644
index e11fe4f..0000000
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNullable.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 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 android.support.annotation;
-
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-@Documented
-@Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNullable {
-}
diff --git a/stub-annotations/src/main/java/android/support/annotation/RecentlyNonNull.java b/stub-annotations/src/main/java/android/support/annotation/RecentlyNonNull.java
deleted file mode 100644
index d2309fc..0000000
--- a/stub-annotations/src/main/java/android/support/annotation/RecentlyNonNull.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 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 android.support.annotation;
-
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-@Documented
-@Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface RecentlyNonNull {
-}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/AnimRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/AnimRes.java
index 83f4e5a..952fcf4 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/AnimRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface AnimRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/AnimatorRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/AnimatorRes.java
index 83f4e5a..6918e9a 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/AnimatorRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface AnimatorRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/AnyRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/AnyRes.java
index 83f4e5a..84d6177 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/AnyRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface AnyRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/AnyThread.java
similarity index 62%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/AnyThread.java
index 83f4e5a..ab4eddc 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/AnyThread.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, CONSTRUCTOR, TYPE, PARAMETER})
+public @interface AnyThread {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/ArrayRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/ArrayRes.java
index 83f4e5a..90a4c29 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/ArrayRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface ArrayRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/AttrRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/AttrRes.java
index 83f4e5a..296e9e9 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/AttrRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface AttrRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/BinderThread.java
similarity index 62%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/BinderThread.java
index 83f4e5a..246e092 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/BinderThread.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, CONSTRUCTOR, TYPE, PARAMETER})
+public @interface BinderThread {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/BoolRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/BoolRes.java
index 83f4e5a..ec44e6e 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/BoolRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface BoolRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/Migrate.java b/stub-annotations/src/main/java/androidx/annotation/CallSuper.java
similarity index 72%
rename from stub-annotations/src/main/java/android/support/annotation/Migrate.java
rename to stub-annotations/src/main/java/androidx/annotation/CallSuper.java
index 233ce52..d099272 100644
--- a/stub-annotations/src/main/java/android/support/annotation/Migrate.java
+++ b/stub-annotations/src/main/java/androidx/annotation/CallSuper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({ANNOTATION_TYPE})
-public @interface Migrate {
-}
+@Target({METHOD})
+public @interface CallSuper {}
diff --git a/stub-annotations/src/main/java/androidx/annotation/CheckResult.java b/stub-annotations/src/main/java/androidx/annotation/CheckResult.java
new file mode 100644
index 0000000..f96c750
--- /dev/null
+++ b/stub-annotations/src/main/java/androidx/annotation/CheckResult.java
@@ -0,0 +1,45 @@
+/*
+ * 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})
+public @interface CheckResult {
+    /**
+     * Defines the name of the suggested method to use instead, if applicable (using the same
+     * signature format as javadoc.) If there is more than one possibility, list them all separated
+     * by commas.
+     *
+     * <p>For example, ProcessBuilder has a method named {@code redirectErrorStream()} which sounds
+     * like it might redirect the error stream. It does not. It's just a getter which returns
+     * whether the process builder will redirect the error stream, and to actually set it, you must
+     * call {@code redirectErrorStream(boolean)}. In that case, the method should be defined like
+     * this:
+     *
+     * <pre>
+     *  &#64;CheckResult(suggest="#redirectErrorStream(boolean)")
+     *  public boolean redirectErrorStream() { ... }
+     * </pre>
+     */
+    String suggest() default "";
+}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/ColorInt.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/ColorInt.java
index 83f4e5a..f6972dd 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/ColorInt.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
+public @interface ColorInt {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/RecentlyNullable.java b/stub-annotations/src/main/java/androidx/annotation/ColorLong.java
similarity index 74%
copy from stub-annotations/src/main/java/android/support/annotation/RecentlyNullable.java
copy to stub-annotations/src/main/java/androidx/annotation/ColorLong.java
index d24bad0..46937da 100644
--- a/stub-annotations/src/main/java/android/support/annotation/RecentlyNullable.java
+++ b/stub-annotations/src/main/java/androidx/annotation/ColorLong.java
@@ -13,23 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+package androidx.annotation;
+
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface RecentlyNullable {
-}
+@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
+public @interface ColorLong {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/ColorRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/ColorRes.java
index 83f4e5a..558f4ef 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/ColorRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface ColorRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/DimenRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/DimenRes.java
index 83f4e5a..95f9a7d 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/DimenRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface DimenRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/Dimension.java
similarity index 80%
rename from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
rename to stub-annotations/src/main/java/androidx/annotation/Dimension.java
index 83f4e5a..64defe8 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/Dimension.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -13,23 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+
+package androidx.annotation;
 
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE})
+public @interface Dimension {
+    int unit() default PX;
+
+    int DP = 0;
+    int PX = 1;
+    int SP = 2;
 }
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/DrawableRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/DrawableRes.java
index 83f4e5a..92ac640 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/DrawableRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface DrawableRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/FloatRange.java
similarity index 61%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/FloatRange.java
index 83f4e5a..7cb2856 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/FloatRange.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,23 +13,30 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE})
+public @interface FloatRange {
+    /** Smallest value. Whether it is inclusive or not is determined by {@link #fromInclusive} */
+    double from() default Double.NEGATIVE_INFINITY;
+    /** Largest value. Whether it is inclusive or not is determined by {@link #toInclusive} */
+    double to() default Double.POSITIVE_INFINITY;
+
+    /** Whether the from value is included in the range */
+    boolean fromInclusive() default true;
+
+    /** Whether the to value is included in the range */
+    boolean toInclusive() default true;
 }
diff --git a/stub-annotations/src/main/java/android/support/annotation/RecentlyNullable.java b/stub-annotations/src/main/java/androidx/annotation/FontRes.java
similarity index 74%
rename from stub-annotations/src/main/java/android/support/annotation/RecentlyNullable.java
rename to stub-annotations/src/main/java/androidx/annotation/FontRes.java
index d24bad0..0ebca72 100644
--- a/stub-annotations/src/main/java/android/support/annotation/RecentlyNullable.java
+++ b/stub-annotations/src/main/java/androidx/annotation/FontRes.java
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface RecentlyNullable {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface FontRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/FractionRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/FractionRes.java
index 83f4e5a..98ec534 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/FractionRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface FractionRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/HalfFloat.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/HalfFloat.java
index 83f4e5a..a239a82 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/HalfFloat.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
+public @interface HalfFloat {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/IdRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/IdRes.java
index 83f4e5a..0ba2072 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/IdRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface IdRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/IntRange.java
similarity index 76%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/IntRange.java
index 83f4e5a..e37b5cc 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/IntRange.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,23 +13,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE})
+public @interface IntRange {
+    /** Smallest value, inclusive */
+    long from() default Long.MIN_VALUE;
+    /** Largest value, inclusive */
+    long to() default Long.MAX_VALUE;
 }
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/IntegerRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/IntegerRes.java
index 83f4e5a..7ab05ea 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/IntegerRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface IntegerRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/InterpolatorRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/InterpolatorRes.java
index 83f4e5a..f8862f9 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/InterpolatorRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface InterpolatorRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/LayoutRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/LayoutRes.java
index 83f4e5a..a3ed0c8 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/LayoutRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface LayoutRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/MainThread.java
similarity index 62%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/MainThread.java
index 83f4e5a..d8a5e60 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/MainThread.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, CONSTRUCTOR, TYPE, PARAMETER})
+public @interface MainThread {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/MenuRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/MenuRes.java
index 83f4e5a..b7914f2 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/MenuRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface MenuRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/RecentlyNullable.java b/stub-annotations/src/main/java/androidx/annotation/NavigationRes.java
similarity index 74%
copy from stub-annotations/src/main/java/android/support/annotation/RecentlyNullable.java
copy to stub-annotations/src/main/java/androidx/annotation/NavigationRes.java
index d24bad0..b964de0 100644
--- a/stub-annotations/src/main/java/android/support/annotation/RecentlyNullable.java
+++ b/stub-annotations/src/main/java/androidx/annotation/NavigationRes.java
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface RecentlyNullable {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface NavigationRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/NonNull.java
similarity index 74%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/NonNull.java
index 83f4e5a..3b41cc8 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/NonNull.java
@@ -13,23 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE_PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, PACKAGE, TYPE_PARAMETER, TYPE_USE})
+public @interface NonNull {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/Nullable.java
similarity index 74%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/Nullable.java
index 83f4e5a..0e6abce 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/Nullable.java
@@ -13,23 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, PACKAGE, TYPE_PARAMETER, TYPE_USE})
+public @interface Nullable {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/PluralsRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/PluralsRes.java
index 83f4e5a..f2741cb 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/PluralsRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface PluralsRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/Px.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/Px.java
index 83f4e5a..5f8f2ff 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/Px.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -13,23 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+@Dimension(unit = Dimension.PX)
+public @interface Px {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/RawRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/RawRes.java
index 83f4e5a..af874df 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/RawRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface RawRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/RecentlyNonNull.java
similarity index 66%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/RecentlyNonNull.java
index 83f4e5a..575b3eb 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/RecentlyNonNull.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, TYPE_USE})
+public @interface RecentlyNonNull {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/RecentlyNullable.java
similarity index 66%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/RecentlyNullable.java
index 83f4e5a..8a9141e 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/RecentlyNullable.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, TYPE_USE})
+public @interface RecentlyNullable {}
diff --git a/stub-annotations/src/main/java/androidx/annotation/RequiresApi.java b/stub-annotations/src/main/java/androidx/annotation/RequiresApi.java
new file mode 100644
index 0000000..f8824b3
--- /dev/null
+++ b/stub-annotations/src/main/java/androidx/annotation/RequiresApi.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 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.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+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({TYPE, METHOD, CONSTRUCTOR, FIELD})
+public @interface RequiresApi {
+    /**
+     * The API level to require. Alias for {@link #api} which allows you to leave out the {@code
+     * api=} part.
+     */
+    @IntRange(from = 1)
+    int value() default 1;
+
+    /** The API level to require */
+    @IntRange(from = 1)
+    int api() default 1;
+}
diff --git a/stub-annotations/src/main/java/androidx/annotation/RequiresFeature.java b/stub-annotations/src/main/java/androidx/annotation/RequiresFeature.java
new file mode 100644
index 0000000..8ca1352
--- /dev/null
+++ b/stub-annotations/src/main/java/androidx/annotation/RequiresFeature.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 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 androidx.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+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({TYPE, FIELD, METHOD, CONSTRUCTOR})
+public @interface RequiresFeature {
+    /** The name of the feature that is required. */
+    String name();
+
+    /**
+     * Defines the name of the method that should be called to check whether the feature is
+     * available, using the same signature format as javadoc. The feature checking method can have
+     * multiple parameters, but the feature name parameter must be of type String and must also be
+     * the first String-type parameter.
+     */
+    String enforcement();
+}
diff --git a/stub-annotations/src/main/java/androidx/annotation/RequiresPermission.java b/stub-annotations/src/main/java/androidx/annotation/RequiresPermission.java
new file mode 100644
index 0000000..74f37e3
--- /dev/null
+++ b/stub-annotations/src/main/java/androidx/annotation/RequiresPermission.java
@@ -0,0 +1,89 @@
+/*
+ * 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 java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+/** Stub only annotation. Do not use directly. */
+@Retention(CLASS)
+@Target({ANNOTATION_TYPE, METHOD, CONSTRUCTOR, FIELD, PARAMETER})
+public @interface RequiresPermission {
+    /**
+     * The name of the permission that is required, if precisely one permission is required. If more
+     * than one permission is required, specify either {@link #allOf()} or {@link #anyOf()} instead.
+     *
+     * <p>If specified, {@link #anyOf()} and {@link #allOf()} must both be null.
+     */
+    String value() default "";
+
+    /**
+     * Specifies a list of permission names that are all required.
+     *
+     * <p>If specified, {@link #anyOf()} and {@link #value()} must both be null.
+     */
+    String[] allOf() default {};
+
+    /**
+     * Specifies a list of permission names where at least one is required
+     *
+     * <p>If specified, {@link #allOf()} and {@link #value()} must both be null.
+     */
+    String[] anyOf() default {};
+
+    /**
+     * If true, the permission may not be required in all cases (e.g. it may only be enforced on
+     * certain platforms, or for certain call parameters, etc.
+     */
+    boolean conditional() default false;
+
+    // STUBS ONLY: historical API range for when this permission applies.
+    // Used for merged annotations.
+    String apis() default "";
+
+    /**
+     * Specifies that the given permission is required for read operations.
+     *
+     * <p>When specified on a parameter, the annotation indicates that the method requires a
+     * permission which depends on the value of the parameter (and typically the corresponding field
+     * passed in will be one of a set of constants which have been annotated with a
+     * {@code @RequiresPermission} annotation.)
+     */
+    @Target({FIELD, METHOD, PARAMETER})
+    @interface Read {
+        RequiresPermission value() default @RequiresPermission;
+    }
+
+    /**
+     * Specifies that the given permission is required for write operations.
+     *
+     * <p>When specified on a parameter, the annotation indicates that the method requires a
+     * permission which depends on the value of the parameter (and typically the corresponding field
+     * passed in will be one of a set of constants which have been annotated with a
+     * {@code @RequiresPermission} annotation.)
+     */
+    @Target({FIELD, METHOD, PARAMETER})
+    @interface Write {
+        RequiresPermission value() default @RequiresPermission;
+    }
+}
diff --git a/stub-annotations/src/main/java/androidx/annotation/RestrictTo.java b/stub-annotations/src/main/java/androidx/annotation/RestrictTo.java
new file mode 100644
index 0000000..51ebdbd
--- /dev/null
+++ b/stub-annotations/src/main/java/androidx/annotation/RestrictTo.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+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({ANNOTATION_TYPE, TYPE, METHOD, CONSTRUCTOR, FIELD, PACKAGE})
+public @interface RestrictTo {
+
+    /** The scope to which usage should be restricted. */
+    Scope[] value();
+
+    enum Scope {
+        /**
+         * Restrict usage to code within the same library (e.g. the same gradle group ID and
+         * artifact ID).
+         */
+        LIBRARY,
+
+        /**
+         * Restrict usage to code within the same group of libraries. This corresponds to the gradle
+         * group ID.
+         */
+        LIBRARY_GROUP,
+
+        /**
+         * Restrict usage to code within the same group ID (based on gradle group ID). This is an
+         * alias for {@link #LIBRARY_GROUP}.
+         *
+         * @deprecated Use {@link #LIBRARY_GROUP} instead
+         */
+        @Deprecated
+        GROUP_ID,
+
+        /** Restrict usage to tests. */
+        TESTS,
+
+        /**
+         * Restrict usage to subclasses of the enclosing class.
+         *
+         * <p><strong>Note:</strong> This scope should not be used to annotate packages.
+         */
+        SUBCLASSES,
+    }
+}
diff --git a/stub-annotations/src/main/java/androidx/annotation/Size.java b/stub-annotations/src/main/java/androidx/annotation/Size.java
new file mode 100644
index 0000000..412a9ca
--- /dev/null
+++ b/stub-annotations/src/main/java/androidx/annotation/Size.java
@@ -0,0 +1,44 @@
+/*
+ * 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.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+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({PARAMETER, LOCAL_VARIABLE, METHOD, FIELD, ANNOTATION_TYPE})
+public @interface Size {
+    /** An exact size (or -1 if not specified) */
+    long value() default -1;
+    /** A minimum size, inclusive */
+    long min() default Long.MIN_VALUE;
+    /** A maximum size, inclusive */
+    long max() default Long.MAX_VALUE;
+    /** The size must be a multiple of this factor */
+    long multiple() default 1;
+
+    // STUBS ONLY: historical API range for when this permission applies.
+    // Used for merged annotations.
+    String apis() default "";
+}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/StringRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/StringRes.java
index 83f4e5a..ecb78b7 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/StringRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface StringRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/StyleRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/StyleRes.java
index 83f4e5a..d257f99 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/StyleRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface StyleRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/StyleableRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/StyleableRes.java
index 83f4e5a..4d780c0 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/StyleableRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface StyleableRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/TransitionRes.java
similarity index 66%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/TransitionRes.java
index 83f4e5a..f1c0e34 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/TransitionRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,23 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD})
+public @interface TransitionRes {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/UiThread.java
similarity index 62%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/UiThread.java
index 83f4e5a..bdcf721 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/UiThread.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, CONSTRUCTOR, TYPE, PARAMETER})
+public @interface UiThread {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/WorkerThread.java
similarity index 62%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/WorkerThread.java
index 83f4e5a..dbb11a5 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/WorkerThread.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, CONSTRUCTOR, TYPE, PARAMETER})
+public @interface WorkerThread {}
diff --git a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java b/stub-annotations/src/main/java/androidx/annotation/XmlRes.java
similarity index 70%
copy from stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
copy to stub-annotations/src/main/java/androidx/annotation/XmlRes.java
index 83f4e5a..cb38365 100644
--- a/stub-annotations/src/main/java/android/support/annotation/NewlyNonNull.java
+++ b/stub-annotations/src/main/java/androidx/annotation/XmlRes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -13,23 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.annotation;
+package androidx.annotation;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
 import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
+/** Stub only annotation. Do not use directly. */
 @Retention(CLASS)
-@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
-@Migrate
-public @interface NewlyNonNull {
-}
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface XmlRes {}