chromium/third_party/androidx/local_modifications/buildcompat/java/androidx/core/os/BuildCompat.kt

/*
 * Copyright (C) 2016 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 androidx.core.os

import android.os.Build
import android.os.ext.SdkExtensions
import androidx.annotation.ChecksSdkIntAtLeast
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
import androidx.annotation.VisibleForTesting

/**
 * This class contains additional platform version checking methods for targeting pre-release
 * versions of Android.
 */
public object BuildCompat {

    /**
     * Checks if the codename is a matching or higher version than the given build value.
     *
     * @param codename the requested build codename, e.g. `"O"` or `"OMR1"`
     * @param buildCodename the value of [Build.VERSION.CODENAME]
     * @return `true` if APIs from the requested codename are available in the build.
     */
    @JvmStatic
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @VisibleForTesting
    public fun isAtLeastPreReleaseCodename(codename: String, buildCodename: String): Boolean {
        // 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()
    }

    /**
     * Checks if the device is running on the Android N release or newer.
     *
     * @return `true` if N APIs are available for use
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N)
    @Deprecated(
        message =
            "Android N is a finalized release and this method is no longer necessary. " +
                "It will be removed in a future release of this library. Instead, use " +
                "`Build.VERSION.SDK_INT >= 24`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 24")
    )
    public fun isAtLeastN(): Boolean = Build.VERSION.SDK_INT >= 24

    /**
     * Checks if the device is running on the Android N MR1 release or newer.
     *
     * @return `true` if N MR1 APIs are available for use
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N_MR1)
    @Deprecated(
        message =
            "Android N MR1 is a finalized release and this method is no longer necessary. " +
                "It will be removed in a future release of this library. Instead, use " +
                "`Build.VERSION.SDK_INT >= 25`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 25")
    )
    public fun isAtLeastNMR1(): Boolean = Build.VERSION.SDK_INT >= 25

    /**
     * Checks if the device is running on a release version of Android O or newer.
     *
     * @return `true` if O APIs are available for use, `false` otherwise
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O)
    @Deprecated(
        message =
            "Android O is a finalized release and this method is no longer necessary. " +
                "It will be removed in a future release of this library. Instead use " +
                "`Build.VERSION.SDK_INT >= 26`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 26")
    )
    public fun isAtLeastO(): Boolean = Build.VERSION.SDK_INT >= 26

    /**
     * Checks if the device is running on a release version of Android O MR1 or newer.
     *
     * @return `true` if O MR1 APIs are available for use, `false` otherwise
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O_MR1)
    @Deprecated(
        message =
            "Android O MR1 is a finalized release and this method is no longer necessary. " +
                "It will be removed in a future release of this library. Instead, use " +
                "`Build.VERSION.SDK_INT >= 27`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 27")
    )
    public fun isAtLeastOMR1(): Boolean = Build.VERSION.SDK_INT >= 27

    /**
     * Checks if the device is running on a release version of Android P or newer.
     *
     * @return `true` if P APIs are available for use, `false` otherwise
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P)
    @Deprecated(
        message =
            "Android P is a finalized release and this method is no longer necessary. " +
                "It will be removed in a future release of this library. Instead, use " +
                "`Build.VERSION.SDK_INT >= 28`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 28")
    )
    public fun isAtLeastP(): Boolean = Build.VERSION.SDK_INT >= 28

    /**
     * Checks if the device is running on release version of Android Q or newer.
     *
     * @return `true` if Q APIs are available for use, `false` otherwise
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.Q)
    @Deprecated(
        message =
            "Android Q is a finalized release and this method is no longer necessary. " +
                "It will be removed in a future release of this library. Instead, use " +
                "`Build.VERSION.SDK_INT >= 29`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 29")
    )
    public fun isAtLeastQ(): Boolean = Build.VERSION.SDK_INT >= 29

    /**
     * Checks if the device is running on release version of Android R or newer.
     *
     * @return `true` if R APIs are available for use, `false` otherwise
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.R)
    @Deprecated(
        message =
            "Android R is a finalized release and this method is no longer necessary. " +
                "It will be removed in a future release of this library. Instead, use " +
                "`Build.VERSION.SDK_INT >= 30`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 30")
    )
    public fun isAtLeastR(): Boolean = Build.VERSION.SDK_INT >= 30

    /**
     * Checks if the device is running on a pre-release version of Android S or a release version of
     * Android S or newer.
     *
     * @return `true` if S APIs are available for use, `false` otherwise
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = 31, codename = "S")
    @Deprecated(
        message =
            "Android S is a finalized release and this method is no longer necessary. " +
                "It will be removed in a future release of this library. Instead, use " +
                "`Build.VERSION.SDK_INT >= 31`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 31")
    )
    public fun isAtLeastS(): Boolean =
        Build.VERSION.SDK_INT >= 31 ||
            (Build.VERSION.SDK_INT >= 30 &&
                isAtLeastPreReleaseCodename("S", Build.VERSION.CODENAME))

    /**
     * Checks if the device is running on a pre-release version of Android Sv2 or a release version
     * of Android Sv2 or newer.
     *
     * @return `true` if Sv2 APIs are available for use, `false` otherwise
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = 32, codename = "Sv2")
    @Deprecated(
        message =
            "Android Sv2 is a finalized release and this method is no longer necessary. " +
                "It will be removed in a future release of this library. Instead, use " +
                "`Build.VERSION.SDK_INT >= 32`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 32")
    )
    public fun isAtLeastSv2(): Boolean =
        Build.VERSION.SDK_INT >= 32 ||
            (Build.VERSION.SDK_INT >= 31 &&
                isAtLeastPreReleaseCodename("Sv2", Build.VERSION.CODENAME))

    /**
     * Checks if the device is running on a pre-release version of Android Tiramisu or a release
     * version of Android Tiramisu or newer.
     *
     * **Note:** When Android Tiramisu is finalized for release, this method will be removed and all
     * calls must be replaced with `Build.VERSION.SDK_INT >= 33`.
     *
     * @return `true` if Tiramisu APIs are available for use, `false` otherwise
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = 33, codename = "Tiramisu")
    @Deprecated(
        message =
            "Android Tiramisu is a finalized release and this method is no longer " +
                "necessary. It will be removed in a future release of this library. Instead, use " +
                "`Build.VERSION.SDK_INT >= 33`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 33")
    )
    public fun isAtLeastT(): Boolean =
        Build.VERSION.SDK_INT >= 33 ||
            (Build.VERSION.SDK_INT >= 32 &&
                isAtLeastPreReleaseCodename("Tiramisu", Build.VERSION.CODENAME))

    /**
     * Checks if the device is running on a pre-release version of Android UpsideDownCake or a
     * release version of Android UpsideDownCake or newer.
     *
     * **Note:** When Android UpsideDownCake is finalized for release, this method will be removed
     * and all calls must be replaced with `Build.VERSION.SDK_INT >= 34`.
     *
     * @return `true` if UpsideDownCake APIs are available for use, `false` otherwise
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = 34, codename = "UpsideDownCake")
    @Deprecated(
        message =
            "Android UpsideDownCase is a finalized release and this method is no longer " +
                "necessary. It will be removed in a future release of this library. Instead, use " +
                "`Build.VERSION.SDK_INT >= 34`.",
        ReplaceWith("android.os.Build.VERSION.SDK_INT >= 34")
    )
    public fun isAtLeastU(): Boolean =
        Build.VERSION.SDK_INT >= 34 ||
            (Build.VERSION.SDK_INT >= 33 &&
                isAtLeastPreReleaseCodename("UpsideDownCake", Build.VERSION.CODENAME))

    /**
     * Checks if the device is running on a pre-release version of Android VanillaIceCream or a
     * release version of Android VanillaIceCream or newer.
     *
     * **Note:** When Android VanillaIceCream is finalized for release, this method will be removed
     * and all calls must be replaced with `Build.VERSION.SDK_INT >= 35`.
     *
     * @return `true` if VanillaIceCream APIs are available for use, `false` otherwise
     */
    @JvmStatic
    @ChecksSdkIntAtLeast(api = 35, codename = "VanillaIceCream")
    public fun isAtLeastV(): Boolean =
        Build.VERSION.SDK_INT >= 35 ||
            (Build.VERSION.SDK_INT >= 34 &&
                isAtLeastPreReleaseCodename("VanillaIceCream", 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
     * removed during the course of a pre-release SDK development cycle.
     *
     * Additionally, pre-release checks **may not** return `true` when run on a finalized version of
     * the SDK associated with the codename.
     */
    @RequiresOptIn
    @Retention(AnnotationRetention.BINARY)
    public annotation class PrereleaseSdkCheck

    /**
     * The value of `SdkExtensions.getExtensionVersion(R)`. This is a convenience constant which
     * provides the extension version in a similar style to `Build.VERSION.SDK_INT`.
     *
     * Compared to calling `getExtensionVersion` directly, using this constant has the benefit of
     * not having to verify the `getExtensionVersion` method is available.
     *
     * @return the version of the R extension, if it exists. 0 otherwise.
     */
    @JvmField
    @ChecksSdkIntAtLeast(extension = Build.VERSION_CODES.R)
    public val R_EXTENSION_INT: Int =
        if (Build.VERSION.SDK_INT >= 30) {
            Api30Impl.getExtensionVersion(Build.VERSION_CODES.R)
        } else 0

    /**
     * The value of `SdkExtensions.getExtensionVersion(S)`. This is a convenience constant which
     * provides the extension version in a similar style to `Build.VERSION.SDK_INT`.
     *
     * Compared to calling `getExtensionVersion` directly, using this constant has the benefit of
     * not having to verify the `getExtensionVersion` method is available.
     *
     * @return the version of the S extension, if it exists. 0 otherwise.
     */
    @JvmField
    @ChecksSdkIntAtLeast(extension = Build.VERSION_CODES.S)
    public val S_EXTENSION_INT: Int =
        if (Build.VERSION.SDK_INT >= 30) {
            Api30Impl.getExtensionVersion(Build.VERSION_CODES.S)
        } else 0

    /**
     * The value of `SdkExtensions.getExtensionVersion(TIRAMISU)`. This is a convenience constant
     * which provides the extension version in a similar style to `Build.VERSION.SDK_INT`.
     *
     * Compared to calling `getExtensionVersion` directly, using this constant has the benefit of
     * not having to verify the `getExtensionVersion` method is available.
     *
     * @return the version of the T extension, if it exists. 0 otherwise.
     */
    @JvmField
    @ChecksSdkIntAtLeast(extension = Build.VERSION_CODES.TIRAMISU)
    public val T_EXTENSION_INT: Int =
        if (Build.VERSION.SDK_INT >= 30) {
            Api30Impl.getExtensionVersion(Build.VERSION_CODES.TIRAMISU)
        } else 0

    /**
     * The value of `SdkExtensions.getExtensionVersion(AD_SERVICES)`. This is a convenience constant
     * which provides the extension version in a similar style to `Build.VERSION.SDK_INT`.
     *
     * Compared to calling `getExtensionVersion` directly, using this constant has the benefit of
     * not having to verify the `getExtensionVersion` method is available.
     *
     * @return the version of the AdServices extension, if it exists. 0 otherwise.
     */
    @JvmField
    @ChecksSdkIntAtLeast(extension = SdkExtensions.AD_SERVICES)
    public val AD_SERVICES_EXTENSION_INT: Int =
        if (Build.VERSION.SDK_INT >= 30) {
            Api30Impl.getExtensionVersion(SdkExtensions.AD_SERVICES)
        } else 0

    @RequiresApi(30)
    private object Api30Impl {

        fun getExtensionVersion(extension: Int): Int {
            return SdkExtensions.getExtensionVersion(extension)
        }
    }
}