SdkSpec = Scope + ApiLevel

SdkSpec.Version was an int type. Now it becomes ApiLevel type which
is a better abstraction of the version (or api level).

Bug: 1655587
Test: m

Change-Id: I4d67b9b9eae45f653b6af4f5b73da9e091b3dfab
diff --git a/android/sdk_version.go b/android/sdk_version.go
index ce22b5f..5fdaa91 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -75,58 +75,15 @@
 	}
 }
 
-// SdkVersion represents a specific version number of an SDK spec of a particular kind
-type SdkVersion int
-
-const (
-	// special version number for a not-yet-frozen SDK
-	SdkVersionCurrent SdkVersion = SdkVersion(FutureApiLevelInt)
-	// special version number to be used for SDK specs where version number doesn't
-	// make sense, e.g. "none", "", etc.
-	SdkVersionNone SdkVersion = SdkVersion(0)
-)
-
-// IsCurrent checks if the SdkVersion refers to the not-yet-published version of an SdkKind
-func (v SdkVersion) IsCurrent() bool {
-	return v == SdkVersionCurrent
-}
-
-// IsNumbered checks if the SdkVersion refers to the published (a.k.a numbered) version of an SdkKind
-func (v SdkVersion) IsNumbered() bool {
-	return !v.IsCurrent() && v != SdkVersionNone
-}
-
-// String returns the string representation of this SdkVersion.
-func (v SdkVersion) String() string {
-	if v.IsCurrent() {
-		return "current"
-	} else if v.IsNumbered() {
-		return strconv.Itoa(int(v))
-	}
-	return "(no version)"
-}
-
-func (v SdkVersion) ApiLevel(ctx EarlyModuleContext) ApiLevel {
-	return ApiLevelOrPanic(ctx, v.String())
-}
-
-// AsNumberString directly converts the numeric value of this sdk version as a string.
-// When isNumbered() is true, this method is the same as String(). However, for SdkVersionCurrent
-// and SdkVersionNone, this returns 10000 and 0 while String() returns "current" and "(no version"),
-// respectively.
-func (v SdkVersion) AsNumberString() string {
-	return strconv.Itoa(int(v))
-}
-
 // SdkSpec represents the kind and the version of an SDK for a module to build against
 type SdkSpec struct {
-	Kind    SdkKind
-	Version SdkVersion
-	Raw     string
+	Kind     SdkKind
+	ApiLevel ApiLevel
+	Raw      string
 }
 
 func (s SdkSpec) String() string {
-	return fmt.Sprintf("%s_%s", s.Kind, s.Version)
+	return fmt.Sprintf("%s_%s", s.Kind, s.ApiLevel)
 }
 
 // Valid checks if this SdkSpec is well-formed. Note however that true doesn't mean that the
@@ -177,10 +134,10 @@
 	}
 
 	if s.Kind == SdkPublic || s.Kind == SdkSystem {
-		if s.Version.IsCurrent() {
+		if s.ApiLevel.IsCurrent() {
 			if i, err := strconv.Atoi(currentSdkVersion); err == nil {
-				version := SdkVersion(i)
-				return SdkSpec{s.Kind, version, s.Raw}
+				apiLevel := uncheckedFinalApiLevel(i)
+				return SdkSpec{s.Kind, apiLevel, s.Raw}
 			}
 			panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion))
 		}
@@ -190,10 +147,10 @@
 
 // UsePrebuilt determines whether prebuilt SDK should be used for this SdkSpec with the given context.
 func (s SdkSpec) UsePrebuilt(ctx EarlyModuleContext) bool {
-	if s.Version.IsCurrent() {
+	if s.ApiLevel.IsCurrent() {
 		// "current" can be built from source and be from prebuilt SDK
 		return ctx.Config().AlwaysUsePrebuiltSdks()
-	} else if s.Version.IsNumbered() {
+	} else if !s.ApiLevel.IsPreview() {
 		// validation check
 		if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && s.Kind != SdkModule {
 			panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind))
@@ -206,50 +163,60 @@
 	return false
 }
 
-// EffectiveVersion converts an SdkSpec into the concrete SdkVersion that the module
-// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
-// it returns FutureApiLevel(10000).
-func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (SdkVersion, error) {
+// EffectiveVersion converts an SdkSpec into the concrete ApiLevel that the module should use. For
+// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns
+// FutureApiLevel(10000).
+func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (ApiLevel, error) {
 	if !s.Valid() {
-		return s.Version, fmt.Errorf("invalid sdk version %q", s.Raw)
+		return s.ApiLevel, fmt.Errorf("invalid sdk version %q", s.Raw)
 	}
 
 	if ctx.DeviceSpecific() || ctx.SocSpecific() {
 		s = s.ForVendorPartition(ctx)
 	}
-	if s.Version.IsNumbered() {
-		return s.Version, nil
+	if !s.ApiLevel.IsPreview() {
+		return s.ApiLevel, nil
 	}
-	return SdkVersion(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()), nil
+	ret := ctx.Config().DefaultAppTargetSdk(ctx)
+	if ret.IsPreview() {
+		return FutureApiLevel, nil
+	}
+	return ret, nil
 }
 
 // EffectiveVersionString converts an SdkSpec into the concrete version string that the module
 // should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
 // it returns the codename (P, Q, R, etc.)
 func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) {
-	ver, err := s.EffectiveVersion(ctx)
-	if err == nil && int(ver) == ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt() {
-		return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
+	if !s.Valid() {
+		return s.ApiLevel.String(), fmt.Errorf("invalid sdk version %q", s.Raw)
 	}
-	return ver.String(), err
+
+	if ctx.DeviceSpecific() || ctx.SocSpecific() {
+		s = s.ForVendorPartition(ctx)
+	}
+	if !s.ApiLevel.IsPreview() {
+		return s.ApiLevel.String(), nil
+	}
+	return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
 }
 
 func SdkSpecFrom(str string) SdkSpec {
 	switch str {
 	// special cases first
 	case "":
-		return SdkSpec{SdkPrivate, SdkVersionNone, str}
+		return SdkSpec{SdkPrivate, NoneApiLevel, str}
 	case "none":
-		return SdkSpec{SdkNone, SdkVersionNone, str}
+		return SdkSpec{SdkNone, NoneApiLevel, str}
 	case "core_platform":
-		return SdkSpec{SdkCorePlatform, SdkVersionNone, str}
+		return SdkSpec{SdkCorePlatform, NoneApiLevel, str}
 	default:
 		// the syntax is [kind_]version
 		sep := strings.LastIndex(str, "_")
 
 		var kindString string
 		if sep == 0 {
-			return SdkSpec{SdkInvalid, SdkVersionNone, str}
+			return SdkSpec{SdkInvalid, NoneApiLevel, str}
 		} else if sep == -1 {
 			kindString = ""
 		} else {
@@ -272,19 +239,19 @@
 		case "system_server":
 			kind = SdkSystemServer
 		default:
-			return SdkSpec{SdkInvalid, SdkVersionNone, str}
+			return SdkSpec{SdkInvalid, NoneApiLevel, str}
 		}
 
-		var version SdkVersion
+		var apiLevel ApiLevel
 		if versionString == "current" {
-			version = SdkVersionCurrent
+			apiLevel = FutureApiLevel
 		} else if i, err := strconv.Atoi(versionString); err == nil {
-			version = SdkVersion(i)
+			apiLevel = uncheckedFinalApiLevel(i)
 		} else {
-			return SdkSpec{SdkInvalid, SdkVersionNone, str}
+			return SdkSpec{SdkInvalid, apiLevel, str}
 		}
 
-		return SdkSpec{kind, version, str}
+		return SdkSpec{kind, apiLevel, str}
 	}
 }
 
@@ -292,7 +259,7 @@
 	// Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module)
 	// Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29,
 	// sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current
-	if s.Kind != SdkSystem || !s.Version.IsNumbered() {
+	if s.Kind != SdkSystem || s.ApiLevel.IsPreview() {
 		return true
 	}
 	allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions()
@@ -302,7 +269,7 @@
 			allowedVersions = systemSdkVersions
 		}
 	}
-	if len(allowedVersions) > 0 && !InList(s.Version.String(), allowedVersions) {
+	if len(allowedVersions) > 0 && !InList(s.ApiLevel.String(), allowedVersions) {
 		ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
 			s.Raw, allowedVersions)
 		return false
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 6b7395b..8510f30 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -55,7 +55,7 @@
 		if err != nil {
 			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
 		}
-		if minSdkVersion >= 23 {
+		if minSdkVersion.FinalOrFutureInt() >= 23 {
 			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !useEmbeddedNativeLibs))
 		} else if useEmbeddedNativeLibs {
 			ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
diff --git a/java/app.go b/java/app.go
index ec30b49..dcb3bc6 100755
--- a/java/app.go
+++ b/java/app.go
@@ -288,7 +288,7 @@
 
 		if minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx); err == nil {
 			a.checkJniLibsSdkVersion(ctx, minSdkVersion)
-			android.CheckMinSdkVersion(a, ctx, minSdkVersion.ApiLevel(ctx))
+			android.CheckMinSdkVersion(a, ctx, minSdkVersion)
 		} else {
 			ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
 		}
@@ -304,7 +304,7 @@
 // because, sdk_version is overridden by min_sdk_version (if set as smaller)
 // and sdkLinkType is checked with dependencies so we can be sure that the whole dependency tree
 // will meet the requirements.
-func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.SdkVersion) {
+func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.ApiLevel) {
 	// It's enough to check direct JNI deps' sdk_version because all transitive deps from JNI deps are checked in cc.checkLinkType()
 	ctx.VisitDirectDeps(func(m android.Module) {
 		if !IsJniDepTag(ctx.OtherModuleDependencyTag(m)) {
@@ -315,7 +315,7 @@
 		// We can rely on android.SdkSpec to convert it to <number> so that "current" is
 		// handled properly regardless of sdk finalization.
 		jniSdkVersion, err := android.SdkSpecFrom(dep.SdkVersion()).EffectiveVersion(ctx)
-		if err != nil || minSdkVersion < jniSdkVersion {
+		if err != nil || minSdkVersion.LessThan(jniSdkVersion) {
 			ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)",
 				dep.SdkVersion(), minSdkVersion, ctx.ModuleName())
 			return
@@ -333,7 +333,7 @@
 	}
 
 	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-	return (minSdkVersion >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) ||
+	return (minSdkVersion.FinalOrFutureInt() >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) ||
 		!apexInfo.IsForPlatform()
 }
 
diff --git a/java/base.go b/java/base.go
index 73e5352..9bc0738 100644
--- a/java/base.go
+++ b/java/base.go
@@ -535,7 +535,7 @@
 }
 
 func (j *Module) MinSdkVersionString() string {
-	return j.MinSdkVersion().Version.String()
+	return j.MinSdkVersion().ApiLevel.String()
 }
 
 func (j *Module) AvailableFor(what string) bool {
@@ -1255,7 +1255,7 @@
 
 	if ctx.Device() {
 		lintSDKVersionString := func(sdkSpec android.SdkSpec) string {
-			if v := sdkSpec.Version; v.IsNumbered() {
+			if v := sdkSpec.ApiLevel; !v.IsPreview() {
 				return v.String()
 			} else {
 				return ctx.Config().DefaultAppTargetSdk(ctx).String()
@@ -1482,7 +1482,7 @@
 	if err != nil {
 		return err
 	}
-	if ver.ApiLevel(ctx).GreaterThan(sdkVersion) {
+	if ver.GreaterThan(sdkVersion) {
 		return fmt.Errorf("newer SDK(%v)", ver)
 	}
 	return nil
diff --git a/java/dex.go b/java/dex.go
index 5c6d41d..7898e9d 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"strconv"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -179,7 +180,7 @@
 		ctx.PropertyErrorf("min_sdk_version", "%s", err)
 	}
 
-	flags = append(flags, "--min-api "+effectiveVersion.AsNumberString())
+	flags = append(flags, "--min-api "+strconv.Itoa(effectiveVersion.FinalOrFutureInt()))
 	return flags
 }
 
diff --git a/java/java.go b/java/java.go
index 5fe8814..fa7c96e 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1156,7 +1156,7 @@
 }
 
 func (j *Import) MinSdkVersionString() string {
-	return j.MinSdkVersion().Version.String()
+	return j.MinSdkVersion().ApiLevel.String()
 }
 
 func (j *Import) Prebuilt() *android.Prebuilt {
@@ -1370,7 +1370,7 @@
 	if err != nil {
 		return err
 	}
-	if ver.ApiLevel(ctx).GreaterThan(sdkVersion) {
+	if ver.GreaterThan(sdkVersion) {
 		return fmt.Errorf("newer SDK(%v)", ver)
 	}
 	return nil
diff --git a/java/sdk.go b/java/sdk.go
index b546ca0..f324b76 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -51,9 +51,9 @@
 	if err != nil {
 		ctx.PropertyErrorf("sdk_version", "%s", err)
 	}
-	if sdk <= 23 {
+	if sdk.FinalOrFutureInt() <= 23 {
 		return JAVA_VERSION_7
-	} else if sdk <= 29 {
+	} else if sdk.FinalOrFutureInt() <= 29 {
 		return JAVA_VERSION_8
 	} else {
 		return JAVA_VERSION_9
@@ -76,11 +76,11 @@
 	}
 
 	if sdkVersion.UsePrebuilt(ctx) {
-		dir := filepath.Join("prebuilts", "sdk", sdkVersion.Version.String(), sdkVersion.Kind.String())
+		dir := filepath.Join("prebuilts", "sdk", sdkVersion.ApiLevel.String(), sdkVersion.Kind.String())
 		jar := filepath.Join(dir, "android.jar")
 		// There's no aidl for other SDKs yet.
 		// TODO(77525052): Add aidl files for other SDKs too.
-		publicDir := filepath.Join("prebuilts", "sdk", sdkVersion.Version.String(), "public")
+		publicDir := filepath.Join("prebuilts", "sdk", sdkVersion.ApiLevel.String(), "public")
 		aidl := filepath.Join(publicDir, "framework.aidl")
 		jarPath := android.ExistentPathForSource(ctx, jar)
 		aidlPath := android.ExistentPathForSource(ctx, aidl)
@@ -89,7 +89,7 @@
 		if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
 			return sdkDep{
 				invalidVersion: true,
-				bootclasspath:  []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.Kind, sdkVersion.Version.String())},
+				bootclasspath:  []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.Kind, sdkVersion.ApiLevel.String())},
 			}
 		}
 
@@ -105,7 +105,7 @@
 
 		var systemModules string
 		if defaultJavaLanguageVersion(ctx, sdkVersion).usesJavaModules() {
-			systemModules = "sdk_public_" + sdkVersion.Version.String() + "_system_modules"
+			systemModules = "sdk_public_" + sdkVersion.ApiLevel.String() + "_system_modules"
 		}
 
 		return sdkDep{
diff --git a/java/sdk_library.go b/java/sdk_library.go
index ebb2154..37b8d9f 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -817,7 +817,7 @@
 func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
 
 	// If a specific numeric version has been requested then use prebuilt versions of the sdk.
-	if sdkVersion.Version.IsNumbered() {
+	if !sdkVersion.ApiLevel.IsPreview() {
 		return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion)
 	}
 
@@ -1466,15 +1466,15 @@
 }
 
 func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s android.SdkSpec) android.Paths {
-	var ver android.SdkVersion
+	var ver android.ApiLevel
 	var kind android.SdkKind
 	if s.UsePrebuilt(ctx) {
-		ver = s.Version
+		ver = s.ApiLevel
 		kind = s.Kind
 	} else {
 		// We don't have prebuilt SDK for the specific sdkVersion.
 		// Instead of breaking the build, fallback to use "system_current"
-		ver = android.SdkVersionCurrent
+		ver = android.FutureApiLevel
 		kind = android.SdkSystem
 	}