Merge "Add BuildCompat.isAtLeastB" into androidx-main
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index 45edc44..d8f9bf5 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -1870,6 +1870,7 @@
   }
 
   public final class BuildCompat {
+    method @ChecksSdkIntAtLeast(api=36, codename="Baklava") public static boolean isAtLeastB();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 46e97fe..dc7f4a4eb 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -2263,6 +2263,7 @@
   }
 
   public final class BuildCompat {
+    method @ChecksSdkIntAtLeast(api=36, codename="Baklava") public static boolean isAtLeastB();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
diff --git a/core/core/src/androidTest/java/androidx/core/os/BuildCompatTest.java b/core/core/src/androidTest/java/androidx/core/os/BuildCompatTest.java
index 26087bd..e9764cd 100644
--- a/core/core/src/androidTest/java/androidx/core/os/BuildCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/os/BuildCompatTest.java
@@ -51,6 +51,13 @@
         assertFalse(BuildCompat.isAtLeastPreReleaseCodename("S", "REL"));
 
         assertFalse(BuildCompat.isAtLeastPreReleaseCodename("RMR1", "REL"));
+
+        assertFalse(BuildCompat.isAtLeastPreReleaseCodename("RMR1", "REL"));
+
+        assertTrue(BuildCompat.isAtLeastPreReleaseCodename("VanillaIceCream", "VanillaIceCream"));
+        assertTrue(BuildCompat.isAtLeastPreReleaseCodename("VanillaIceCream", "Baklava"));
+        assertTrue(BuildCompat.isAtLeastPreReleaseCodename("Baklava", "Baklava"));
+        assertFalse(BuildCompat.isAtLeastPreReleaseCodename("Baklava", "VanillaIceCream"));
     }
 
     @Test
@@ -82,4 +89,10 @@
     public void isAtLeastV_byMinSdk() {
         assertTrue(BuildCompat.isAtLeastV());
     }
+
+    @SdkSuppress(minSdkVersion = 36)
+    @Test
+    public void isAtLeastB_byMinSdk() {
+        assertTrue(BuildCompat.isAtLeastB());
+    }
 }
diff --git a/core/core/src/main/java/androidx/core/os/BuildCompat.kt b/core/core/src/main/java/androidx/core/os/BuildCompat.kt
index 22937a3..0cfe5a7 100644
--- a/core/core/src/main/java/androidx/core/os/BuildCompat.kt
+++ b/core/core/src/main/java/androidx/core/os/BuildCompat.kt
@@ -40,13 +40,32 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     @VisibleForTesting
     public fun isAtLeastPreReleaseCodename(codename: String, buildCodename: String): Boolean {
+        fun codenameToInt(codename: String): Int? =
+            when (codename.uppercase()) {
+                "BAKLAVA" -> 0
+                else -> null
+            }
+
         // Special case "REL", which means the build is not a pre-release build.
         if ("REL" == buildCodename) {
             return false
         }
-        // Otherwise lexically compare them.  Return true if the build codename is equal to or
-        // greater than the requested codename.
-        return buildCodename.uppercase() >= codename.uppercase()
+
+        // Starting with Baklava, the Android dessert names wrapped around to the start of the
+        // alphabet; handle these "new" codenames explicitly; lexically compare "old" codenames.
+        // Return true if the build codename is equal to or greater than the requested codename.
+        val buildCodenameInt = codenameToInt(buildCodename)
+        val codenameInt = codenameToInt(codename)
+        if (buildCodenameInt != null && codenameInt != null) {
+            // both codenames are "new" -> use hard-coded int values
+            return buildCodenameInt >= codenameInt
+        } else if (buildCodenameInt == null && codenameInt == null) {
+            // both codenames are "old" -> use lexical comparison
+            return buildCodename.uppercase() >= codename.uppercase()
+        } else {
+            // one codename is "new", one is "old"
+            return buildCodenameInt != null
+        }
     }
 
     /**
@@ -271,6 +290,22 @@
                 isAtLeastPreReleaseCodename("VanillaIceCream", Build.VERSION.CODENAME))
 
     /**
+     * Checks if the device is running on a pre-release version of Android Baklava or a release
+     * version of Android Baklava or newer.
+     *
+     * **Note:** When Android Baklava is finalized for release, this method will be removed and all
+     * calls must be replaced with `Build.VERSION.SDK_INT >= 36`.
+     *
+     * @return `true` if Baklava APIs are available for use, `false` otherwise
+     */
+    @JvmStatic
+    @ChecksSdkIntAtLeast(api = 36, codename = "Baklava")
+    public fun isAtLeastB(): Boolean =
+        Build.VERSION.SDK_INT >= 36 ||
+            (Build.VERSION.SDK_INT >= 35 &&
+                isAtLeastPreReleaseCodename("Baklava", Build.VERSION.CODENAME))
+
+    /**
      * Experimental feature set for pre-release SDK checks.
      *
      * Pre-release SDK checks **do not** guarantee correctness, as APIs may have been added or