diff --git a/src/main/java/com/android/tools/metalava/Options.kt b/src/main/java/com/android/tools/metalava/Options.kt
index 07be60664f65e4f718ed68068937560f6557fdf8..33afd52f752236219a0f224ee625da70e10dcb8a 100644
--- a/src/main/java/com/android/tools/metalava/Options.kt
+++ b/src/main/java/com/android/tools/metalava/Options.kt
@@ -148,6 +148,7 @@ const val ARG_STUB_PACKAGES = "--stub-packages"
 const val ARG_STUB_IMPORT_PACKAGES = "--stub-import-packages"
 const val ARG_DELETE_EMPTY_BASELINES = "--delete-empty-baselines"
 const val ARG_SUBTRACT_API = "--subtract-api"
+const val ARG_TYPEDEFS_IN_SIGNATURES = "--typedefs-in-signatures"
 
 class Options(
     private val args: Array<String>,
@@ -556,6 +557,15 @@ class Options(
     /** List of signature files to export as JDiff files */
     val convertToXmlFiles: List<ConvertFile> = mutableConvertToXmlFiles
 
+    enum class TypedefMode {
+        NONE,
+        REFERENCE,
+        INLINE
+    }
+
+    /** How to handle typedef annotations in signature files; corresponds to $ARG_TYPEDEFS_IN_SIGNATURES */
+    var typedefMode = TypedefMode.NONE
+
     /** File conversion tasks */
     data class ConvertFile(
         val fromApiFile: File,
@@ -769,6 +779,17 @@ class Options(
                     mutableSkipEmitPackages += packages.split(File.pathSeparatorChar)
                 }
 
+                ARG_TYPEDEFS_IN_SIGNATURES -> {
+                    val type = getValue(args, ++index)
+                    typedefMode = when (type) {
+                        "ref" -> TypedefMode.REFERENCE
+                        "inline" -> TypedefMode.INLINE
+                        "none" -> TypedefMode.NONE
+                        else -> throw DriverException(
+                            stderr = "$ARG_TYPEDEFS_IN_SIGNATURES must be one of ref, inline, none; was $type")
+                    }
+                }
+
                 ARG_BASELINE -> {
                     val relative = getValue(args, ++index)
                     assert(baselineFile == null) { "Only one baseline is allowed; found both $baselineFile and $relative" }
@@ -1922,6 +1943,12 @@ class Options(
             "$ARG_SUBTRACT_API <api file>", "Subtracts the API in the given signature or jar file from the " +
                 "current API being emitted via $ARG_API, $ARG_STUBS, $ARG_DOC_STUBS, etc. " +
                 "Note that the subtraction only applies to classes; it does not subtract members.",
+            "$ARG_TYPEDEFS_IN_SIGNATURES <ref|inline>", "Whether to include typedef annotations in signature " +
+                "files. `$ARG_TYPEDEFS_IN_SIGNATURES ref` will include just a reference to the typedef class, " +
+                "which is not itself part of the API and is not included as a class, and " +
+                "`$ARG_TYPEDEFS_IN_SIGNATURES inline` will include the constants themselves into each usage " +
+                "site. You can also supply `$ARG_TYPEDEFS_IN_SIGNATURES none` to explicitly turn it off, if the " +
+                "default ever changes.",
 
             "", "\nDocumentation:",
             ARG_PUBLIC, "Only include elements that are public",
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 0ce737c54c84116a9c2745eed7423e4870a419ef..9b237b655191978ae3f074c55d13412f8e9c5d53 100644
--- a/src/main/java/com/android/tools/metalava/model/AnnotationItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/AnnotationItem.kt
@@ -32,6 +32,7 @@ import com.android.tools.metalava.ANDROID_NULLABLE
 import com.android.tools.metalava.ANDROID_SUPPORT_ANNOTATION_PREFIX
 import com.android.tools.metalava.Compatibility
 import com.android.tools.metalava.JAVA_LANG_PREFIX
+import com.android.tools.metalava.Options
 import com.android.tools.metalava.RECENTLY_NONNULL
 import com.android.tools.metalava.RECENTLY_NULLABLE
 import com.android.tools.metalava.doclava1.ApiPredicate
@@ -85,6 +86,9 @@ interface AnnotationItem {
     /** True if this annotation represents @IntDef, @LongDef or @StringDef */
     fun isTypeDefAnnotation(): Boolean {
         val name = qualifiedName() ?: return false
+        if (!(name.endsWith("Def"))) {
+            return false
+        }
         return (INT_DEF_ANNOTATION.isEquals(name) ||
             STRING_DEF_ANNOTATION.isEquals(name) ||
             LONG_DEF_ANNOTATION.isEquals(name) ||
@@ -120,6 +124,12 @@ interface AnnotationItem {
         return codebase.findClass(qualifiedName() ?: return null)
     }
 
+    /** If this annotation has a typedef annotation associated with it, return it */
+    fun findTypedefAnnotation(): AnnotationItem? {
+        val className = originalName() ?: return null
+        return codebase.findClass(className)?.modifiers?.annotations()?.firstOrNull { it.isTypeDefAnnotation() }
+    }
+
     /** Returns the retention of this annotation */
     val retention: AnnotationRetention
         get() {
@@ -466,6 +476,12 @@ interface AnnotationItem {
             // See if the annotation is pointing to an annotation class that is part of the API; if not, skip it.
             val cls = codebase.findClass(qualifiedName) ?: return NO_ANNOTATION_TARGETS
             if (!ApiPredicate().test(cls)) {
+                if (options.typedefMode != Options.TypedefMode.NONE) {
+                    if (cls.modifiers.annotations().any { it.isTypeDefAnnotation() }) {
+                        return ANNOTATION_SIGNATURE_ONLY
+                    }
+                }
+
                 return NO_ANNOTATION_TARGETS
             }
 
diff --git a/src/main/java/com/android/tools/metalava/model/AnnotationTarget.kt b/src/main/java/com/android/tools/metalava/model/AnnotationTarget.kt
index 82671f035f802d179f1d270a7c1e7672699a8ffe..a4d2c72f74039044261295d545dbd7a6eecc6933 100644
--- a/src/main/java/com/android/tools/metalava/model/AnnotationTarget.kt
+++ b/src/main/java/com/android/tools/metalava/model/AnnotationTarget.kt
@@ -16,6 +16,9 @@
 
 package com.android.tools.metalava.model
 
+import com.android.tools.metalava.Options
+import com.android.tools.metalava.options
+
 /** Various places where a given annotation can be written */
 enum class AnnotationTarget {
     /** Write the annotation into the signature file */
@@ -80,4 +83,11 @@ val ANNOTATION_IN_DOC_STUBS_AND_EXTERNAL = setOf(
 val ANNOTATION_EXTERNAL = setOf(AnnotationTarget.SIGNATURE_FILE, AnnotationTarget.EXTERNAL_ANNOTATIONS_FILE)
 
 /** Write it only into the external annotations file, not the signature file */
-val ANNOTATION_EXTERNAL_ONLY = setOf(AnnotationTarget.SIGNATURE_FILE, AnnotationTarget.EXTERNAL_ANNOTATIONS_FILE)
+val ANNOTATION_EXTERNAL_ONLY = if (options.typedefMode == Options.TypedefMode.INLINE ||
+    options.typedefMode == Options.TypedefMode.NONE) // just here for compatibility purposes
+    setOf(AnnotationTarget.SIGNATURE_FILE, AnnotationTarget.EXTERNAL_ANNOTATIONS_FILE)
+else
+    setOf(AnnotationTarget.EXTERNAL_ANNOTATIONS_FILE)
+
+/** Write it only into the he signature file */
+val ANNOTATION_SIGNATURE_ONLY = setOf(AnnotationTarget.SIGNATURE_FILE)
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 d645edf3d9744a95b5560d0ff113883384b266cd..e46e1ef579bf09f6d52007ef284e415df8118be1 100644
--- a/src/main/java/com/android/tools/metalava/model/ModifierList.kt
+++ b/src/main/java/com/android/tools/metalava/model/ModifierList.kt
@@ -493,6 +493,7 @@ interface ModifierList {
                         continue
                     }
 
+                    var printAnnotation = annotation
                     if (!annotation.targets().contains(target)) {
                         continue
                     } else if ((annotation.isNullnessAnnotation())) {
@@ -502,6 +503,23 @@ interface ModifierList {
                     } else if (annotation.qualifiedName() == "java.lang.Deprecated") {
                         // Special cased in stubs and signature files: emitted first
                         continue
+                    } else if (options.typedefMode == Options.TypedefMode.INLINE) {
+                        val typedef = annotation.findTypedefAnnotation()
+                        if (typedef != null) {
+                            printAnnotation = typedef
+                        }
+                    } else if (options.typedefMode == Options.TypedefMode.REFERENCE &&
+                        annotation.targets() === ANNOTATION_SIGNATURE_ONLY &&
+                        annotation.findTypedefAnnotation() != null) {
+                        // For annotation references, only include the simple name
+                        writer.write("@")
+                        writer.write(annotation.resolve()?.simpleName() ?: annotation.qualifiedName()!!)
+                        if (separateLines) {
+                            writer.write("\n")
+                        } else {
+                            writer.write(" ")
+                        }
+                        continue
                     }
 
                     // Optionally filter out duplicates
@@ -520,7 +538,8 @@ interface ModifierList {
                         }
                     }
 
-                    val source = annotation.toSource(target)
+                    val source = printAnnotation.toSource(target)
+
                     if (omitCommonPackages) {
                         writer.write(AnnotationItem.shortenAnnotation(source))
                     } else {
diff --git a/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt b/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt
index 2d9269567e19aedc5a3a8c28d1bb2be07db43fbc..02cb3a81afe1cbe93f3fc545e635062d0e83229b 100644
--- a/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt
+++ b/src/test/java/com/android/tools/metalava/ExtractAnnotationsTest.kt
@@ -21,13 +21,9 @@ import org.junit.Test
 @SuppressWarnings("ALL") // Sample code
 class ExtractAnnotationsTest : DriverTest() {
 
-    @Test
-    fun `Check java typedef extraction and warning about non-source retention of typedefs`() {
-        check(
-            includeSourceRetentionAnnotations = false,
-            sourceFiles = *arrayOf(
-                java(
-                    """
+    private val sourceFiles1 = arrayOf(
+        java(
+            """
                     package test.pkg;
 
                     import android.annotation.IntDef;
@@ -70,10 +66,17 @@ class ExtractAnnotationsTest : DriverTest() {
                         }
                     }
                     """
-                ).indented(),
-                intDefAnnotationSource,
-                intRangeAnnotationSource
-            ),
+        ).indented(),
+        intDefAnnotationSource,
+        intRangeAnnotationSource
+    )
+
+    @Test
+    fun `Check java typedef extraction and warning about non-source retention of typedefs`() {
+        check(
+            includeSourceRetentionAnnotations = false,
+            format = FileFormat.V2,
+            sourceFiles = *sourceFiles1,
             warnings = "src/test/pkg/IntDefTest.java:11: error: This typedef annotation class should have @Retention(RetentionPolicy.SOURCE) [AnnotationExtraction]",
             extractAnnotations = mapOf(
                 "test.pkg" to """
@@ -509,4 +512,112 @@ class ExtractAnnotationsTest : DriverTest() {
             )
         )
     }
+
+    @Test
+    fun `No typedef signatures in api files`() {
+        check(
+            includeSourceRetentionAnnotations = false,
+            extraArguments = arrayOf(
+                ARG_HIDE_PACKAGE, "android.annotation",
+                ARG_TYPEDEFS_IN_SIGNATURES, "none"
+            ),
+            format = FileFormat.V2,
+            sourceFiles = *sourceFiles1,
+            api = """
+                // Signature format: 2.0
+                package test.pkg {
+                  public class IntDefTest {
+                    ctor public IntDefTest();
+                    method public void setFlags(Object, int);
+                    method public void setStyle(int, int);
+                    method public void testIntDef(int);
+                    field public static final int STYLE_NORMAL = 0; // 0x0
+                    field public static final int STYLE_NO_FRAME = 2; // 0x2
+                    field public static final int STYLE_NO_INPUT = 3; // 0x3
+                    field public static final int STYLE_NO_TITLE = 1; // 0x1
+                    field public static final String TYPE_1 = "type1";
+                    field public static final String TYPE_2 = "type2";
+                    field public static final int UNRELATED = 3; // 0x3
+                    field public static final String UNRELATED_TYPE = "other";
+                  }
+                  public static class IntDefTest.Inner {
+                    ctor public IntDefTest.Inner();
+                    method public void setInner(int);
+                  }
+                }
+            """
+        )
+    }
+
+    @Test
+    fun `Inlining typedef signatures in api files`() {
+        check(
+            includeSourceRetentionAnnotations = false,
+            extraArguments = arrayOf(
+                ARG_HIDE_PACKAGE, "android.annotation",
+                ARG_TYPEDEFS_IN_SIGNATURES, "inline"
+            ),
+            format = FileFormat.V2,
+            sourceFiles = *sourceFiles1,
+            api = """
+                // Signature format: 2.0
+                package test.pkg {
+                  public class IntDefTest {
+                    ctor public IntDefTest();
+                    method public void setFlags(Object, @IntDef(value={test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 3 + 1}, flag=true) int);
+                    method public void setStyle(@IntDef({test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT}) int, int);
+                    method public void testIntDef(int);
+                    field public static final int STYLE_NORMAL = 0; // 0x0
+                    field public static final int STYLE_NO_FRAME = 2; // 0x2
+                    field public static final int STYLE_NO_INPUT = 3; // 0x3
+                    field public static final int STYLE_NO_TITLE = 1; // 0x1
+                    field public static final String TYPE_1 = "type1";
+                    field public static final String TYPE_2 = "type2";
+                    field public static final int UNRELATED = 3; // 0x3
+                    field public static final String UNRELATED_TYPE = "other";
+                  }
+                  public static class IntDefTest.Inner {
+                    ctor public IntDefTest.Inner();
+                    method public void setInner(@IntDef(value={test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 3 + 1}, flag=true) int);
+                  }
+                }
+            """
+        )
+    }
+
+    @Test
+    fun `Referencing typedef signatures in api files`() {
+        check(
+            includeSourceRetentionAnnotations = false,
+            extraArguments = arrayOf(
+                ARG_HIDE_PACKAGE, "android.annotation",
+                ARG_TYPEDEFS_IN_SIGNATURES, "ref"
+            ),
+            format = FileFormat.V2,
+            sourceFiles = *sourceFiles1,
+            api = """
+                // Signature format: 2.0
+                package test.pkg {
+                  public class IntDefTest {
+                    ctor public IntDefTest();
+                    method public void setFlags(Object, @DialogFlags int);
+                    method public void setStyle(@DialogStyle int, int);
+                    method public void testIntDef(int);
+                    field public static final int STYLE_NORMAL = 0; // 0x0
+                    field public static final int STYLE_NO_FRAME = 2; // 0x2
+                    field public static final int STYLE_NO_INPUT = 3; // 0x3
+                    field public static final int STYLE_NO_TITLE = 1; // 0x1
+                    field public static final String TYPE_1 = "type1";
+                    field public static final String TYPE_2 = "type2";
+                    field public static final int UNRELATED = 3; // 0x3
+                    field public static final String UNRELATED_TYPE = "other";
+                  }
+                  public static class IntDefTest.Inner {
+                    ctor public IntDefTest.Inner();
+                    method public void setInner(@DialogFlags int);
+                  }
+                }
+            """
+        )
+    }
 }
\ 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 d625725a9be67f692a8e360a1fa0e1ee76f89f53..c6af7606961ea96b4bbd1ee1c9ac02eed1e9afd5 100644
--- a/src/test/java/com/android/tools/metalava/OptionsTest.kt
+++ b/src/test/java/com/android/tools/metalava/OptionsTest.kt
@@ -121,6 +121,16 @@ API sources:
                                           --api, --stubs, --doc-stubs, etc. Note that the
                                           subtraction only applies to classes; it does not
                                           subtract members.
+--typedefs-in-signatures <ref|inline>     Whether to include typedef annotations in
+                                          signature files. `--typedefs-in-signatures ref`
+                                          will include just a reference to the typedef
+                                          class, which is not itself part of the API and
+                                          is not included as a class, and
+                                          `--typedefs-in-signatures inline` will include
+                                          the constants themselves into each usage site.
+                                          You can also supply `--typedefs-in-signatures
+                                          none` to explicitly turn it off, if the default
+                                          ever changes.
 
 Documentation:
 --public                                  Only include elements that are public