blob: 49fb968177e9e3de18178b208176ab033bdb740c [file] [log] [blame]
// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.structural.Ordered;
import com.google.common.collect.ImmutableList;
import java.util.List;
/** Android API level description */
public class AndroidApiLevel implements Ordered<AndroidApiLevel> {
private static final List<AndroidApiLevel> valuesSorted;
public static final AndroidApiLevel B;
public static final AndroidApiLevel B_1_1;
public static final AndroidApiLevel C;
public static final AndroidApiLevel D;
public static final AndroidApiLevel E;
public static final AndroidApiLevel E_0_1;
public static final AndroidApiLevel E_MR1;
public static final AndroidApiLevel F;
public static final AndroidApiLevel G;
public static final AndroidApiLevel G_MR1;
public static final AndroidApiLevel H;
public static final AndroidApiLevel H_MR1;
public static final AndroidApiLevel H_MR2;
public static final AndroidApiLevel I;
public static final AndroidApiLevel I_MR1;
public static final AndroidApiLevel J;
public static final AndroidApiLevel J_MR1;
public static final AndroidApiLevel J_MR2;
public static final AndroidApiLevel K;
public static final AndroidApiLevel K_WATCH;
public static final AndroidApiLevel L;
public static final AndroidApiLevel L_MR1;
public static final AndroidApiLevel M;
public static final AndroidApiLevel N;
public static final AndroidApiLevel N_MR1;
public static final AndroidApiLevel O;
public static final AndroidApiLevel O_MR1;
public static final AndroidApiLevel P;
public static final AndroidApiLevel Q;
public static final AndroidApiLevel R;
public static final AndroidApiLevel S;
public static final AndroidApiLevel Sv2;
public static final AndroidApiLevel T;
public static final AndroidApiLevel U;
public static final AndroidApiLevel V;
public static final AndroidApiLevel BAKLAVA;
public static final AndroidApiLevel BAKLAVA_1;
public static final AndroidApiLevel CINNAMON_BUN;
public static final AndroidApiLevel MAIN;
// Used for API modeling of Android extension APIs.
public static final AndroidApiLevel EXTENSION;
// When updating LATEST and a new version goes public, add a new api-versions.xml to third_party
// and update the version and generated jar in AndroidApiDatabaseBuilderGeneratorTest. Together
// with that update third_party/android_jar/libcore_latest/core-oj.jar and run
// GenerateCovariantReturnTypeMethodsTest.
public static final AndroidApiLevel LATEST;
public static final AndroidApiLevel API_DATABASE_LEVEL;
public static final AndroidApiLevel UNKNOWN;
/** Constant used to signify some unknown min api when compiling platform. */
public static final int ANDROID_PLATFORM_CONSTANT = 10000;
static {
ImmutableList.Builder<AndroidApiLevel> builder = ImmutableList.builder();
builder.add(B = new AndroidApiLevel(1, 0, "B"));
builder.add(B_1_1 = new AndroidApiLevel(2, 0, "B_1_1"));
builder.add(C = new AndroidApiLevel(3, 0, "C"));
builder.add(D = new AndroidApiLevel(4, 0, "D"));
builder.add(E = new AndroidApiLevel(5, 0, "E"));
builder.add(E_0_1 = new AndroidApiLevel(6, 0, "E_0_1"));
builder.add(E_MR1 = new AndroidApiLevel(7, 0, "E_MR1"));
builder.add(F = new AndroidApiLevel(8, 0, "F"));
builder.add(G = new AndroidApiLevel(9, 0, "G"));
builder.add(G_MR1 = new AndroidApiLevel(10, 0, "G_MR1"));
builder.add(H = new AndroidApiLevel(11, 0, "H"));
builder.add(H_MR1 = new AndroidApiLevel(12, 0, "H_MR1"));
builder.add(H_MR2 = new AndroidApiLevel(13, 0, "H_MR2"));
builder.add(I = new AndroidApiLevel(14, 0, "I"));
builder.add(I_MR1 = new AndroidApiLevel(15, 0, "I_MR1"));
builder.add(J = new AndroidApiLevel(16, 0, "J"));
builder.add(J_MR1 = new AndroidApiLevel(17, 0, "J_MR1"));
builder.add(J_MR2 = new AndroidApiLevel(18, 0, "J_MR2"));
builder.add(K = new AndroidApiLevel(19, 0, "K"));
builder.add(K_WATCH = new AndroidApiLevel(20, 0, "K_WATCH"));
builder.add(L = new AndroidApiLevel(21, 0, "L"));
builder.add(L_MR1 = new AndroidApiLevel(22, 0, "L_MR1"));
builder.add(M = new AndroidApiLevel(23, 0, "M"));
builder.add(N = new AndroidApiLevel(24, 0, "N"));
builder.add(N_MR1 = new AndroidApiLevel(25, 0, "N_MR1"));
builder.add(O = new AndroidApiLevel(26, 0, "O"));
builder.add(O_MR1 = new AndroidApiLevel(27, 0, "O_MR1"));
builder.add(P = new AndroidApiLevel(28, 0, "P"));
builder.add(Q = new AndroidApiLevel(29, 0, "Q"));
builder.add(R = new AndroidApiLevel(30, 0, "R"));
builder.add(S = new AndroidApiLevel(31, 0, "S"));
builder.add(Sv2 = new AndroidApiLevel(32, 0, "Sv2"));
builder.add(T = new AndroidApiLevel(33, 0, "T"));
builder.add(U = new AndroidApiLevel(34, 0, "U"));
builder.add(V = new AndroidApiLevel(35, 0, "V"));
builder.add(BAKLAVA = new AndroidApiLevel(36, 0, "BAKLAVA"));
builder.add(BAKLAVA_1 = new AndroidApiLevel(36, 1, "BAKLAVA_1"));
builder.add(CINNAMON_BUN = new AndroidApiLevel(37, 0, "CINNAMON_BUN"));
builder.add(MAIN = new AndroidApiLevel(38, 0, "MAIN"));
builder.add(EXTENSION = new AndroidApiLevel(Integer.MAX_VALUE, 0, "EXTENSION"));
valuesSorted = builder.build();
assert valuesSorted.size() == 40;
assert checkValuesSorted();
LATEST = CINNAMON_BUN;
API_DATABASE_LEVEL = LATEST;
UNKNOWN = MAIN;
}
private final int level;
private final int minor;
private final String name;
private AndroidApiLevel(int level, int minor, String name) {
this.level = level;
this.minor = minor;
this.name = name;
}
private static boolean checkValuesSorted() {
for (int i = 1; i < valuesSorted.size(); i++) {
assert valuesSorted.get(i - 1).isLessThan(valuesSorted.get(i));
}
return true;
}
public int getLevel() {
return level;
}
public int getMinor() {
return minor;
}
public String getName() {
return "Android " + name;
}
public static AndroidApiLevel getDefault() {
return AndroidApiLevel.B;
}
public AndroidApiLevel max(AndroidApiLevel other) {
return Ordered.max(this, other);
}
public DexVersion getDexVersion() {
return DexVersion.getDexVersion(this);
}
public AndroidApiLevel next() {
return getAndroidApiLevel(getLevel() + 1);
}
public AndroidApiLevel verifyLevel(int expected) {
assert level == expected;
return this;
}
public static List<AndroidApiLevel> getAndroidApiLevelsSorted() {
return valuesSorted;
}
public static AndroidApiLevel getMinAndroidApiLevel(DexVersion dexVersion) {
switch (dexVersion) {
case V35:
return AndroidApiLevel.B;
case V37:
return AndroidApiLevel.N;
case V38:
return AndroidApiLevel.O;
case V39:
return AndroidApiLevel.P;
case V40:
return AndroidApiLevel.R;
case V41:
assert InternalOptions.containerDexApiLevel().isEqualTo(AndroidApiLevel.BAKLAVA);
return AndroidApiLevel.BAKLAVA;
default:
throw new Unreachable();
}
}
@Deprecated
@SuppressWarnings("InlineMeSuggester")
public static AndroidApiLevel getAndroidApiLevel(int apiLevel) {
return getAndroidApiLevel(apiLevel, 0);
}
public static AndroidApiLevel getAndroidApiLevel(int apiLevel, int minor) {
assert apiLevel > 0;
assert minor >= 0;
if ((apiLevel <= 35 && minor != 0) || minor > 1) {
throw new IllegalArgumentException();
}
assert CINNAMON_BUN == LATEST; // This has to be updated when we add new api levels.
assert UNKNOWN.isGreaterThan(LATEST);
switch (apiLevel) {
case 1:
return B;
case 2:
return B_1_1;
case 3:
return C;
case 4:
return D;
case 5:
return E;
case 6:
return E_0_1;
case 7:
return E_MR1;
case 8:
return F;
case 9:
return G;
case 10:
return G_MR1;
case 11:
return H;
case 12:
return H_MR1;
case 13:
return H_MR2;
case 14:
return I;
case 15:
return I_MR1;
case 16:
return J;
case 17:
return J_MR1;
case 18:
return J_MR2;
case 19:
return K;
case 20:
return K_WATCH;
case 21:
return L;
case 22:
return L_MR1;
case 23:
return M;
case 24:
return N;
case 25:
return N_MR1;
case 26:
return O;
case 27:
return O_MR1;
case 28:
return P;
case 29:
return Q;
case 30:
return R;
case 31:
return S;
case 32:
return Sv2;
case 33:
return T;
case 34:
return U;
case 35:
return V;
case 36:
assert minor <= 1;
return minor == 0 ? BAKLAVA : BAKLAVA_1;
case 37:
assert minor == 0;
return CINNAMON_BUN;
default:
return MAIN;
}
}
public static AndroidApiLevel parseAndroidApiLevel(String apiLevel) {
int dotPosition = apiLevel.indexOf('.');
if (dotPosition == -1) {
return AndroidApiLevel.getAndroidApiLevel(Integer.parseInt(apiLevel));
} else {
String majorApiLevel = apiLevel.substring(0, dotPosition);
String minorApiLevel = apiLevel.substring(dotPosition + 1);
assert Integer.parseInt(minorApiLevel) >= 0;
return AndroidApiLevel.getAndroidApiLevel(
Integer.parseInt(majorApiLevel), Integer.parseInt(minorApiLevel));
}
}
public byte serializeAsByte() {
if (this == EXTENSION) {
return 0x7f;
}
assert level < 64;
assert minor < 2; // Re-evaluate this when minor can be higher than 1.
return (byte) (level << 1 | minor);
}
public static AndroidApiLevel deserializeFromByte(byte b) {
if (b == 0x7f) {
return EXTENSION;
}
int i = Byte.toUnsignedInt(b);
int major = i >> 1;
int minor = i & 0x1;
return getAndroidApiLevel(major, minor);
}
@Override
public int compareTo(AndroidApiLevel other) {
return level != other.level ? level - other.level : minor - other.minor;
}
@Override
public String toString() {
return getName();
}
}