Update SdkLevel and sdk_level.h

Ideally, we would deprecate ApiLevelUtil classes maintained by tradefed
in favor of these utils. Since tradefed drops the prebuilts / sources
into old branches, we should avoid using fixed VERSION_CODES in code.

This makes the util behave similarly to BuildCompat which
understands pre-release builds as well. See https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/main/java/androidx/core/os/BuildCompat.java.

Bug: 187807290
Test: m
Change-Id: I4f1e34759218df62affbefbe1c6db8782152f033
Merged-In: I4f1e34759218df62affbefbe1c6db8782152f033
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index fd78ff1..b53cbf1 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,12 @@
+[Builtin Hooks]
+bpfmt = true
+clang_format = true
+commit_msg_changeid_field = true
+commit_msg_test_field = true
+
+[Builtin Hooks Options]
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+
 [Hook Scripts]
 do_not_use_DO_NOT_MERGE = ${REPO_ROOT}/build/soong/scripts/check_do_not_merge.sh ${PREUPLOAD_COMMIT}
 check_java_paths = ${REPO_ROOT}/frameworks/libs/modules-utils/tools/check_java_paths.py
\ No newline at end of file
diff --git a/build/include/android-modules-utils/sdk_level.h b/build/include/android-modules-utils/sdk_level.h
index a373178..102e01f 100644
--- a/build/include/android-modules-utils/sdk_level.h
+++ b/build/include/android-modules-utils/sdk_level.h
@@ -17,32 +17,34 @@
 #pragma once
 
 #include <android-base/properties.h>
+#include <android/api-level.h>
 
 namespace android {
 namespace modules {
 namespace sdklevel {
 
-// Return true iff the running Android SDK is at least "R".
-static inline bool IsAtLeastR() {
-  return android::base::GetIntProperty("ro.build.version.sdk", -1) >= 30;
+// Checks if the codename is a matching or higher version than the device's
+// codename.
+static bool IsAtLeastPreReleaseCodename(const std::string &codename) {
+  const std::string &deviceCodename =
+      android::base::GetProperty("ro.build.version.codename", "");
+  return "REL" != deviceCodename && deviceCodename.compare(codename) >= 0;
 }
 
-// Returns true iff the running Android SDK is pre-release "S" or "T", built
-// based on "R" SDK.
-//
-// If new SDK versions are added > R, then this method needs to be updated to
-// recognise them (e.g. if we add SDK version for R-QPR, the current
-// implementation will not recognise pre-release "S" versions built on that).
+// Checks if the device is running on release version of Android R or newer.
+static inline bool IsAtLeastR() { return android_get_device_api_level() >= 30; }
+
+// Checks if the device is running on a pre-release version of Android S or a
+// release version of Android S or newer.
 static inline bool IsAtLeastS() {
-  // TODO(b/170831689) This should check SDK_INT >= S once S sdk finalised.
-  // Note that removing the current conditions may lead to issues in
-  // mainlinefood (and possibly public beta?).
-  std::string codename =
-    android::base::GetProperty("ro.build.version.codename", "");
-  return android::base::GetIntProperty("ro.build.version.sdk", -1) == 30 &&
-      (codename == "S" || codename == "T");
+  return android_get_device_api_level() >= 31 ||
+         IsAtLeastPreReleaseCodename("S");
 }
 
+// Checks if the device is running on a pre-release version of Android T or a
+// release version of Android T or newer.
+static inline bool IsAtLeastT() { return IsAtLeastPreReleaseCodename("T"); }
+
 } // namespace utils
 } // namespace modules
 } // namespace android
diff --git a/java/com/android/modules/utils/build/SdkLevel.java b/java/com/android/modules/utils/build/SdkLevel.java
index 115b9b9..a87d248 100644
--- a/java/com/android/modules/utils/build/SdkLevel.java
+++ b/java/com/android/modules/utils/build/SdkLevel.java
@@ -16,44 +16,53 @@
 
 package com.android.modules.utils.build;
 
-import android.os.Build;
+import static android.os.Build.VERSION.CODENAME;
+import static android.os.Build.VERSION.SDK_INT;
 
 import androidx.annotation.ChecksSdkIntAtLeast;
+import androidx.annotation.NonNull;
 
 /**
- * Utility class to check SDK level.
+ * Utility class to check SDK level on a device.
  *
  * @hide
  */
-public class SdkLevel {
+public final class SdkLevel {
 
     private SdkLevel() {}
 
-    /** Return true iff the running Android SDK is at least "R". */
-    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.R)
+    /** Checks if the device is running on release version of Android R or newer. */
+    @ChecksSdkIntAtLeast(api = 30 /* Build.VERSION_CODES.R */)
     public static boolean isAtLeastR() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
+        return SDK_INT >= 30;
     }
 
     /**
-     * Returns true iff the running Android SDK is pre-release "S" or "T", built based on "R" SDK.
-     *
-     * If new SDK versions are added > R, then this method needs to be updated to recognise them
-     * (e.g. if we add SDK version for R-QPR,  the current implementation will not recognise
-     * pre-release "S" versions built on that).
+     * Checks if the device is running on a pre-release version of Android S or a release version of
+     * Android S or newer.
      */
-    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.CUR_DEVELOPMENT)
+    @ChecksSdkIntAtLeast(api = 31 /* Build.VERSION_CODES.S */, codename = "S")
     public static boolean isAtLeastS() {
-        // TODO(b/170831689) This should check SDK_INT >= S once S sdk finalised. Note that removing the
-        // current conditions may lead to issues in mainlinefood (and possibly public beta?).
+        return SDK_INT >= 31 || isAtLeastPreReleaseCodename("S");
+    }
 
-        // While in development, builds will have R SDK_INT and "S" or "T" codename.
-        // We don't accept SDK_INT > R for now, since R and S may have non-consecutive values.
-        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R
-            && ("S".equals(Build.VERSION.CODENAME) || "T".equals(Build.VERSION.CODENAME))) {
-            return true;
+    /**
+     * Checks if the device is running on a pre-release version of Android T or a release version of
+     * Android T or newer.
+     */
+    @ChecksSdkIntAtLeast(codename = "T")
+    public static boolean isAtLeastT() {
+        return isAtLeastPreReleaseCodename("T");
+    }
+
+    private static boolean isAtLeastPreReleaseCodename(@NonNull String codename) {
+        // Special case "REL", which means the build is not a pre-release build.
+        if ("REL".equals(CODENAME)) {
+            return false;
         }
 
-        return false;
+        // Otherwise lexically compare them. Return true if the build codename is equal to or
+        // greater than the requested codename.
+        return CODENAME.compareTo(codename) >= 0;
     }
 }