package de.robv.android.xposed.installer.util;
import android.content.Context;
import android.os.Build;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.zip.ZipFile;
import de.robv.android.xposed.installer.R;
import de.robv.android.xposed.installer.XposedApp;
import de.robv.android.xposed.installer.installation.FlashCallback;
public final class InstallZipUtil {
public static class ZipCheckResult {
private boolean mValidZip = false;
private boolean mFlashableInApp = false;
public boolean isValidZip() {
return mValidZip;
}
public boolean isFlashableInApp() {
return mFlashableInApp;
}
}
public static ZipCheckResult checkZip(ZipFile zip) {
ZipCheckResult result = new ZipCheckResult();
// Check for update-binary.
if (zip.getEntry("META-INF/com/google/android/update-binary") == null) {
return result;
}
result.mValidZip = true;
// Check whether the file can be flashed directly in the app.
if (zip.getEntry("META-INF/com/google/android/flash-script.sh") != null) {
result.mFlashableInApp = true;
}
return result;
}
public static class XposedProp {
private String mVersion = null;
private int mVersionInt = 0;
private String mArch = null;
private int mMinSdk = 0;
private int mMaxSdk = 0;
private boolean isComplete() {
return mVersion != null
&& mVersionInt > 0
&& mArch != null
&& mMinSdk > 0
&& mMaxSdk > 0;
}
public String getVersion() {
return mVersion;
}
public int getVersionInt() {
return mVersionInt;
}
public boolean isArchCompatible() {
return FrameworkZips.ARCH.equals(mArch);
}
public boolean isSdkCompatible() {
return mMinSdk <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT <= mMaxSdk;
}
public boolean isCompatible() {
return isSdkCompatible() && isArchCompatible();
}
}
public static XposedProp parseXposedProp(InputStream is) throws IOException {
XposedProp prop = new XposedProp();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("=", 2);
if (parts.length != 2) {
continue;
}
String key = parts[0].trim();
if (key.charAt(0) == '#') {
continue;
}
String value = parts[1].trim();
if (key.equals("version")) {
prop.mVersion = value;
prop.mVersionInt = ModuleUtil.extractIntPart(value);
} else if (key.equals("arch")) {
prop.mArch = value;
} else if (key.equals("minsdk")) {
prop.mMinSdk = Integer.parseInt(value);
} else if (key.equals("maxsdk")) {
prop.mMaxSdk = Integer.parseInt(value);
}
}
reader.close();
return prop.isComplete() ? prop : null;
}
public static String messageForError(int code, Object... args) {
Context context = XposedApp.getInstance();
switch (code) {
case FlashCallback.ERROR_TIMEOUT:
return context.getString(R.string.flash_error_timeout);
case FlashCallback.ERROR_SHELL_DIED:
return context.getString(R.string.flash_error_shell_died);
case FlashCallback.ERROR_NO_ROOT_ACCESS:
return context.getString(R.string.root_failed);
case FlashCallback.ERROR_INVALID_ZIP:
String message = context.getString(R.string.flash_error_invalid_zip);
if (args.length > 0) {
message += "\n" + args[0];
}
return message;
case FlashCallback.ERROR_NOT_FLASHABLE_IN_APP:
return context.getString(R.string.flash_error_not_flashable_in_app);
default:
return context.getString(R.string.flash_error_default, code);
}
}
public static void triggerError(FlashCallback callback, int code, Object... args) {
callback.onError(code, messageForError(code, args));
}
public static void closeSilently(ZipFile z) {
try {
z.close();
} catch (IOException ignored) {}
}
private InstallZipUtil() {}
}