mirror of
https://github.com/revanced/Apktool.git
synced 2024-12-04 18:12:54 +01:00
Merge pull request #2604 from IgorEisberg/master
Fix baksmali without API version and various optimizations
This commit is contained in:
commit
d1e4478f82
@ -149,10 +149,10 @@ public class Main {
|
|||||||
decoder.setFrameworkDir(cli.getOptionValue("p"));
|
decoder.setFrameworkDir(cli.getOptionValue("p"));
|
||||||
}
|
}
|
||||||
if (cli.hasOption("m") || cli.hasOption("match-original")) {
|
if (cli.hasOption("m") || cli.hasOption("match-original")) {
|
||||||
decoder.setAnalysisMode(true, false);
|
decoder.setAnalysisMode(true);
|
||||||
}
|
}
|
||||||
if (cli.hasOption("api") || cli.hasOption("api-level")) {
|
if (cli.hasOption("api") || cli.hasOption("api-level")) {
|
||||||
decoder.setApi(Integer.parseInt(cli.getOptionValue("api")));
|
decoder.setApiLevel(Integer.parseInt(cli.getOptionValue("api")));
|
||||||
}
|
}
|
||||||
if (cli.hasOption("o") || cli.hasOption("output")) {
|
if (cli.hasOption("o") || cli.hasOption("output")) {
|
||||||
outDir = new File(cli.getOptionValue("o"));
|
outDir = new File(cli.getOptionValue("o"));
|
||||||
|
@ -31,8 +31,7 @@ import brut.androlib.src.SmaliBuilder;
|
|||||||
import brut.androlib.src.SmaliDecoder;
|
import brut.androlib.src.SmaliDecoder;
|
||||||
import brut.common.BrutException;
|
import brut.common.BrutException;
|
||||||
import brut.directory.*;
|
import brut.directory.*;
|
||||||
import brut.util.BrutIO;
|
import brut.util.*;
|
||||||
import brut.util.OS;
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -81,7 +80,7 @@ public class Androlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decodeSourcesSmali(File apkFile, File outDir, String filename, boolean bakdeb, int api)
|
public void decodeSourcesSmali(File apkFile, File outDir, String filename, boolean bakDeb, int apiLevel)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
File smaliDir;
|
File smaliDir;
|
||||||
@ -93,7 +92,7 @@ public class Androlib {
|
|||||||
OS.rmdir(smaliDir);
|
OS.rmdir(smaliDir);
|
||||||
smaliDir.mkdirs();
|
smaliDir.mkdirs();
|
||||||
LOGGER.info("Baksmaling " + filename + "...");
|
LOGGER.info("Baksmaling " + filename + "...");
|
||||||
SmaliDecoder.decode(apkFile, smaliDir, filename, bakdeb, api);
|
SmaliDecoder.decode(apkFile, smaliDir, filename, bakDeb, apiLevel);
|
||||||
} catch (BrutException ex) {
|
} catch (BrutException ex) {
|
||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
}
|
}
|
||||||
@ -193,7 +192,7 @@ public class Androlib {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decodeUnknownFiles(ExtFile apkFile, File outDir, ResTable resTable)
|
public void decodeUnknownFiles(ExtFile apkFile, File outDir)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
LOGGER.info("Copying unknown files...");
|
LOGGER.info("Copying unknown files...");
|
||||||
File unknownOut = new File(outDir, UNK_DIRNAME);
|
File unknownOut = new File(outDir, UNK_DIRNAME);
|
||||||
|
@ -67,14 +67,10 @@ public class ApkDecoder {
|
|||||||
mResTable = null;
|
mResTable = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOutDir(File outDir) throws AndrolibException {
|
public void setOutDir(File outDir) {
|
||||||
mOutDir = outDir;
|
mOutDir = outDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApi(int api) {
|
|
||||||
mApi = api;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void decode() throws AndrolibException, IOException, DirectoryException {
|
public void decode() throws AndrolibException, IOException, DirectoryException {
|
||||||
try {
|
try {
|
||||||
File outDir = getOutDir();
|
File outDir = getOutDir();
|
||||||
@ -102,9 +98,6 @@ public class ApkDecoder {
|
|||||||
case DECODE_RESOURCES_NONE:
|
case DECODE_RESOURCES_NONE:
|
||||||
mAndrolib.decodeResourcesRaw(mApkFile, outDir);
|
mAndrolib.decodeResourcesRaw(mApkFile, outDir);
|
||||||
if (mForceDecodeManifest == FORCE_DECODE_MANIFEST_FULL) {
|
if (mForceDecodeManifest == FORCE_DECODE_MANIFEST_FULL) {
|
||||||
setTargetSdkVersion();
|
|
||||||
setAnalysisMode(mAnalysisMode, true);
|
|
||||||
|
|
||||||
// done after raw decoding of resources because copyToDir overwrites dest files
|
// done after raw decoding of resources because copyToDir overwrites dest files
|
||||||
if (hasManifest()) {
|
if (hasManifest()) {
|
||||||
mAndrolib.decodeManifestWithResources(mApkFile, outDir, getResTable());
|
mAndrolib.decodeManifestWithResources(mApkFile, outDir, getResTable());
|
||||||
@ -112,9 +105,6 @@ public class ApkDecoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DECODE_RESOURCES_FULL:
|
case DECODE_RESOURCES_FULL:
|
||||||
setTargetSdkVersion();
|
|
||||||
setAnalysisMode(mAnalysisMode, true);
|
|
||||||
|
|
||||||
if (hasManifest()) {
|
if (hasManifest()) {
|
||||||
mAndrolib.decodeManifestWithResources(mApkFile, outDir, getResTable());
|
mAndrolib.decodeManifestWithResources(mApkFile, outDir, getResTable());
|
||||||
}
|
}
|
||||||
@ -142,7 +132,7 @@ public class ApkDecoder {
|
|||||||
break;
|
break;
|
||||||
case DECODE_SOURCES_SMALI:
|
case DECODE_SOURCES_SMALI:
|
||||||
case DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES:
|
case DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES:
|
||||||
mAndrolib.decodeSourcesSmali(mApkFile, outDir, "classes.dex", mBakDeb, mApi);
|
mAndrolib.decodeSourcesSmali(mApkFile, outDir, "classes.dex", mBakDeb, mApiLevel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,11 +148,11 @@ public class ApkDecoder {
|
|||||||
mAndrolib.decodeSourcesRaw(mApkFile, outDir, file);
|
mAndrolib.decodeSourcesRaw(mApkFile, outDir, file);
|
||||||
break;
|
break;
|
||||||
case DECODE_SOURCES_SMALI:
|
case DECODE_SOURCES_SMALI:
|
||||||
mAndrolib.decodeSourcesSmali(mApkFile, outDir, file, mBakDeb, mApi);
|
mAndrolib.decodeSourcesSmali(mApkFile, outDir, file, mBakDeb, mApiLevel);
|
||||||
break;
|
break;
|
||||||
case DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES:
|
case DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES:
|
||||||
if (file.startsWith("classes") && file.endsWith(".dex")) {
|
if (file.startsWith("classes") && file.endsWith(".dex")) {
|
||||||
mAndrolib.decodeSourcesSmali(mApkFile, outDir, file, mBakDeb, mApi);
|
mAndrolib.decodeSourcesSmali(mApkFile, outDir, file, mBakDeb, mApiLevel);
|
||||||
} else {
|
} else {
|
||||||
mAndrolib.decodeSourcesRaw(mApkFile, outDir, file);
|
mAndrolib.decodeSourcesRaw(mApkFile, outDir, file);
|
||||||
}
|
}
|
||||||
@ -174,7 +164,7 @@ public class ApkDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mAndrolib.decodeRawFiles(mApkFile, outDir, mDecodeAssets);
|
mAndrolib.decodeRawFiles(mApkFile, outDir, mDecodeAssets);
|
||||||
mAndrolib.decodeUnknownFiles(mApkFile, outDir, mResTable);
|
mAndrolib.decodeUnknownFiles(mApkFile, outDir);
|
||||||
mUncompressedFiles = new ArrayList<String>();
|
mUncompressedFiles = new ArrayList<String>();
|
||||||
mAndrolib.recordUncompressedFiles(mApkFile, mUncompressedFiles);
|
mAndrolib.recordUncompressedFiles(mApkFile, mUncompressedFiles);
|
||||||
mAndrolib.writeOriginalFiles(mApkFile, outDir);
|
mAndrolib.writeOriginalFiles(mApkFile, outDir);
|
||||||
@ -216,31 +206,20 @@ public class ApkDecoder {
|
|||||||
mDecodeAssets = mode;
|
mDecodeAssets = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAnalysisMode(boolean mode, boolean pass) throws AndrolibException{
|
public void setAnalysisMode(boolean mode) {
|
||||||
mAnalysisMode = mode;
|
mAnalysisMode = mode;
|
||||||
|
|
||||||
// only set mResTable, once it exists
|
if (mResTable != null) {
|
||||||
if (pass) {
|
|
||||||
if (mResTable == null) {
|
|
||||||
mResTable = getResTable();
|
|
||||||
}
|
|
||||||
mResTable.setAnalysisMode(mode);
|
mResTable.setAnalysisMode(mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTargetSdkVersion() throws AndrolibException {
|
public void setApiLevel(int apiLevel) {
|
||||||
if (mResTable == null) {
|
mApiLevel = apiLevel;
|
||||||
mResTable = mAndrolib.getResTable(mApkFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> sdkInfo = mResTable.getSdkInfo();
|
|
||||||
if (sdkInfo.get("targetSdkVersion") != null) {
|
|
||||||
mApi = Integer.parseInt(sdkInfo.get("targetSdkVersion"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBaksmaliDebugMode(boolean bakdeb) {
|
public void setBaksmaliDebugMode(boolean bakDeb) {
|
||||||
mBakDeb = bakdeb;
|
mBakDeb = bakDeb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setForceDelete(boolean forceDelete) {
|
public void setForceDelete(boolean forceDelete) {
|
||||||
@ -268,6 +247,7 @@ public class ApkDecoder {
|
|||||||
"Apk doesn't contain either AndroidManifest.xml file or resources.arsc file");
|
"Apk doesn't contain either AndroidManifest.xml file or resources.arsc file");
|
||||||
}
|
}
|
||||||
mResTable = mAndrolib.getResTable(mApkFile, hasResources);
|
mResTable = mAndrolib.getResTable(mApkFile, hasResources);
|
||||||
|
mResTable.setAnalysisMode(mAnalysisMode);
|
||||||
}
|
}
|
||||||
return mResTable;
|
return mResTable;
|
||||||
}
|
}
|
||||||
@ -344,8 +324,8 @@ public class ApkDecoder {
|
|||||||
meta.version = Androlib.getVersion();
|
meta.version = Androlib.getVersion();
|
||||||
meta.apkFileName = mApkFile.getName();
|
meta.apkFileName = mApkFile.getName();
|
||||||
|
|
||||||
if (mDecodeResources != DECODE_RESOURCES_NONE && (hasManifest() || hasResources())) {
|
if (mResTable != null) {
|
||||||
meta.isFrameworkApk = mAndrolib.isFrameworkApk(getResTable());
|
meta.isFrameworkApk = mAndrolib.isFrameworkApk(mResTable);
|
||||||
putUsesFramework(meta);
|
putUsesFramework(meta);
|
||||||
putSdkInfo(meta);
|
putSdkInfo(meta);
|
||||||
putPackageInfo(meta);
|
putPackageInfo(meta);
|
||||||
@ -359,8 +339,8 @@ public class ApkDecoder {
|
|||||||
mAndrolib.writeMetaFile(mOutDir, meta);
|
mAndrolib.writeMetaFile(mOutDir, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putUsesFramework(MetaInfo meta) throws AndrolibException {
|
private void putUsesFramework(MetaInfo meta) {
|
||||||
Set<ResPackage> pkgs = getResTable().listFramePackages();
|
Set<ResPackage> pkgs = mResTable.listFramePackages();
|
||||||
if (pkgs.isEmpty()) {
|
if (pkgs.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -380,8 +360,8 @@ public class ApkDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putSdkInfo(MetaInfo meta) throws AndrolibException {
|
private void putSdkInfo(MetaInfo meta) {
|
||||||
Map<String, String> info = getResTable().getSdkInfo();
|
Map<String, String> info = mResTable.getSdkInfo();
|
||||||
if (info.size() > 0) {
|
if (info.size() > 0) {
|
||||||
String refValue;
|
String refValue;
|
||||||
if (info.get("minSdkVersion") != null) {
|
if (info.get("minSdkVersion") != null) {
|
||||||
@ -407,12 +387,12 @@ public class ApkDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void putPackageInfo(MetaInfo meta) throws AndrolibException {
|
private void putPackageInfo(MetaInfo meta) throws AndrolibException {
|
||||||
String renamed = getResTable().getPackageRenamed();
|
String renamed = mResTable.getPackageRenamed();
|
||||||
String original = getResTable().getPackageOriginal();
|
String original = mResTable.getPackageOriginal();
|
||||||
|
|
||||||
int id = getResTable().getPackageId();
|
int id = mResTable.getPackageId();
|
||||||
try {
|
try {
|
||||||
id = getResTable().getPackage(renamed).getId();
|
id = mResTable.getPackage(renamed).getId();
|
||||||
} catch (UndefinedResObjectException ignored) {}
|
} catch (UndefinedResObjectException ignored) {}
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(original)) {
|
if (Strings.isNullOrEmpty(original)) {
|
||||||
@ -428,8 +408,8 @@ public class ApkDecoder {
|
|||||||
meta.packageInfo.forcedPackageId = String.valueOf(id);
|
meta.packageInfo.forcedPackageId = String.valueOf(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putVersionInfo(MetaInfo meta) throws AndrolibException {
|
private void putVersionInfo(MetaInfo meta) {
|
||||||
VersionInfo info = getResTable().getVersionInfo();
|
VersionInfo info = mResTable.getVersionInfo();
|
||||||
String refValue = ResXmlPatcher.pullValueFromStrings(mOutDir, info.versionName);
|
String refValue = ResXmlPatcher.pullValueFromStrings(mOutDir, info.versionName);
|
||||||
if (refValue != null) {
|
if (refValue != null) {
|
||||||
info.versionName = refValue;
|
info.versionName = refValue;
|
||||||
@ -437,6 +417,14 @@ public class ApkDecoder {
|
|||||||
meta.versionInfo = info;
|
meta.versionInfo = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void putSharedLibraryInfo(MetaInfo meta) {
|
||||||
|
meta.sharedLibrary = mResTable.getSharedLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putSparseResourcesInfo(MetaInfo meta) {
|
||||||
|
meta.sparseResources = mResTable.getSparseResources();
|
||||||
|
}
|
||||||
|
|
||||||
private void putUnknownInfo(MetaInfo meta) {
|
private void putUnknownInfo(MetaInfo meta) {
|
||||||
meta.unknownFiles = mAndrolib.mResUnknownFiles.getUnknownFiles();
|
meta.unknownFiles = mAndrolib.mResUnknownFiles.getUnknownFiles();
|
||||||
}
|
}
|
||||||
@ -447,14 +435,6 @@ public class ApkDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putSparseResourcesInfo(MetaInfo meta) {
|
|
||||||
meta.sparseResources = mResTable.getSparseResources();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putSharedLibraryInfo(MetaInfo meta) {
|
|
||||||
meta.sharedLibrary = mResTable.getSharedLibrary();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Androlib mAndrolib;
|
private final Androlib mAndrolib;
|
||||||
|
|
||||||
private final static Logger LOGGER = Logger.getLogger(Androlib.class.getName());
|
private final static Logger LOGGER = Logger.getLogger(Androlib.class.getName());
|
||||||
@ -471,5 +451,5 @@ public class ApkDecoder {
|
|||||||
private boolean mBakDeb = true;
|
private boolean mBakDeb = true;
|
||||||
private Collection<String> mUncompressedFiles;
|
private Collection<String> mUncompressedFiles;
|
||||||
private boolean mAnalysisMode = false;
|
private boolean mAnalysisMode = false;
|
||||||
private int mApi = 15;
|
private int mApiLevel = 0;
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,12 @@ import brut.androlib.res.data.*;
|
|||||||
import brut.androlib.res.decoder.*;
|
import brut.androlib.res.decoder.*;
|
||||||
import brut.androlib.res.decoder.ARSCDecoder.ARSCData;
|
import brut.androlib.res.decoder.ARSCDecoder.ARSCData;
|
||||||
import brut.androlib.res.decoder.ARSCDecoder.FlagsOffset;
|
import brut.androlib.res.decoder.ARSCDecoder.FlagsOffset;
|
||||||
import brut.directory.*;
|
|
||||||
import brut.androlib.res.util.ExtMXSerializer;
|
import brut.androlib.res.util.ExtMXSerializer;
|
||||||
import brut.androlib.res.util.ExtXmlSerializer;
|
import brut.androlib.res.util.ExtXmlSerializer;
|
||||||
import brut.androlib.res.xml.ResValuesXmlSerializable;
|
import brut.androlib.res.xml.ResValuesXmlSerializable;
|
||||||
import brut.androlib.res.xml.ResXmlPatcher;
|
import brut.androlib.res.xml.ResXmlPatcher;
|
||||||
import brut.common.BrutException;
|
import brut.common.BrutException;
|
||||||
|
import brut.directory.*;
|
||||||
import brut.util.*;
|
import brut.util.*;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.xmlpull.v1.XmlSerializer;
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
|
@ -32,14 +32,11 @@ import java.io.InputStream;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class SmaliBuilder {
|
public class SmaliBuilder {
|
||||||
|
|
||||||
public static void build(ExtFile smaliDir, File dexFile, int apiLevel) throws AndrolibException {
|
public static void build(ExtFile smaliDir, File dexFile, int apiLevel) throws AndrolibException {
|
||||||
new SmaliBuilder(smaliDir, dexFile, apiLevel).build();
|
new SmaliBuilder(smaliDir, dexFile, apiLevel).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void build(ExtFile smaliDir, File dexFile) throws AndrolibException {
|
|
||||||
new SmaliBuilder(smaliDir, dexFile, 0).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private SmaliBuilder(ExtFile smaliDir, File dexFile, int apiLevel) {
|
private SmaliBuilder(ExtFile smaliDir, File dexFile, int apiLevel) {
|
||||||
mSmaliDir = smaliDir;
|
mSmaliDir = smaliDir;
|
||||||
mDexFile = dexFile;
|
mDexFile = dexFile;
|
||||||
@ -85,7 +82,7 @@ public class SmaliBuilder {
|
|||||||
|
|
||||||
private final ExtFile mSmaliDir;
|
private final ExtFile mSmaliDir;
|
||||||
private final File mDexFile;
|
private final File mDexFile;
|
||||||
private int mApiLevel = 0;
|
private final int mApiLevel;
|
||||||
|
|
||||||
private final static Logger LOGGER = Logger.getLogger(SmaliBuilder.class.getName());
|
private final static Logger LOGGER = Logger.getLogger(SmaliBuilder.class.getName());
|
||||||
}
|
}
|
||||||
|
@ -31,17 +31,17 @@ import java.io.IOException;
|
|||||||
|
|
||||||
public class SmaliDecoder {
|
public class SmaliDecoder {
|
||||||
|
|
||||||
public static void decode(File apkFile, File outDir, String dexName, boolean bakdeb, int api)
|
public static void decode(File apkFile, File outDir, String dexName, boolean bakDeb, int apiLevel)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
new SmaliDecoder(apkFile, outDir, dexName, bakdeb, api).decode();
|
new SmaliDecoder(apkFile, outDir, dexName, bakDeb, apiLevel).decode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmaliDecoder(File apkFile, File outDir, String dexName, boolean bakdeb, int api) {
|
private SmaliDecoder(File apkFile, File outDir, String dexName, boolean bakDeb, int apiLevel) {
|
||||||
mApkFile = apkFile;
|
mApkFile = apkFile;
|
||||||
mOutDir = outDir;
|
mOutDir = outDir;
|
||||||
mDexFile = dexName;
|
mDexFile = dexName;
|
||||||
mBakDeb = bakdeb;
|
mBakDeb = bakDeb;
|
||||||
mApi = api;
|
mApiLevel = apiLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void decode() throws AndrolibException {
|
private void decode() throws AndrolibException {
|
||||||
@ -67,7 +67,7 @@ public class SmaliDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create the container
|
// create the container
|
||||||
MultiDexContainer<? extends DexBackedDexFile> container = DexFileFactory.loadDexContainer(mApkFile, Opcodes.forApi(mApi));
|
MultiDexContainer<? extends DexBackedDexFile> container = DexFileFactory.loadDexContainer(mApkFile, mApiLevel > 0 ? Opcodes.forApi(mApiLevel) : null);
|
||||||
MultiDexContainer.DexEntry<? extends DexBackedDexFile> dexEntry;
|
MultiDexContainer.DexEntry<? extends DexBackedDexFile> dexEntry;
|
||||||
DexBackedDexFile dexFile;
|
DexBackedDexFile dexFile;
|
||||||
|
|
||||||
@ -105,5 +105,5 @@ public class SmaliDecoder {
|
|||||||
private final File mOutDir;
|
private final File mOutDir;
|
||||||
private final String mDexFile;
|
private final String mDexFile;
|
||||||
private final boolean mBakDeb;
|
private final boolean mBakDeb;
|
||||||
private final int mApi;
|
private final int mApiLevel;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user