Merge "Don't override maxTargetSdk for trackingBug=170729553."
diff --git a/java/android/compat/annotation/Android.bp b/java/android/compat/annotation/Android.bp
index f72aac6..77b11e0 100644
--- a/java/android/compat/annotation/Android.bp
+++ b/java/android/compat/annotation/Android.bp
@@ -23,6 +23,7 @@
         "EnabledAfter.java",
         "EnabledSince.java",
         "LoggingOnly.java",
+        "Overridable.java",
     ],
     sdk_version: "core_current",
     exported_plugins: ["compat-changeid-annotation-processor"],
@@ -37,6 +38,7 @@
         "EnabledAfter.java",
         "EnabledSince.java",
         "LoggingOnly.java",
+        "Overridable.java",
         "UnsupportedAppUsage.java",
     ],
     visibility: [
diff --git a/java/android/compat/annotation/Overridable.java b/java/android/compat/annotation/Overridable.java
new file mode 100644
index 0000000..b2611d0
--- /dev/null
+++ b/java/android/compat/annotation/Overridable.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 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.compat.annotation;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Used to indicate that a compatibility {@link ChangeId change} can be overridden on user builds.
+ *
+ * <p>This annotation should only be applied to change ID constants that are also annotated with
+ * {@link ChangeId}. In any other context, this annotation will have no effect.
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({FIELD})
+public @interface Overridable {
+}
diff --git a/java/android/processor/compat/changeid/Change.java b/java/android/processor/compat/changeid/Change.java
index 32f6c14..0418a85 100644
--- a/java/android/processor/compat/changeid/Change.java
+++ b/java/android/processor/compat/changeid/Change.java
@@ -27,6 +27,7 @@
     final Integer enabledAfter;
     final Integer enabledSince;
     final String description;
+    final boolean overridable;
     /**
      * Package name that the change is defined in.
      */
@@ -45,8 +46,9 @@
     final String sourcePosition;
 
      Change(Long id, String name, boolean disabled, boolean loggingOnly, Integer enabledAfter,
-            Integer enabledSince, String description, String javaPackage, String className,
-            String qualifiedClass, String sourcePosition) {
+             Integer enabledSince, String description, boolean overridable, String javaPackage,
+             String className,
+             String qualifiedClass, String sourcePosition) {
         this.id = id;
         this.name = name;
         this.disabled = disabled;
@@ -54,6 +56,7 @@
         this.enabledAfter = enabledAfter;
         this.enabledSince = enabledSince;
         this.description = description;
+        this.overridable = overridable;
         this.javaPackage = javaPackage;
         this.className = className;
         this.qualifiedClass = qualifiedClass;
@@ -68,6 +71,7 @@
         Integer enabledAfter;
         Integer enabledSince;
         String description;
+        boolean overridable;
         String javaPackage;
         String javaClass;
         String qualifiedClass;
@@ -111,6 +115,11 @@
             return this;
         }
 
+        public Builder overridable() {
+            this.overridable = true;
+            return this;
+        }
+
         public Builder javaPackage(String javaPackage) {
             this.javaPackage = javaPackage;
             return this;
@@ -133,7 +142,7 @@
 
         public Change build() {
             return new Change(id, name, disabled, loggingOnly, enabledAfter, enabledSince,
-                    description, javaPackage, javaClass, qualifiedClass, sourcePosition);
+                    description, overridable, javaPackage, javaClass, qualifiedClass, sourcePosition);
         }
     }
 }
diff --git a/java/android/processor/compat/changeid/ChangeIdProcessor.java b/java/android/processor/compat/changeid/ChangeIdProcessor.java
index 493bf45..4815baa 100644
--- a/java/android/processor/compat/changeid/ChangeIdProcessor.java
+++ b/java/android/processor/compat/changeid/ChangeIdProcessor.java
@@ -72,6 +72,7 @@
     private static final String ENABLED_SINCE_CLASS_NAME = "android.compat.annotation.EnabledSince";
     private static final String LOGGING_CLASS_NAME = "android.compat.annotation.LoggingOnly";
     private static final String TARGET_SDK_VERSION = "targetSdkVersion";
+    private static final String OVERRIDABLE_CLASS_NAME = "android.compat.annotation.Overridable";
 
     private static final Pattern JAVADOC_SANITIZER = Pattern.compile("^\\s", Pattern.MULTILINE);
     private static final Pattern HIDE_TAG_MATCHER = Pattern.compile("(\\s|^)@hide(\\s|$)");
@@ -194,6 +195,9 @@
                 case ENABLED_SINCE_CLASS_NAME:
                     builder.enabledSince((Integer)(Objects.requireNonNull(sdkValue).getValue()));
                     break;
+                case OVERRIDABLE_CLASS_NAME:
+                    builder.overridable();
+                    break;
                 case CHANGE_ID_QUALIFIED_CLASS_NAME:
                     changeId = mirror;
                     break;
diff --git a/java/android/processor/compat/changeid/XmlWriter.java b/java/android/processor/compat/changeid/XmlWriter.java
index 968f599..772aa41 100644
--- a/java/android/processor/compat/changeid/XmlWriter.java
+++ b/java/android/processor/compat/changeid/XmlWriter.java
@@ -67,6 +67,7 @@
     private static final String XML_ENABLED_AFTER_ATTR = "enableAfterTargetSdk";
     private static final String XML_ENABLED_SINCE_ATTR = "enableSinceTargetSdk";
     private static final String XML_DESCRIPTION_ATTR = "description";
+    private static final String XML_OVERRIDABLE_ATTR = "overridable";
     private static final String XML_METADATA_ELEMENT = "meta-data";
     private static final String XML_DEFINED_IN = "definedIn";
     private static final String XML_SOURCE_POSITION = "sourcePosition";
@@ -99,6 +100,9 @@
         if (change.description != null) {
             newElement.setAttribute(XML_DESCRIPTION_ATTR, change.description);
         }
+        if (change.overridable) {
+            newElement.setAttribute(XML_OVERRIDABLE_ATTR, "true");
+        }
         Element metaData = mDocument.createElement(XML_METADATA_ELEMENT);
         if (change.qualifiedClass != null) {
             metaData.setAttribute(XML_DEFINED_IN, change.qualifiedClass);
diff --git a/javatest/android/processor/compat/changeid/ChangeIdProcessorTest.java b/javatest/android/processor/compat/changeid/ChangeIdProcessorTest.java
index 6be9183..7c84aff 100644
--- a/javatest/android/processor/compat/changeid/ChangeIdProcessorTest.java
+++ b/javatest/android/processor/compat/changeid/ChangeIdProcessorTest.java
@@ -87,6 +87,16 @@
                     "@Target({FIELD})",
                     "public @interface EnabledSince {",
                     "int targetSdkVersion();",
+                    "}"),
+            JavaFileObjects.forSourceLines("android.compat.annotation.Overridable",
+                    "package android.compat.annotation;",
+                    "import static java.lang.annotation.ElementType.FIELD;",
+                    "import static java.lang.annotation.RetentionPolicy.SOURCE;",
+                    "import java.lang.annotation.Retention;",
+                    "import java.lang.annotation.Target;",
+                    "@Retention(SOURCE)",
+                    "@Target({FIELD})",
+                    "public @interface Overridable {",
                     "}")
 
     };
@@ -104,6 +114,7 @@
                         "import android.compat.annotation.EnabledAfter;",
                         "import android.compat.annotation.EnabledSince;",
                         "import android.compat.annotation.Disabled;",
+                        "import android.compat.annotation.Overridable;",
                         "public class Compat {",
                         "    /**",
                         "    * description of",
@@ -120,20 +131,28 @@
                         "    @ChangeId",
                         "    @EnabledSince(targetSdkVersion=30)",
                         "    public static final long LAST_CHANGE = 23456701l;",
+                        "    /** description of OVERRIDABLE_CHANGE **/",
+                        "    @ChangeId",
+                        "    @Overridable",
+                        "    public static final long OVERRIDABLE_CHANGE = 23456702l;",
                         "}")
         };
         String expectedFile = HEADER + "<config>" +
                 "<compat-change description=\"description of MY_CHANGE_ID\" "
                 + "enableAfterTargetSdk=\"29\" id=\"123456789\" name=\"MY_CHANGE_ID\">"
                 + "<meta-data definedIn=\"libcore.util.Compat\" "
-                + "sourcePosition=\"libcore/util/Compat.java:12\"/></compat-change>"
+                + "sourcePosition=\"libcore/util/Compat.java:13\"/></compat-change>"
                 + "<compat-change description=\"description of ANOTHER_CHANGE\" disabled=\"true\" "
                 + "id=\"23456700\" name=\"ANOTHER_CHANGE\"><meta-data definedIn=\"libcore.util"
-                + ".Compat\" sourcePosition=\"libcore/util/Compat.java:15\"/></compat-change>"
+                + ".Compat\" sourcePosition=\"libcore/util/Compat.java:16\"/></compat-change>"
                 + "<compat-change description=\"description of LAST_CHANGE\" "
                 + "enableSinceTargetSdk=\"30\" id=\"23456701\" name=\"LAST_CHANGE\">"
                 + "<meta-data definedIn=\"libcore.util.Compat\" "
-                + "sourcePosition=\"libcore/util/Compat.java:19\"/></compat-change>"
+                + "sourcePosition=\"libcore/util/Compat.java:20\"/></compat-change>"
+                + "<compat-change description=\"description of OVERRIDABLE_CHANGE\" "
+                + "id=\"23456702\" name=\"OVERRIDABLE_CHANGE\" overridable=\"true\">"
+                + "<meta-data definedIn=\"libcore.util.Compat\" "
+                + "sourcePosition=\"libcore/util/Compat.java:24\"/></compat-change>"
                 + "</config>";
         Compilation compilation =
                 Compiler.javac()
diff --git a/javatest/android/processor/compat/changeid/XmlWriterTest.java b/javatest/android/processor/compat/changeid/XmlWriterTest.java
index f401fc6..1cf774c 100644
--- a/javatest/android/processor/compat/changeid/XmlWriterTest.java
+++ b/javatest/android/processor/compat/changeid/XmlWriterTest.java
@@ -88,12 +88,19 @@
                 .name("change-name5")
                 .loggingOnly()
                 .build();
+        Change overridable = new Change.Builder()
+                .id(666L)
+                .name("change-name6")
+                .disabled()
+                .overridable()
+                .build();
 
         writer.addChange(c);
         writer.addChange(disabled);
         writer.addChange(sdkRestricted);
         writer.addChange(both);
         writer.addChange(loggingOnly);
+        writer.addChange(overridable);
         writer.write(mOutputStream);
 
         String expected = HEADER + "<config>"
@@ -104,6 +111,8 @@
                 + "<compat-change disabled=\"true\" enableAfterTargetSdk=\"29\" id=\"444\" "
                 + "name=\"change-name4\"/>"
                 + "<compat-change id=\"555\" loggingOnly=\"true\" name=\"change-name5\"/>"
+                + "<compat-change disabled=\"true\" id=\"666\" name=\"change-name6\" "
+                + "overridable=\"true\"/>"
                 + "</config>";
 
         assertThat(mOutputStream.toString(), startsWith(expected));