Reland "Change minApiLevel on InternalOptions from int to AndroidApiLevel"

This reverts commit 90e4860801ffe94a6e91587747fe7105a4cd4740.

Change-Id: I5fb295ff316b243e9f64497db57b5d24d8ea6673
diff --git a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
index a4af022..c856d87 100644
--- a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
+++ b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
@@ -104,7 +104,7 @@
 
   InternalOptions getInternalOptions() {
     InternalOptions options = new InternalOptions(factory, getReporter());
-    options.minApiLevel = minApiLevel;
+    options.minApiLevel = AndroidApiLevel.getAndroidApiLevel(minApiLevel);
     options.desugaredLibraryConfiguration = desugaredLibraryConfiguration;
     return options;
   }
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 8863e35..1ef4a6e 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -458,7 +458,7 @@
     internal.mainDexListConsumer = getMainDexListConsumer();
     internal.minimalMainDex = internal.debug || minimalMainDex;
     internal.enableMainDexListCheck = enableMainDexListCheck;
-    internal.minApiLevel = getMinApiLevel();
+    internal.minApiLevel = AndroidApiLevel.getAndroidApiLevel(getMinApiLevel());
     internal.intermediate = intermediate;
     internal.readCompileTimeAnnotations = intermediate;
     internal.desugarGraphConsumer = desugarGraphConsumer;
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java
index 9492e12..b21bb03 100644
--- a/src/main/java/com/android/tools/r8/ExtractMarker.java
+++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -98,11 +98,10 @@
     }
   }
 
-  private static Collection<Marker> extractMarker(AndroidApp app)
-      throws IOException, ExecutionException {
+  private static Collection<Marker> extractMarker(AndroidApp app) throws IOException {
     InternalOptions options = new InternalOptions();
     options.skipReadingDexCode = true;
-    options.minApiLevel = AndroidApiLevel.P.getLevel();
+    options.minApiLevel = AndroidApiLevel.P;
     DexApplication dexApp = new ApplicationReader(app, options, new Timing("ExtractMarker")).read();
     return dexApp.dexItemFactory.extractMarkers();
   }
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index fc9a567..9ec502c 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.inspector.Inspector;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
 import com.android.tools.r8.utils.DumpInputFlags;
@@ -160,7 +161,7 @@
     internal.debug = getMode() == CompilationMode.DEBUG;
     assert internal.mainDexListConsumer == null;
     assert !internal.minimalMainDex;
-    internal.minApiLevel = getMinApiLevel();
+    internal.minApiLevel = AndroidApiLevel.getAndroidApiLevel(getMinApiLevel());
     assert !internal.intermediate;
     assert internal.readCompileTimeAnnotations;
     internal.programConsumer = getProgramConsumer();
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 7aed2af..581d808 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -105,7 +105,6 @@
 import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer;
 import com.android.tools.r8.synthesis.SyntheticFinalization;
 import com.android.tools.r8.synthesis.SyntheticItems;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.CfgPrinter;
 import com.android.tools.r8.utils.CollectionUtils;
@@ -332,7 +331,7 @@
               options.itemFactory, options.getProguardConfiguration().getRules())) {
             synthesizedProguardRules.add(
                 ProguardConfigurationUtils.buildAssumeNoSideEffectsRuleForApiLevel(
-                    options.itemFactory, AndroidApiLevel.getAndroidApiLevel(options.minApiLevel)));
+                    options.itemFactory, options.minApiLevel));
           }
         }
         SubtypingInfo subtypingInfo = new SubtypingInfo(appView);
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 4fdb44d..7d4b172 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -833,7 +833,10 @@
     assert !internal.debug;
     internal.debug = getMode() == CompilationMode.DEBUG;
     internal.programConsumer = getProgramConsumer();
-    internal.minApiLevel = getMinApiLevel();
+    internal.minApiLevel =
+        getMinApiLevel() < 0
+            ? AndroidApiLevel.B
+            : AndroidApiLevel.getAndroidApiLevel(getMinApiLevel());
     internal.desugarState = getDesugarState();
     assert internal.isShrinking() == getEnableTreeShaking();
     assert internal.isMinifying() == getEnableMinification();
diff --git a/src/main/java/com/android/tools/r8/androidapi/AvailableApiExceptions.java b/src/main/java/com/android/tools/r8/androidapi/AvailableApiExceptions.java
index c44f1f4..606d653 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AvailableApiExceptions.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AvailableApiExceptions.java
@@ -26,7 +26,7 @@
   private final Set<DexType> exceptions;
 
   public AvailableApiExceptions(InternalOptions options) {
-    assert options.minApiLevel < AndroidApiLevel.L.getLevel();
+    assert options.minApiLevel.isLessThan(AndroidApiLevel.L);
     exceptions = build(options.itemFactory, options.minApiLevel);
   }
 
@@ -35,9 +35,9 @@
   }
 
   /** The content of this method can be regenerated with GenerateAvailableExceptions.main. */
-  public static Set<DexType> build(DexItemFactory factory, int minApiLevel) {
+  public static Set<DexType> build(DexItemFactory factory, AndroidApiLevel minApiLevel) {
     Set<DexType> types = SetUtils.newIdentityHashSet(333);
-    if (minApiLevel >= 1) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.B)) {
       types.add(factory.createType("Landroid/app/PendingIntent$CanceledException;"));
       types.add(factory.createType("Landroid/content/ActivityNotFoundException;"));
       types.add(factory.createType("Landroid/content/IntentFilter$MalformedMimeTypeException;"));
@@ -305,17 +305,17 @@
       types.add(factory.createType("Lorg/xml/sax/SAXParseException;"));
       types.add(factory.createType("Lorg/xmlpull/v1/XmlPullParserException;"));
     }
-    if (minApiLevel >= 4) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.D)) {
       types.add(factory.createType("Landroid/content/IntentSender$SendIntentException;"));
     }
-    if (minApiLevel >= 5) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.E)) {
       types.add(factory.createType("Landroid/accounts/AccountsException;"));
       types.add(factory.createType("Landroid/accounts/AuthenticatorException;"));
       types.add(factory.createType("Landroid/accounts/NetworkErrorException;"));
       types.add(factory.createType("Landroid/accounts/OperationCanceledException;"));
       types.add(factory.createType("Landroid/content/OperationApplicationException;"));
     }
-    if (minApiLevel >= 8) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.F)) {
       types.add(factory.createType("Ljavax/xml/datatype/DatatypeConfigurationException;"));
       types.add(factory.createType("Ljavax/xml/transform/TransformerConfigurationException;"));
       types.add(factory.createType("Ljavax/xml/transform/TransformerException;"));
@@ -326,7 +326,7 @@
       types.add(factory.createType("Ljavax/xml/xpath/XPathFunctionException;"));
       types.add(factory.createType("Lorg/w3c/dom/ls/LSException;"));
     }
-    if (minApiLevel >= 9) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.G)) {
       types.add(factory.createType("Landroid/net/sip/SipException;"));
       types.add(factory.createType("Landroid/nfc/FormatException;"));
       types.add(factory.createType("Ljava/io/IOError;"));
@@ -346,10 +346,10 @@
       types.add(factory.createType("Ljava/util/ServiceConfigurationError;"));
       types.add(factory.createType("Ljava/util/zip/ZipError;"));
     }
-    if (minApiLevel >= 10) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.G_MR1)) {
       types.add(factory.createType("Landroid/nfc/TagLostException;"));
     }
-    if (minApiLevel >= 11) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.H)) {
       types.add(factory.createType("Landroid/app/Fragment$InstantiationException;"));
       types.add(factory.createType("Landroid/database/sqlite/SQLiteAccessPermException;"));
       types.add(
@@ -372,28 +372,28 @@
       types.add(factory.createType("Landroid/util/MalformedJsonException;"));
       types.add(factory.createType("Landroid/view/KeyCharacterMap$UnavailableException;"));
     }
-    if (minApiLevel >= 14) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.I)) {
       types.add(factory.createType("Landroid/security/KeyChainException;"));
       types.add(factory.createType("Landroid/util/NoSuchPropertyException;"));
     }
-    if (minApiLevel >= 15) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.I_MR1)) {
       types.add(factory.createType("Landroid/os/TransactionTooLargeException;"));
     }
-    if (minApiLevel >= 16) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.J)) {
       types.add(factory.createType("Landroid/media/MediaCodec$CryptoException;"));
       types.add(factory.createType("Landroid/media/MediaCryptoException;"));
       types.add(factory.createType("Landroid/os/OperationCanceledException;"));
     }
-    if (minApiLevel >= 17) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.J_MR1)) {
       types.add(factory.createType("Landroid/view/WindowManager$InvalidDisplayException;"));
     }
-    if (minApiLevel >= 18) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.J_MR2)) {
       types.add(factory.createType("Landroid/media/DeniedByServerException;"));
       types.add(factory.createType("Landroid/media/MediaDrmException;"));
       types.add(factory.createType("Landroid/media/NotProvisionedException;"));
       types.add(factory.createType("Landroid/media/UnsupportedSchemeException;"));
     }
-    if (minApiLevel >= 19) {
+    if (minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.K)) {
       types.add(factory.createType("Landroid/media/ResourceBusyException;"));
       types.add(
           factory.createType("Landroid/os/ParcelFileDescriptor$FileDescriptorDetachedException;"));
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index e0c1cc2..31d40bb 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -261,7 +261,7 @@
       return true;
     }
     AndroidApiLevel nativeMultiDex = AndroidApiLevel.L;
-    if (options.minApiLevel < nativeMultiDex.getLevel()) {
+    if (options.minApiLevel.isLessThan(nativeMultiDex)) {
       return true;
     }
     assert options.mainDexKeepRules.isEmpty();
@@ -270,13 +270,12 @@
     return true;
   }
 
-  private int validateOrComputeMinApiLevel(int computedMinApiLevel, DexReader dexReader) {
+  private AndroidApiLevel validateOrComputeMinApiLevel(
+      AndroidApiLevel computedMinApiLevel, DexReader dexReader) {
     DexVersion version = dexReader.getDexVersion();
-    if (options.minApiLevel == AndroidApiLevel.getDefault().getLevel()) {
-      computedMinApiLevel = Math
-          .max(computedMinApiLevel, AndroidApiLevel.getMinAndroidApiLevel(version).getLevel());
-    } else if (!version
-        .matchesApiLevel(AndroidApiLevel.getAndroidApiLevel(options.minApiLevel))) {
+    if (options.minApiLevel == AndroidApiLevel.getDefault()) {
+      computedMinApiLevel = computedMinApiLevel.max(AndroidApiLevel.getMinAndroidApiLevel(version));
+    } else if (!version.matchesApiLevel(options.minApiLevel)) {
       throw new CompilationError("Dex file with version '" + version.getIntValue() +
           "' cannot be used with min sdk level '" + options.minApiLevel + "'.");
     }
@@ -340,7 +339,7 @@
       }
       hasReadProgramResourceFromDex = true;
       List<DexParser<DexProgramClass>> dexParsers = new ArrayList<>(dexSources.size());
-      int computedMinApiLevel = options.minApiLevel;
+      AndroidApiLevel computedMinApiLevel = options.minApiLevel;
       for (ProgramResource input : dexSources) {
         DexReader dexReader = new DexReader(input);
         if (options.passthroughDexCode) {
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 42bd66b..dc93c37 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -318,7 +318,7 @@
       return true;
     }
 
-    int apiLevel = options.minApiLevel;
+    AndroidApiLevel apiLevel = options.minApiLevel;
     for (DexField field : mapping.getFields()) {
       assert field.name.isValidSimpleName(apiLevel);
     }
@@ -815,8 +815,7 @@
     dest.putBytes(
         options.testing.forceDexVersionBytes != null
             ? options.testing.forceDexVersionBytes
-            : DexVersion.getDexVersion(AndroidApiLevel.getAndroidApiLevel(options.minApiLevel))
-                .getBytes());
+            : DexVersion.getDexVersion(options.minApiLevel).getBytes());
     dest.putByte(Constants.DEX_FILE_MAGIC_SUFFIX);
     // Leave out checksum and signature for now.
     dest.moveTo(Constants.FILE_SIZE_OFFSET);
@@ -1099,7 +1098,7 @@
     private final Map<DexProgramClass, DexAnnotationDirectory> clazzToAnnotationDirectory
         = new HashMap<>();
 
-    private final int minApiLevel;
+    private final AndroidApiLevel minApiLevel;
 
     private static <T> Object2IntMap<T> createObject2IntMap() {
       Object2IntMap<T> result = new Object2IntLinkedOpenHashMap<>();
@@ -1148,7 +1147,7 @@
     public boolean add(DexAnnotationSet annotationSet) {
       // Until we fully drop support for API levels < 17, we have to emit an empty annotation set to
       // work around a DALVIK bug. See b/36951668.
-      if ((minApiLevel >= AndroidApiLevel.J_MR1.getLevel()) && annotationSet.isEmpty()) {
+      if ((minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.J_MR1)) && annotationSet.isEmpty()) {
         return false;
       }
       return add(annotationSets, annotationSet);
@@ -1300,7 +1299,7 @@
     public int getOffsetFor(DexAnnotationSet annotationSet) {
       // Until we fully drop support for API levels < 17, we have to emit an empty annotation set to
       // work around a DALVIK bug. See b/36951668.
-      if ((minApiLevel >= AndroidApiLevel.J_MR1.getLevel()) && annotationSet.isEmpty()) {
+      if ((minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.J_MR1)) && annotationSet.isEmpty()) {
         return 0;
       }
       return lookup(annotationSet, annotationSets);
@@ -1351,7 +1350,7 @@
     void setOffsetFor(DexAnnotationSet annotationSet, int offset) {
       // Until we fully drop support for API levels < 17, we have to emit an empty annotation set to
       // work around a DALVIK bug. See b/36951668.
-      assert (minApiLevel < AndroidApiLevel.J_MR1.getLevel()) || !annotationSet.isEmpty();
+      assert (minApiLevel.isLessThan(AndroidApiLevel.J_MR1)) || !annotationSet.isEmpty();
       setOffsetFor(annotationSet, offset, annotationSets);
     }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexString.java b/src/main/java/com/android/tools/r8/graph/DexString.java
index ba4d653..87630f2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexString.java
+++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -399,9 +399,9 @@
     }
   }
 
-  public static boolean isValidSimpleName(int apiLevel, String string) {
+  public static boolean isValidSimpleName(AndroidApiLevel apiLevel, String string) {
     // space characters are not allowed prior to Android R
-    if (apiLevel < AndroidApiLevel.R.getLevel()) {
+    if (apiLevel.isLessThan(AndroidApiLevel.R)) {
       int cp;
       for (int i = 0; i < string.length(); ) {
         cp = string.codePointAt(i);
@@ -414,9 +414,9 @@
     return true;
   }
 
-  public boolean isValidSimpleName(int apiLevel) {
+  public boolean isValidSimpleName(AndroidApiLevel apiLevel) {
     // space characters are not allowed prior to Android R
-    if (apiLevel < AndroidApiLevel.R.getLevel()) {
+    if (apiLevel.isLessThan(AndroidApiLevel.R)) {
       try {
         return isValidSimpleName(apiLevel, decode());
       } catch (UTFDataFormatException e) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index cc28692..e258037 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -165,19 +165,19 @@
 
       DexItemFactory factory = options.itemFactory;
 
-      if (options.minApiLevel < AndroidApiLevel.K.getLevel()) {
+      if (options.minApiLevel.isLessThan(AndroidApiLevel.K)) {
         initializeAndroidKMethodProviders(factory);
       }
-      if (options.minApiLevel < AndroidApiLevel.N.getLevel()) {
+      if (options.minApiLevel.isLessThan(AndroidApiLevel.N)) {
         initializeAndroidNMethodProviders(factory);
       }
-      if (options.minApiLevel < AndroidApiLevel.O.getLevel()) {
+      if (options.minApiLevel.isLessThan(AndroidApiLevel.O)) {
         initializeAndroidOMethodProviders(factory);
       }
-      if (options.minApiLevel < AndroidApiLevel.R.getLevel()) {
+      if (options.minApiLevel.isLessThan(AndroidApiLevel.R)) {
         initializeAndroidRMethodProviders(factory);
       }
-      if (options.minApiLevel < AndroidApiLevel.S.getLevel()) {
+      if (options.minApiLevel.isLessThan(AndroidApiLevel.S)) {
         initializeAndroidSMethodProviders(factory);
       }
 
@@ -186,13 +186,13 @@
       // libraries or natively. If Optional/Stream class is not present, we do not desugar to
       // avoid confusion in error messages.
       if (appView.rewritePrefix.hasRewrittenType(factory.optionalType, appView)
-          || options.minApiLevel >= AndroidApiLevel.N.getLevel()) {
+          || options.minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
         initializeJava9OptionalMethodProviders(factory);
         initializeJava10OptionalMethodProviders(factory);
         initializeJava11OptionalMethodProviders(factory);
       }
       if (appView.rewritePrefix.hasRewrittenType(factory.streamType, appView)
-          || options.minApiLevel >= AndroidApiLevel.N.getLevel()) {
+          || options.minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
         initializeStreamMethodProviders(factory);
       }
 
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
index ccc2ef7..8ac5e71 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -93,7 +93,7 @@
             + Version.LABEL
             + "\n");
     if (options.isGeneratingDex()) {
-      builder.append("# " + MARKER_KEY_MIN_API + ": " + options.minApiLevel + "\n");
+      builder.append("# " + MARKER_KEY_MIN_API + ": " + options.minApiLevel.getLevel() + "\n");
     }
     if (Version.isDevelopmentVersion()) {
       builder.append(
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 523552a..d902793 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -64,6 +64,10 @@
     return AndroidApiLevel.B;
   }
 
+  public AndroidApiLevel max(AndroidApiLevel other) {
+    return Ordered.max(this, other);
+  }
+
   public DexVersion getDexVersion() {
     return DexVersion.getDexVersion(this);
   }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 12126a4..849d641 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -383,7 +383,7 @@
     // since the output depends on the min API in this case. There is basically no min API entry
     // in R8 cf to cf.
     if (isGeneratingDex() || desugarState == DesugarState.ON) {
-      marker.setMinApi(minApiLevel);
+      marker.setMinApi(minApiLevel.getLevel());
     }
     if (desugaredLibraryConfiguration.getIdentifier() != null) {
       marker.setDesugaredLibraryIdentifiers(desugaredLibraryConfiguration.getIdentifier());
@@ -526,7 +526,7 @@
       getExtensiveInterfaceMethodMinifierLoggingFilter();
 
   public List<String> methodsFilter = ImmutableList.of();
-  public int minApiLevel = AndroidApiLevel.getDefault().getLevel();
+  public AndroidApiLevel minApiLevel = AndroidApiLevel.getDefault();
   // Skipping min_api check and compiling an intermediate result intended for later merging.
   // Intermediate builds also emits or update synthesized classes mapping.
   public boolean intermediate = false;
@@ -1505,7 +1505,7 @@
   }
 
   private boolean hasMinApi(AndroidApiLevel level) {
-    return minApiLevel >= level.getLevel();
+    return minApiLevel.isGreaterThanOrEqualTo(level);
   }
 
   /**
@@ -1588,7 +1588,7 @@
     // the highest known API level when the compiler is built. This ensures that when this is used
     // by the Android Platform build (which normally use an API level of 10000) there will be
     // no rewriting of backported methods. See b/147480264.
-    return desugarState.isOn() && minApiLevel <= AndroidApiLevel.LATEST.getLevel();
+    return desugarState.isOn() && minApiLevel.isLessThanOrEqualTo(AndroidApiLevel.LATEST);
   }
 
   public boolean enableTryWithResourcesDesugaring() {
@@ -1690,7 +1690,7 @@
   // being thrown on out of bounds.
   public boolean canUseSameArrayAndResultRegisterInArrayGetWide() {
     assert isGeneratingDex();
-    return minApiLevel > AndroidApiLevel.O_MR1.getLevel();
+    return minApiLevel.isGreaterThan(AndroidApiLevel.O_MR1);
   }
 
   // Some Lollipop versions of Art found in the wild perform invalid bounds
@@ -1707,7 +1707,7 @@
   //
   // See b/69364976 and b/77996377.
   public boolean canHaveBoundsCheckEliminationBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.M.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.M);
   }
 
   // MediaTek JIT compilers for KitKat phones did not implement the not
@@ -1723,7 +1723,7 @@
   // assumed to not change. If the receiver register is reused for something else the verifier
   // will fail and the code will not run.
   public boolean canHaveThisTypeVerifierBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.M.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.M);
   }
 
   // Art crashes if we do dead reference elimination of the receiver in release mode and Art
@@ -1732,13 +1732,13 @@
   //
   // See b/116683601 and b/116837585.
   public boolean canHaveThisJitCodeDebuggingBug() {
-    return minApiLevel < AndroidApiLevel.Q.getLevel();
+    return minApiLevel.isLessThan(AndroidApiLevel.Q);
   }
 
   // The dalvik jit had a bug where the long operations add, sub, or, xor and and would write
   // the first part of the result long before reading the second part of the input longs.
   public boolean canHaveOverlappingLongRegisterBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.L.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.L);
   }
 
   // Some dalvik versions found in the wild perform invalid JIT compilation of cmp-long
@@ -1771,7 +1771,7 @@
   //
   // See b/75408029.
   public boolean canHaveCmpLongBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.L.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.L);
   }
 
   // Some Lollipop VMs crash if there is a const instruction between a cmp and an if instruction.
@@ -1799,7 +1799,7 @@
   //
   // See b/115552239.
   public boolean canHaveCmpIfFloatBug() {
-    return minApiLevel < AndroidApiLevel.M.getLevel();
+    return minApiLevel.isLessThan(AndroidApiLevel.M);
   }
 
   // Some Lollipop VMs incorrectly optimize code with mul2addr instructions. In particular,
@@ -1821,7 +1821,7 @@
   //
   // This issue has only been observed on a Verizon Ellipsis 8 tablet. See b/76115465.
   public boolean canHaveMul2AddrBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.M.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.M);
   }
 
   // Some Marshmallow VMs create an incorrect doubly-linked list of instructions. When the VM
@@ -1830,7 +1830,7 @@
   //
   // See b/77842465.
   public boolean canHaveDex2OatLinkedListBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.N.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.N);
   }
 
   // dex2oat on Marshmallow VMs does aggressive inlining which can eat up all the memory on
@@ -1838,7 +1838,7 @@
   //
   // See b/111960171
   public boolean canHaveDex2OatInliningIssue() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.N.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.N);
   }
 
   // Art 7.0.0 and later Art JIT may perform an invalid optimization if a string new-instance does
@@ -1846,7 +1846,7 @@
   //
   // See b/78493232 and b/80118070.
   public boolean canHaveArtStringNewInitBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.Q.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.Q);
   }
 
   // Dalvik tracing JIT may perform invalid optimizations when int/float values are converted to
@@ -1854,7 +1854,7 @@
   //
   // See b/77496850.
   public boolean canHaveNumberConversionRegisterAllocationBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.L.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.L);
   }
 
   // Some Lollipop mediatek VMs have a peculiar bug where the inliner crashes if there is a
@@ -1867,7 +1867,7 @@
   //
   // See b/68378480.
   public boolean canHaveForwardingInitInliningBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.M.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.M);
   }
 
   // Some Lollipop x86_64 VMs have a bug causing a segfault if an exception handler directly targets
@@ -1879,7 +1879,7 @@
   //
   // See b/111337896.
   public boolean canHaveExceptionTargetingLoopHeaderBug() {
-    return isGeneratingDex() && !debug && minApiLevel < AndroidApiLevel.M.getLevel();
+    return isGeneratingDex() && !debug && minApiLevel.isLessThan(AndroidApiLevel.M);
   }
 
   // The Dalvik tracing JIT can trace past the end of the instruction stream and end up
@@ -1894,7 +1894,7 @@
   // We also could not insert any dead code (e.g. a return) because that would make mediatek
   // dominator calculations on 7.0.0 crash. See b/128926846.
   public boolean canHaveTracingPastInstructionsStreamBug() {
-    return minApiLevel < AndroidApiLevel.L.getLevel();
+    return minApiLevel.isLessThan(AndroidApiLevel.L);
   }
 
   // The art verifier incorrectly propagates type information for the following pattern:
@@ -1922,7 +1922,7 @@
   // Fixed in Android Q, see b/120985556.
   public boolean canHaveArtInstanceOfVerifierBug() {
     assert isGeneratingDex();
-    return minApiLevel < AndroidApiLevel.Q.getLevel();
+    return minApiLevel.isLessThan(AndroidApiLevel.Q);
   }
 
   // Some Art Lollipop version do not deal correctly with long-to-int conversions.
@@ -1945,7 +1945,7 @@
   public boolean canHaveLongToIntBug() {
     // We have only seen this happening on Lollipop arm64 backends. We have tested on
     // Marshmallow and Nougat arm64 devices and they do not have the bug.
-    return minApiLevel < AndroidApiLevel.M.getLevel();
+    return minApiLevel.isLessThan(AndroidApiLevel.M);
   }
 
   // The Art VM for Android N through P has a bug in the JIT that means that if the same
@@ -1958,7 +1958,7 @@
   //
   // See b/120164595.
   public boolean canHaveExceptionTypeBug() {
-    return minApiLevel < AndroidApiLevel.Q.getLevel();
+    return minApiLevel.isLessThan(AndroidApiLevel.Q);
   }
 
   // Art 4.0.4 fails with a verification error when a null-literal is being passed directly to an
@@ -1966,7 +1966,7 @@
   // elimination of check-cast instructions where the value being cast is the constant null.
   // See b/123269162.
   public boolean canHaveArtCheckCastVerifierBug() {
-    return minApiLevel < AndroidApiLevel.J.getLevel();
+    return minApiLevel.isLessThan(AndroidApiLevel.J);
   }
 
   // The verifier will merge A[] and B[] to Object[], even when both A and B implement an interface
@@ -1990,7 +1990,7 @@
   //
   // See b/131349148
   public boolean canHaveDalvikCatchHandlerVerificationBug() {
-    return isGeneratingClassFiles() || minApiLevel < AndroidApiLevel.L.getLevel();
+    return isGeneratingClassFiles() || minApiLevel.isLessThan(AndroidApiLevel.L);
   }
 
   // Having an invoke instruction that targets an abstract method on a non-abstract class will fail
@@ -1998,7 +1998,7 @@
   //
   // See b/132953944.
   public boolean canHaveDalvikAbstractMethodOnNonAbstractClassVerificationBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.L.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.L);
   }
 
   // On dalvik we see issues when using an int value in places where a boolean, byte, char, or short
@@ -2012,14 +2012,14 @@
   //
   // See also b/134304597 and b/124152497.
   public boolean canHaveDalvikIntUsedAsNonIntPrimitiveTypeBug() {
-    return isGeneratingClassFiles() || minApiLevel < AndroidApiLevel.L.getLevel();
+    return isGeneratingClassFiles() || minApiLevel.isLessThan(AndroidApiLevel.L);
   }
 
   // The standard library prior to API 19 did not contain a ZipFile that implemented Closable.
   //
   // See b/177532008.
   public boolean canHaveZipFileWithMissingCloseableBug() {
-    return isGeneratingClassFiles() || minApiLevel < AndroidApiLevel.K.getLevel();
+    return isGeneratingClassFiles() || minApiLevel.isLessThan(AndroidApiLevel.K);
   }
 
   // Some versions of Dalvik had a bug where a switch with a MAX_INT key would still go to
@@ -2027,7 +2027,7 @@
   //
   // See b/177790310.
   public boolean canHaveSwitchMaxIntBug() {
-    return isGeneratingDex() && minApiLevel < AndroidApiLevel.K.getLevel();
+    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.K);
   }
 
   // On Dalvik the methods Integer.parseInt and Long.parseLong does not support strings with a '+'
@@ -2035,6 +2035,6 @@
   //
   // See b/182137865.
   public boolean canParseNumbersWithPlusPrefix() {
-    return minApiLevel > AndroidApiLevel.K.getLevel();
+    return minApiLevel.isGreaterThan(AndroidApiLevel.K);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/AsmTestBase.java b/src/test/java/com/android/tools/r8/AsmTestBase.java
index a8b8a49..a3d5cf6 100644
--- a/src/test/java/com/android/tools/r8/AsmTestBase.java
+++ b/src/test/java/com/android/tools/r8/AsmTestBase.java
@@ -29,7 +29,7 @@
   protected void ensureSameOutput(String main, AndroidApiLevel apiLevel,
       List<String> args, byte[]... classes) throws Exception {
     AndroidApp app = buildAndroidApp(classes);
-    Consumer<InternalOptions> setMinApiLevel = o -> o.minApiLevel = apiLevel.getLevel();
+    Consumer<InternalOptions> setMinApiLevel = o -> o.minApiLevel = apiLevel;
     ProcessResult javaResult = runOnJavaRaw(main, Arrays.asList(classes), args);
     Consumer<ArtCommandBuilder> cmdBuilder = builder -> {
       for (String arg : args) {
diff --git a/src/test/java/com/android/tools/r8/debug/DoNotCrashOnAccessToThisRunner.java b/src/test/java/com/android/tools/r8/debug/DoNotCrashOnAccessToThisRunner.java
index 3e562cf..2363533 100644
--- a/src/test/java/com/android/tools/r8/debug/DoNotCrashOnAccessToThisRunner.java
+++ b/src/test/java/com/android/tools/r8/debug/DoNotCrashOnAccessToThisRunner.java
@@ -27,17 +27,19 @@
     DelayedDebugTestConfig cf =
         temp -> new CfDebugTestConfig().addPaths(ToolHelper.getClassPathForTests());
     DelayedDebugTestConfig d8 =
-        temp -> new D8DebugTestConfig().compileAndAdd(
-            temp,
-            ImmutableList.of(ToolHelper.getClassFileForTestClass(CLASS)),
-            options -> {
-              // Release mode so receiver can be clobbered.
-              options.debug = false;
-              // Api level M so that the workarounds for Lollipop verifier doesn't
-              // block the receiver register. We want to check b/116683601 which
-              // happens on at least 7.0.0.
-              options.minApiLevel = AndroidApiLevel.M.getLevel();
-            });
+        temp ->
+            new D8DebugTestConfig()
+                .compileAndAdd(
+                    temp,
+                    ImmutableList.of(ToolHelper.getClassFileForTestClass(CLASS)),
+                    options -> {
+                      // Release mode so receiver can be clobbered.
+                      options.debug = false;
+                      // Api level M so that the workarounds for Lollipop verifier doesn't
+                      // block the receiver register. We want to check b/116683601 which
+                      // happens on at least 7.0.0.
+                      options.minApiLevel = AndroidApiLevel.M;
+                    });
     return ImmutableList.of(new Object[]{"CF", cf}, new Object[]{"D8", d8});
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java b/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
index 8096c47..5cfc6cd 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
@@ -39,7 +39,7 @@
       // android.jar for that level.
       CodeInspector inspector = new CodeInspector(ToolHelper.getAndroidJar(apiLevel));
       InternalOptions options = new InternalOptions();
-      options.minApiLevel = apiLevel.getLevel();
+      options.minApiLevel = apiLevel;
       List<DexMethod> backportedMethods =
           BackportedMethodRewriter.generateListOfBackportedMethods(
               AndroidApp.builder().build(), options, ThreadUtils.getExecutorService(options));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java
index 8cf8b26..b4d7969 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java
@@ -27,7 +27,7 @@
     testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
 
     InternalOptions options = new InternalOptions();
-    options.minApiLevel = AndroidApiLevel.I_MR1.getLevel();
+    options.minApiLevel = AndroidApiLevel.I_MR1;
     assert options.canHaveArtCheckCastVerifierBug();
 
     testForR8(Backend.DEX)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
index b15cca9..14d84e7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
@@ -103,7 +103,7 @@
     assumeTrue(parameters.isDexRuntime());
     // Set the min API and create the raw app.
     InternalOptions options = new InternalOptions();
-    options.minApiLevel = parameters.getApiLevel().getLevel();
+    options.minApiLevel = parameters.getApiLevel();
     DirectMappedDexApplication application =
         new ApplicationReader(
                 AndroidApp.builder()
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index a01f7dc..0005549 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -812,7 +812,7 @@
     Timing timing = Timing.empty();
     InternalOptions options =
         new InternalOptions(new DexItemFactory(), new Reporter(diagnosticsHandler));
-    options.minApiLevel = minApi;
+    options.minApiLevel = AndroidApiLevel.getAndroidApiLevel(minApi);
     options.intermediate = intermediate;
     DexItemFactory factory = options.itemFactory;
     AppView<?> appView = AppView.createForR8(DexApplication.builder(options, timing).build());
diff --git a/src/test/java/com/android/tools/r8/regress/b69906048/Regress69906048Test.java b/src/test/java/com/android/tools/r8/regress/b69906048/Regress69906048Test.java
index 06c0ca4..bb1fed9 100644
--- a/src/test/java/com/android/tools/r8/regress/b69906048/Regress69906048Test.java
+++ b/src/test/java/com/android/tools/r8/regress/b69906048/Regress69906048Test.java
@@ -15,15 +15,16 @@
 
   @Test
   public void buildWithD8AndRunWithDalvikOrArt() throws Exception {
-    AndroidApp androidApp = ToolHelper.runR8(
-        ToolHelper.prepareR8CommandBuilder(
-            readClasses(ClassWithAnnotations.class, AnAnnotation.class))
-            .setDisableTreeShaking(true)
-            .setDisableMinification(true)
-            .addProguardConfiguration(
-                ImmutableList.of("-keepattributes *Annotation*"), Origin.unknown())
-            .build(),
-        options -> options.minApiLevel = ToolHelper.getMinApiLevelForDexVm().getLevel());
+    AndroidApp androidApp =
+        ToolHelper.runR8(
+            ToolHelper.prepareR8CommandBuilder(
+                    readClasses(ClassWithAnnotations.class, AnAnnotation.class))
+                .setDisableTreeShaking(true)
+                .setDisableMinification(true)
+                .addProguardConfiguration(
+                    ImmutableList.of("-keepattributes *Annotation*"), Origin.unknown())
+                .build(),
+            options -> options.minApiLevel = ToolHelper.getMinApiLevelForDexVm());
     String result = runOnArt(androidApp, ClassWithAnnotations.class);
     Assert.assertEquals("@" + AnAnnotation.class.getCanonicalName() + "()", result);
   }
diff --git a/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java b/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
index f3ab264..03efc25 100644
--- a/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
+++ b/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
@@ -456,10 +456,10 @@
       throws Exception {
     AndroidApp app = readClasses(Path.class, Log.class, testClass);
     if (compiler == Tool.D8) {
-      app = compileWithD8(app, o -> o.minApiLevel = apiLevel.getLevel());
+      app = compileWithD8(app, o -> o.minApiLevel = apiLevel);
     } else {
       assert compiler == Tool.R8;
-      app = compileWithR8(app, "-keep class * { *; }", o -> o.minApiLevel = apiLevel.getLevel());
+      app = compileWithR8(app, "-keep class * { *; }", o -> o.minApiLevel = apiLevel);
     }
     checkPathParserMethods(app, testClass, a, b);
   }
@@ -479,10 +479,10 @@
       throws Exception {
     AndroidApp app = readClasses(testClass);
     if (compiler == Tool.D8) {
-      app = compileWithD8(app, o -> o.minApiLevel = apiLevel.getLevel());
+      app = compileWithD8(app, o -> o.minApiLevel = apiLevel);
     } else {
       assert compiler == Tool.R8;
-      app = compileWithR8(app, "-keep class * { *; }", o -> o.minApiLevel = apiLevel.getLevel());
+      app = compileWithR8(app, "-keep class * { *; }", o -> o.minApiLevel = apiLevel);
     }
     CodeInspector inspector = new CodeInspector(app);
     DexItemFactory factory = inspector.getFactory();
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java
index eb269c1..d698e0b 100644
--- a/src/test/java/com/android/tools/r8/utils/Smali.java
+++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -108,7 +108,7 @@
     SingleFileConsumer consumer = new SingleFileConsumer();
     AndroidApp app = AndroidApp.builder().addDexProgramData(data, Origin.unknown()).build();
     InternalOptions options = new InternalOptions();
-    options.minApiLevel = apiLevel;
+    options.minApiLevel = AndroidApiLevel.getAndroidApiLevel(apiLevel);
     options.programConsumer = consumer;
     ExecutorService executor = ThreadUtils.getExecutorService(1);
     try {