Snap for 14082709 from e6f015b55f1ba452286e84d40bca7b8afdbd52ae to studio-narwhal4-release

Change-Id: I1af3049929644436d5ed1586de7e6548ab74fbab
diff --git a/base/dependencies.properties b/base/dependencies.properties
index 372731a..9cbfdfc 100644
--- a/base/dependencies.properties
+++ b/base/dependencies.properties
@@ -108,16 +108,16 @@
 kotlin_coroutines_android = org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4
 
 # Kotlin dependencies used to build the Android Gradle plugin
-kotlin_gradle_plugin = org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.0
-kotlin_gradle_plugin_idea = org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.2.0
-kotlin_gradle_pluginmarker = org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:2.2.0
-kotlin_reflect = org.jetbrains.kotlin:kotlin-reflect:2.2.0
-kotlin_stdlib = org.jetbrains.kotlin:kotlin-stdlib:2.2.0
-kotlin_test = org.jetbrains.kotlin:kotlin-test:2.2.0
+kotlin_gradle_plugin = org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.10
+kotlin_gradle_plugin_idea = org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.2.10
+kotlin_gradle_pluginmarker = org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:2.2.10
+kotlin_reflect = org.jetbrains.kotlin:kotlin-reflect:2.2.10
+kotlin_stdlib = org.jetbrains.kotlin:kotlin-stdlib:2.2.10
+kotlin_test = org.jetbrains.kotlin:kotlin-test:2.2.10
 # Kotlin dependencies used to compile and run AGP tests -- these are usually updated together with the Kotlin
 # dependencies used to build AGP above
-compose_compiler_gradle_plugin = org.jetbrains.kotlin:compose-compiler-gradle-plugin:2.2.0
-ksp_gradle_plugin = com.google.devtools.ksp:symbol-processing-gradle-plugin:2.2.0-2.0.2
+compose_compiler_gradle_plugin = org.jetbrains.kotlin:compose-compiler-gradle-plugin:2.2.10
+ksp_gradle_plugin = com.google.devtools.ksp:symbol-processing-gradle-plugin:2.2.10-2.0.2
 
 kxml = net.sf.kxml:kxml2:2.3.0
 jetifier_core = com.android.tools.build.jetifier:jetifier-core:1.0.0-beta10
diff --git a/src/main/java/com/android/tools/internal/metalava/GenerateApiReleaseNotes.java b/src/main/java/com/android/tools/internal/metalava/GenerateApiReleaseNotes.java
index ff6d850..a72ecd0 100644
--- a/src/main/java/com/android/tools/internal/metalava/GenerateApiReleaseNotes.java
+++ b/src/main/java/com/android/tools/internal/metalava/GenerateApiReleaseNotes.java
@@ -44,6 +44,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 public abstract class GenerateApiReleaseNotes extends DefaultTask {
@@ -66,29 +67,40 @@
     public abstract ConfigurableFileCollection getOldApiFiles();
 
     public GenerateApiReleaseNotes() {
-        getCurrentVersion().convention("current.txt");
+        getCurrentVersion().convention("current");
     }
 
     @TaskAction
     public void generate() throws IOException {
         File olderApiSignatureFile = null;
+        String previousVersion = null;
         if (!getPreviousVersion().isPresent()) {
             Optional<AgpVersion> previousStableVersion = getOldApiFiles().getFiles().stream()
                     .map(file -> AgpVersion.parseFileNameOrNull(file.getName()))
                     .filter(Objects::nonNull).max(Comparator.naturalOrder());
-            assert previousStableVersion.isPresent();
+            if (!previousStableVersion.isPresent()) {
+                throw new RuntimeException("previous stable version not present");
+            }
             olderApiSignatureFile = getProject().getLayout().getProjectDirectory().dir("previous-gradle-apis").file(previousStableVersion.get() + ".txt").getAsFile();
+            previousVersion = previousStableVersion.get().toString();
         } else {
-            olderApiSignatureFile = getProject().getLayout().getProjectDirectory().dir("previous-gradle-apis").file(getPreviousVersion().get()).getAsFile();
+            olderApiSignatureFile = getProject().getLayout().getProjectDirectory().dir("previous-gradle-apis").file(getPreviousVersion().get() + ".txt").getAsFile();
+            previousVersion = getPreviousVersion().get();
         }
 
-        File currentApiSignatureFile = getInputDirectory().get().file(getCurrentVersion().get()).getAsFile();
+        File currentApiSignatureFile = getInputDirectory().get().file(getCurrentVersion().get() + ".txt").getAsFile();
+        String currentVersion = getCurrentVersion().get();
 
         if (!currentApiSignatureFile.exists() || !olderApiSignatureFile.exists()) return;
-        generateReleaseNotes(currentApiSignatureFile, olderApiSignatureFile);
+        generateReleaseNotes(currentApiSignatureFile, olderApiSignatureFile, previousVersion, currentVersion);
     }
 
-    private void generateReleaseNotes(File currentApiSignatureFile, File olderApiSignatureFile) throws IOException {
+    private void generateReleaseNotes(
+            File currentApiSignatureFile,
+            File olderApiSignatureFile,
+            String previousVersion,
+            String currentVersion
+    ) throws IOException {
         Map<String, ClassDefinition> currentApiElements =
                 parseApiSignature(IOUtils.toString(new FileReader(currentApiSignatureFile)))
                         .stream()
@@ -101,27 +113,61 @@
                         .collect(Collectors.toMap(
                                 clazz -> clazz.getPackageName() + "." + clazz.getClassName(), clazz -> clazz));
 
-        findStabilizedApis(currentApiElements, olderApiElements);
-
+        findStabilizedApis(currentApiElements, olderApiElements, previousVersion, currentVersion);
     }
 
     // Finds apis that were incubating in older api version but are not in current
     private void findStabilizedApis(
             Map<String, ClassDefinition> currentApiElements,
-            Map<String, ClassDefinition> olderApiElements
+            Map<String, ClassDefinition> olderApiElements,
+            String previousVersion,
+            String currentVersion
     ) {
         StringBuilder sb = new StringBuilder();
-        sb.append("Android Gradle plugin API updates").append("\n");
+        sb.append("Android Gradle plugin API updates")
+                .append("(between ").append(previousVersion).append(" and ").append(currentVersion).append(")")
+                .append("\n\n");
 
+        boolean changes = false;
         for (String className : olderApiElements.keySet()) {
-            com.android.tools.internal.metalava.ClassDefinition oldClassDefinition = olderApiElements.get(className);
+            ClassDefinition oldClassDefinition = olderApiElements.get(className);
             ClassDefinition classDefinition = currentApiElements.get(className);
-            if (classDefinition != null && oldClassDefinition.isIncubating() && !classDefinition.isIncubating()) {
-                // class has become stable
-                sb.append(className).append(" is now stable\n");
+
+            if (classDefinition != null) {
+                if (oldClassDefinition.isIncubating() && !classDefinition.isIncubating()) {
+                    // class has become stable
+                    sb.append("Class ").append(className).append(" is now stable\n");
+                    changes = true;
+                }
+
+                for (MethodOrFieldDefinition oldMethod : oldClassDefinition.getMethods()) {
+                    Optional<MethodOrFieldDefinition> currentMethod = classDefinition.getMethods().stream()
+                            .filter(method -> method.getName().equals(oldMethod.getName()))
+                            .findFirst();
+                    if (currentMethod.isPresent() && oldMethod.isIncubating() && !currentMethod.get().isIncubating()) {
+                        // method has become stable
+                        sb.append("Method ").append(oldMethod.getName()).append(" in ").append(className).append(" is now stable\n");
+                        changes = true;
+                    }
+                }
+
+                for (MethodOrFieldDefinition oldField : oldClassDefinition.getFields()) {
+                    Optional<MethodOrFieldDefinition> currentField = classDefinition.getFields().stream()
+                            .filter(field -> field.getName().equals(oldField.getName()))
+                            .findFirst();
+                    if (currentField.isPresent() && oldField.isIncubating() && !currentField.get().isIncubating()) {
+                        // field has become stable
+                        sb.append("Field ").append(oldField.getName()).append(" in ").append(className).append(" is now stable\n");
+                        changes = true;
+                    }
+                }
             }
         }
 
+        if (!changes) {
+            sb.append("No APIs were made stable.");
+        }
+
         writeToFile(sb, "stable-apis.txt");
     }
 
@@ -152,6 +198,11 @@
 
                     boolean isDeprecated = line.startsWith("@Deprecated");
                     line = line.replace("@Deprecated", "").trim();
+                    boolean isReplacedByIncubating = line.startsWith("@com.android.build.api.annotations.ReplacedByIncubating");
+                    if (isReplacedByIncubating) {
+                        Pattern p = Pattern.compile("@com\\.android\\.build\\.api\\.annotations\\.ReplacedByIncubating(\\(.*\\))?");
+                        line = p.matcher(line).replaceAll("");
+                    }
                     boolean isIncubating = line.startsWith("@org.gradle.api.Incubating");
                     line = line.replace("@org.gradle.api.Incubating", "").trim();