diff --git a/src/main/java/com/android/tools/metalava/DocAnalyzer.kt b/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
index c2550929bc43457eb40cbbd2c278e24a37ee64de..77ff1050916853fb6c37a5a14ff48f09b0313808 100644
--- a/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
+++ b/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
@@ -206,6 +206,7 @@ class DocAnalyzer(
                     "androidx.annotation.StringDef" -> handleTypeDef(annotation, item)
                     "android.annotation.RequiresFeature" -> handleRequiresFeature(annotation, item)
                     "androidx.annotation.RequiresApi" -> handleRequiresApi(annotation, item)
+                    "android.provider.Column" -> handleColumn(annotation, item)
                     "kotlin.Deprecated" -> handleKotlinDeprecation(annotation, item)
                 }
 
@@ -484,6 +485,48 @@ class DocAnalyzer(
                     addApiLevelDocumentation(level, item)
                 }
             }
+
+            private fun handleColumn(
+                annotation: AnnotationItem,
+                item: Item
+            ) {
+                val value = annotation.findAttribute("value")?.leafValues()?.firstOrNull() ?: return
+                val readOnly = annotation.findAttribute("readOnly")?.leafValues()?.firstOrNull()?.value() == true
+                val sb = StringBuilder(100)
+                val resolved = value.resolve()
+                val field = resolved as? FieldItem
+                sb.append("This constant represents a column name that can be used with a ")
+                sb.append("{@link android.content.ContentProvider}")
+                sb.append(" through a ")
+                sb.append("{@link android.content.ContentValues}")
+                sb.append(" or ")
+                sb.append("{@link android.database.Cursor}")
+                sb.append(" object. The values stored in this column are ")
+                sb.append("")
+                if (field == null) {
+                    reporter.report(
+                        Errors.MISSING_COLUMN, item,
+                        "Cannot find feature field for $value required by $item (may be hidden or removed)"
+                    )
+                    sb.append("{@link ${value.toSource()}}")
+                } else {
+                    if (filterReference.test(field)) {
+                        sb.append("{@link ${field.containingClass().qualifiedName()}#${field.name()} ${field.containingClass().simpleName()}#${field.name()}} ")
+                    } else {
+                        reporter.report(
+                            Errors.MISSING_COLUMN, item,
+                            "Feature field $value required by $item is hidden or removed"
+                        )
+                        sb.append("${field.containingClass().simpleName()}#${field.name()} ")
+                    }
+                }
+
+                if (readOnly) {
+                    sb.append(", and are read-only and cannot be mutated")
+                }
+                sb.append(".")
+                appendDocumentation(sb.toString(), item, false)
+            }
         })
     }
 
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 8621c5c7c9fa0f0ec217efc7a9cf7911d7c1e023..dfb78b91aff932d7e050c8f276ab1322edb5f9fc 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/Errors.java
+++ b/src/main/java/com/android/tools/metalava/doclava1/Errors.java
@@ -258,6 +258,7 @@ public class Errors {
     // and (2) the principle is adopted by the API council
     public static final Error EXTENDS_DEPRECATED = new Error(161, HIDDEN);
     public static final Error FORBIDDEN_TAG = new Error(162, ERROR);
+    public static final Error MISSING_COLUMN = new Error(163, WARNING, Category.DOCUMENTATION);
 
     // API lint
     public static final Error START_WITH_LOWER = new Error(300, ERROR, Category.API_LINT, "S1");
diff --git a/src/test/java/com/android/tools/metalava/DocAnalyzerTest.kt b/src/test/java/com/android/tools/metalava/DocAnalyzerTest.kt
index 5811331309cef36243f9023e081aa05181696efa..5b4efcff8da647960bb2c4a6b52097eeb4717622 100644
--- a/src/test/java/com/android/tools/metalava/DocAnalyzerTest.kt
+++ b/src/test/java/com/android/tools/metalava/DocAnalyzerTest.kt
@@ -1869,4 +1869,75 @@ class DocAnalyzerTest : DriverTest() {
 
         dir.deleteRecursively()
     }
+
+    @Test
+    fun `Test Column annotation`() {
+        // Bug: 120429729
+        check(
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    import android.provider.Column;
+                    import android.database.Cursor;
+                    @SuppressWarnings("WeakerAccess")
+                    public class ColumnTest {
+                        @Column(Cursor.FIELD_TYPE_STRING)
+                        public static final String DATA = "_data";
+                        @Column(value = Cursor.FIELD_TYPE_BLOB, readOnly = true)
+                        public static final String HASH = "_hash";
+                        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+                        public static final String TITLE = "title";
+                        @Column(value = Cursor.NONEXISTENT, readOnly = true)
+                        public static final String BOGUS = "bogus";
+                    }
+                    """
+                ),
+                java(
+                    """
+                        package android.database;
+                        public interface Cursor {
+                            int FIELD_TYPE_NULL = 0;
+                            int FIELD_TYPE_INTEGER = 1;
+                            int FIELD_TYPE_FLOAT = 2;
+                            int FIELD_TYPE_STRING = 3;
+                            int FIELD_TYPE_BLOB = 4;
+                        }
+                    """
+                ),
+                columnSource
+            ),
+            checkCompilation = true,
+            checkDoclava1 = false,
+            warnings = """
+                src/test/pkg/ColumnTest.java:12: warning: Cannot find feature field for Cursor.NONEXISTENT required by field ColumnTest.BOGUS (may be hidden or removed) [MissingColumn]
+                """,
+            stubs = arrayOf(
+                """
+                package test.pkg;
+                import android.database.Cursor;
+                @SuppressWarnings({"unchecked", "deprecation", "all"})
+                public class ColumnTest {
+                public ColumnTest() { throw new RuntimeException("Stub!"); }
+                /**
+                 * This constant represents a column name that can be used with a {@link android.content.ContentProvider} through a {@link android.content.ContentValues} or {@link android.database.Cursor} object. The values stored in this column are {@link Cursor.NONEXISTENT}, and are read-only and cannot be mutated.
+                 */
+                @android.provider.Column(value=Cursor.NONEXISTENT, readOnly=true) public static final java.lang.String BOGUS = "bogus";
+                /**
+                 * This constant represents a column name that can be used with a {@link android.content.ContentProvider} through a {@link android.content.ContentValues} or {@link android.database.Cursor} object. The values stored in this column are {@link android.database.Cursor#FIELD_TYPE_STRING Cursor#FIELD_TYPE_STRING} .
+                 */
+                @android.provider.Column(android.database.Cursor.FIELD_TYPE_STRING) public static final java.lang.String DATA = "_data";
+                /**
+                 * This constant represents a column name that can be used with a {@link android.content.ContentProvider} through a {@link android.content.ContentValues} or {@link android.database.Cursor} object. The values stored in this column are {@link android.database.Cursor#FIELD_TYPE_BLOB Cursor#FIELD_TYPE_BLOB} , and are read-only and cannot be mutated.
+                 */
+                @android.provider.Column(value=android.database.Cursor.FIELD_TYPE_BLOB, readOnly=true) public static final java.lang.String HASH = "_hash";
+                /**
+                 * This constant represents a column name that can be used with a {@link android.content.ContentProvider} through a {@link android.content.ContentValues} or {@link android.database.Cursor} object. The values stored in this column are {@link android.database.Cursor#FIELD_TYPE_STRING Cursor#FIELD_TYPE_STRING} , and are read-only and cannot be mutated.
+                 */
+                @android.provider.Column(value=android.database.Cursor.FIELD_TYPE_STRING, readOnly=true) public static final java.lang.String TITLE = "title";
+                }
+                """
+            )
+        )
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/metalava/DriverTest.kt b/src/test/java/com/android/tools/metalava/DriverTest.kt
index 8db14dc75dc4ac51776b3aa7c18cc3065f144351..5618e94f49cf4a986acbc132818801e7ff8e9634 100644
--- a/src/test/java/com/android/tools/metalava/DriverTest.kt
+++ b/src/test/java/com/android/tools/metalava/DriverTest.kt
@@ -2453,3 +2453,28 @@ val visibleForTestingSource: TestFile = java(
     }
     """
 ).indented()
+
+val columnSource: TestFile = java(
+    """
+    package android.provider;
+
+    import static java.lang.annotation.ElementType.FIELD;
+    import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+    import android.content.ContentProvider;
+    import android.content.ContentValues;
+    import android.database.Cursor;
+
+    import java.lang.annotation.Documented;
+    import java.lang.annotation.Retention;
+    import java.lang.annotation.Target;
+
+    @Documented
+    @Retention(RUNTIME)
+    @Target({FIELD})
+    public @interface Column {
+        int value();
+        boolean readOnly() default false;
+    }
+    """
+).indented()
\ No newline at end of file