and the kotlin keeps coming
just keeps on coming Signed-off-by: androidacy-user <opensource@androidacy.com>pull/27/head
parent
a73a7b613e
commit
7068288d07
@ -1,49 +1,70 @@
|
|||||||
package com.fox2code.mmm.repo;
|
package com.fox2code.mmm.repo
|
||||||
|
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes
|
||||||
|
import com.fox2code.mmm.manager.ModuleInfo
|
||||||
|
|
||||||
import com.fox2code.mmm.manager.ModuleInfo;
|
class RepoModule {
|
||||||
|
@JvmField
|
||||||
|
val repoData: RepoData
|
||||||
|
@JvmField
|
||||||
|
val moduleInfo: ModuleInfo
|
||||||
|
@JvmField
|
||||||
|
val id: String
|
||||||
|
@JvmField
|
||||||
|
var repoName: String? = null
|
||||||
|
@JvmField
|
||||||
|
var lastUpdated: Long = 0
|
||||||
|
@JvmField
|
||||||
|
var propUrl: String? = null
|
||||||
|
@JvmField
|
||||||
|
var zipUrl: String? = null
|
||||||
|
@JvmField
|
||||||
|
var notesUrl: String? = null
|
||||||
|
@JvmField
|
||||||
|
var checksum: String? = null
|
||||||
|
@JvmField
|
||||||
|
var processed = false
|
||||||
|
|
||||||
public class RepoModule {
|
@JvmField
|
||||||
public final RepoData repoData;
|
|
||||||
public final ModuleInfo moduleInfo;
|
|
||||||
public final String id;
|
|
||||||
public String repoName;
|
|
||||||
public long lastUpdated;
|
|
||||||
public String propUrl;
|
|
||||||
public String zipUrl;
|
|
||||||
public String notesUrl;
|
|
||||||
public String checksum;
|
|
||||||
public boolean processed;
|
|
||||||
@StringRes
|
@StringRes
|
||||||
public int qualityText;
|
var qualityText = 0
|
||||||
public int qualityValue;
|
@JvmField
|
||||||
public boolean safe;
|
var qualityValue = 0
|
||||||
|
var safe: Boolean
|
||||||
|
|
||||||
public RepoModule(RepoData repoData, String id) {
|
constructor(repoData: RepoData, id: String) {
|
||||||
this.repoData = repoData;
|
this.repoData = repoData
|
||||||
this.moduleInfo = new ModuleInfo(id);
|
moduleInfo = ModuleInfo(id)
|
||||||
this.id = id;
|
this.id = id
|
||||||
this.moduleInfo.flags |=
|
moduleInfo.flags = moduleInfo.flags or ModuleInfo.FLAG_METADATA_INVALID
|
||||||
ModuleInfo.FLAG_METADATA_INVALID;
|
safe = moduleInfo.safe
|
||||||
this.safe = this.moduleInfo.safe;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// allows all fields to be set-
|
// allows all fields to be set-
|
||||||
public RepoModule(RepoData repoData, String id, String name, String description, String author, String donate, String config, String support, String version, int versionCode) {
|
constructor(
|
||||||
this.repoData = repoData;
|
repoData: RepoData,
|
||||||
this.moduleInfo = new ModuleInfo(id);
|
id: String,
|
||||||
this.id = id;
|
name: String?,
|
||||||
this.moduleInfo.name = name;
|
description: String?,
|
||||||
this.moduleInfo.description = description;
|
author: String?,
|
||||||
this.moduleInfo.author = author;
|
donate: String?,
|
||||||
this.moduleInfo.donate = donate;
|
config: String?,
|
||||||
this.moduleInfo.config = config;
|
support: String?,
|
||||||
this.moduleInfo.support = support;
|
version: String?,
|
||||||
this.moduleInfo.version = version;
|
versionCode: Int
|
||||||
this.moduleInfo.versionCode = versionCode;
|
) {
|
||||||
this.moduleInfo.flags |=
|
this.repoData = repoData
|
||||||
ModuleInfo.FLAG_METADATA_INVALID;
|
moduleInfo = ModuleInfo(id)
|
||||||
this.safe = this.moduleInfo.safe;
|
this.id = id
|
||||||
|
moduleInfo.name = name
|
||||||
|
moduleInfo.description = description
|
||||||
|
moduleInfo.author = author
|
||||||
|
moduleInfo.donate = donate
|
||||||
|
moduleInfo.config = config
|
||||||
|
moduleInfo.support = support
|
||||||
|
moduleInfo.version = version
|
||||||
|
moduleInfo.versionCode = versionCode.toLong()
|
||||||
|
moduleInfo.flags = moduleInfo.flags or ModuleInfo.FLAG_METADATA_INVALID
|
||||||
|
safe = moduleInfo.safe
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,423 +1,460 @@
|
|||||||
package com.fox2code.mmm.utils.io;
|
@file:Suppress("unused")
|
||||||
|
|
||||||
import static com.fox2code.mmm.AppUpdateManager.FLAG_COMPAT_LOW_QUALITY;
|
package com.fox2code.mmm.utils.io
|
||||||
import static com.fox2code.mmm.AppUpdateManager.getFlagsForModule;
|
|
||||||
|
|
||||||
import android.os.Build;
|
import android.os.Build
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils
|
||||||
|
import com.fox2code.mmm.AppUpdateManager
|
||||||
|
import com.fox2code.mmm.manager.ModuleInfo
|
||||||
|
import com.topjohnwu.superuser.io.SuFileInputStream
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
import com.fox2code.mmm.AppUpdateManager;
|
enum class PropUtils {
|
||||||
import com.fox2code.mmm.manager.ModuleInfo;
|
|
||||||
import com.topjohnwu.superuser.io.SuFileInputStream;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
@SuppressWarnings("SpellCheckingInspection")
|
|
||||||
public enum PropUtils {
|
|
||||||
;
|
;
|
||||||
private static final HashMap<String, String> moduleSupportsFallbacks = new HashMap<>();
|
|
||||||
private static final HashMap<String, String> moduleConfigsFallbacks = new HashMap<>();
|
@Suppress("SpellCheckingInspection")
|
||||||
private static final HashMap<String, Integer> moduleMinApiFallbacks = new HashMap<>();
|
companion object {
|
||||||
private static final HashMap<String, String> moduleUpdateJsonFallbacks = new HashMap<>();
|
private val moduleSupportsFallbacks = HashMap<String, String>()
|
||||||
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
|
private val moduleConfigsFallbacks = HashMap<String, String>()
|
||||||
private static final HashSet<String> moduleMTTRebornFallback = new HashSet<>();
|
private val moduleMinApiFallbacks = HashMap<String, Int>()
|
||||||
private static final HashSet<String> moduleImportantProp = new HashSet<>(Arrays.asList(
|
private val moduleUpdateJsonFallbacks = HashMap<String, String>()
|
||||||
|
private val moduleMTTRebornFallback = HashSet<String>()
|
||||||
|
private val moduleImportantProp = HashSet(
|
||||||
|
mutableListOf(
|
||||||
"id", "name", "version", "versionCode"
|
"id", "name", "version", "versionCode"
|
||||||
));
|
)
|
||||||
private static final int RIRU_MIN_API;
|
)
|
||||||
|
private var RIRU_MIN_API = 0
|
||||||
|
|
||||||
// Note: These fallback values may not be up-to-date
|
// Note: These fallback values may not be up-to-date
|
||||||
// They are only used if modules don't define the metadata
|
// They are only used if modules don't define the metadata
|
||||||
static {
|
init {
|
||||||
// Support are pages or groups where the user can get support for the module
|
// Support are pages or groups where the user can get support for the module
|
||||||
moduleSupportsFallbacks.put("aospill", "https://t.me/PannekoX");
|
moduleSupportsFallbacks["aospill"] = "https://t.me/PannekoX"
|
||||||
moduleSupportsFallbacks.put("bromitewebview", "https://t.me/androidacy_discussions");
|
moduleSupportsFallbacks["bromitewebview"] = "https://t.me/androidacy_discussions"
|
||||||
moduleSupportsFallbacks.put("fontrevival", "https://t.me/androidacy_discussions");
|
moduleSupportsFallbacks["fontrevival"] = "https://t.me/androidacy_discussions"
|
||||||
moduleSupportsFallbacks.put("MagiskHidePropsConf", "https://forum.xda-developers.com/t" +
|
moduleSupportsFallbacks["MagiskHidePropsConf"] = "https://forum.xda-developers.com/t" +
|
||||||
"/module-magiskhide-props-config-safetynet-prop-edits-and-more-v6-1-1.3789228/");
|
"/module-magiskhide-props-config-safetynet-prop-edits-and-more-v6-1-1.3789228/"
|
||||||
moduleSupportsFallbacks.put("quickstepswitcher", "https://t.me/QuickstepSwitcherSupport");
|
moduleSupportsFallbacks["quickstepswitcher"] = "https://t.me/QuickstepSwitcherSupport"
|
||||||
moduleSupportsFallbacks.put("riru_edxposed", "https://t.me/EdXposed");
|
moduleSupportsFallbacks["riru_edxposed"] = "https://t.me/EdXposed"
|
||||||
moduleSupportsFallbacks.put("riru_lsposed", "https://github.com/LSPosed/LSPosed/issues");
|
moduleSupportsFallbacks["riru_lsposed"] = "https://github.com/LSPosed/LSPosed/issues"
|
||||||
moduleSupportsFallbacks.put("substratum", "https://github.com/substratum/substratum/issues");
|
moduleSupportsFallbacks["substratum"] =
|
||||||
|
"https://github.com/substratum/substratum/issues"
|
||||||
// Config are application installed by modules that allow them to be configured
|
// Config are application installed by modules that allow them to be configured
|
||||||
moduleConfigsFallbacks.put("quickstepswitcher", "xyz.paphonb.quickstepswitcher");
|
moduleConfigsFallbacks["quickstepswitcher"] = "xyz.paphonb.quickstepswitcher"
|
||||||
moduleConfigsFallbacks.put("hex_installer_module", "project.vivid.hex.bodhi");
|
moduleConfigsFallbacks["hex_installer_module"] = "project.vivid.hex.bodhi"
|
||||||
moduleConfigsFallbacks.put("riru_edxposed", "org.meowcat.edxposed.manager");
|
moduleConfigsFallbacks["riru_edxposed"] = "org.meowcat.edxposed.manager"
|
||||||
moduleConfigsFallbacks.put("riru_lsposed", "org.lsposed.manager");
|
moduleConfigsFallbacks["riru_lsposed"] = "org.lsposed.manager"
|
||||||
moduleConfigsFallbacks.put("zygisk_lsposed", "org.lsposed.manager");
|
moduleConfigsFallbacks["zygisk_lsposed"] = "org.lsposed.manager"
|
||||||
moduleConfigsFallbacks.put("xposed_dalvik", "de.robv.android.xposed.installer");
|
moduleConfigsFallbacks["xposed_dalvik"] = "de.robv.android.xposed.installer"
|
||||||
moduleConfigsFallbacks.put("xposed", "de.robv.android.xposed.installer");
|
moduleConfigsFallbacks["xposed"] = "de.robv.android.xposed.installer"
|
||||||
moduleConfigsFallbacks.put("substratum", "projekt.substratum");
|
moduleConfigsFallbacks["substratum"] = "projekt.substratum"
|
||||||
// minApi is the minimum android version required to use the module
|
// minApi is the minimum android version required to use the module
|
||||||
moduleMinApiFallbacks.put("HideNavBar", Build.VERSION_CODES.Q);
|
moduleMinApiFallbacks["HideNavBar"] = Build.VERSION_CODES.Q
|
||||||
moduleMinApiFallbacks.put("riru_ifw_enhance", Build.VERSION_CODES.O);
|
moduleMinApiFallbacks["riru_ifw_enhance"] = Build.VERSION_CODES.O
|
||||||
moduleMinApiFallbacks.put("zygisk_ifw_enhance", Build.VERSION_CODES.O);
|
moduleMinApiFallbacks["zygisk_ifw_enhance"] = Build.VERSION_CODES.O
|
||||||
moduleMinApiFallbacks.put("riru_edxposed", Build.VERSION_CODES.O);
|
moduleMinApiFallbacks["riru_edxposed"] = Build.VERSION_CODES.O
|
||||||
moduleMinApiFallbacks.put("zygisk_edxposed", Build.VERSION_CODES.O);
|
moduleMinApiFallbacks["zygisk_edxposed"] = Build.VERSION_CODES.O
|
||||||
moduleMinApiFallbacks.put("riru_lsposed", Build.VERSION_CODES.O_MR1);
|
moduleMinApiFallbacks["riru_lsposed"] = Build.VERSION_CODES.O_MR1
|
||||||
moduleMinApiFallbacks.put("zygisk_lsposed", Build.VERSION_CODES.O_MR1);
|
moduleMinApiFallbacks["zygisk_lsposed"] = Build.VERSION_CODES.O_MR1
|
||||||
moduleMinApiFallbacks.put("noneDisplayCutout", Build.VERSION_CODES.P);
|
moduleMinApiFallbacks["noneDisplayCutout"] = Build.VERSION_CODES.P
|
||||||
moduleMinApiFallbacks.put("quickstepswitcher", Build.VERSION_CODES.P);
|
moduleMinApiFallbacks["quickstepswitcher"] = Build.VERSION_CODES.P
|
||||||
moduleMinApiFallbacks.put("riru_clipboard_whitelist", Build.VERSION_CODES.Q);
|
moduleMinApiFallbacks["riru_clipboard_whitelist"] = Build.VERSION_CODES.Q
|
||||||
// minApi for riru core include submodules
|
// minApi for riru core include submodules
|
||||||
moduleMinApiFallbacks.put("riru-core", RIRU_MIN_API = Build.VERSION_CODES.M);
|
moduleMinApiFallbacks["riru-core"] = Build.VERSION_CODES.M.also { RIRU_MIN_API = it }
|
||||||
// Fallbacks in case updateJson is missing
|
// Fallbacks in case updateJson is missing
|
||||||
final String GH_UC = "https://raw.githubusercontent.com/";
|
val ghUC = "https://raw.githubusercontent.com/"
|
||||||
moduleUpdateJsonFallbacks.put("BluetoothLibraryPatcher",
|
moduleUpdateJsonFallbacks["BluetoothLibraryPatcher"] =
|
||||||
GH_UC + "3arthur6/BluetoothLibraryPatcher/master/update.json");
|
ghUC + "3arthur6/BluetoothLibraryPatcher/master/update.json"
|
||||||
moduleUpdateJsonFallbacks.put("Detach",
|
moduleUpdateJsonFallbacks["Detach"] =
|
||||||
GH_UC + "xerta555/Detach-Files/blob/master/Updater.json");
|
ghUC + "xerta555/Detach-Files/blob/master/Updater.json"
|
||||||
for (String module : new String[]{"busybox-ndk", "adb-ndk", "twrp-keep",
|
for (module in arrayOf(
|
||||||
"adreno-dev", "nano-ndk", "zipsigner", "nexusmedia", "mtd-ndk"}) {
|
"busybox-ndk", "adb-ndk", "twrp-keep",
|
||||||
moduleUpdateJsonFallbacks.put(module,
|
"adreno-dev", "nano-ndk", "zipsigner", "nexusmedia", "mtd-ndk"
|
||||||
GH_UC + "Magisk-Modules-Repo/" + module + "/master/update.json");
|
)) {
|
||||||
}
|
moduleUpdateJsonFallbacks[module] =
|
||||||
moduleUpdateJsonFallbacks.put("riru_ifw_enhance", "https://github.com/" +
|
ghUC + "Magisk-Modules-Repo/" + module + "/master/update.json"
|
||||||
"Kr328/Riru-IFWEnhance/releases/latest/download/riru-ifw-enhance.json");
|
}
|
||||||
moduleUpdateJsonFallbacks.put("zygisk_ifw_enhance", "https://github.com/" +
|
moduleUpdateJsonFallbacks["riru_ifw_enhance"] = "https://github.com/" +
|
||||||
"Kr328/Riru-IFWEnhance/releases/latest/download/zygisk-ifw-enhance.json");
|
"Kr328/Riru-IFWEnhance/releases/latest/download/riru-ifw-enhance.json"
|
||||||
moduleUpdateJsonFallbacks.put("riru_lsposed",
|
moduleUpdateJsonFallbacks["zygisk_ifw_enhance"] = "https://github.com/" +
|
||||||
"https://lsposed.github.io/LSPosed/release/riru.json");
|
"Kr328/Riru-IFWEnhance/releases/latest/download/zygisk-ifw-enhance.json"
|
||||||
moduleUpdateJsonFallbacks.put("zygisk_lsposed",
|
moduleUpdateJsonFallbacks["riru_lsposed"] =
|
||||||
"https://lsposed.github.io/LSPosed/release/zygisk.json");
|
"https://lsposed.github.io/LSPosed/release/riru.json"
|
||||||
}
|
moduleUpdateJsonFallbacks["zygisk_lsposed"] =
|
||||||
|
"https://lsposed.github.io/LSPosed/release/zygisk.json"
|
||||||
public static void readProperties(ModuleInfo moduleInfo, String file,
|
}
|
||||||
boolean local) throws IOException {
|
|
||||||
readProperties(moduleInfo, SuFileInputStream.open(file), file, local);
|
@Throws(IOException::class)
|
||||||
}
|
fun readProperties(
|
||||||
|
moduleInfo: ModuleInfo, file: String,
|
||||||
public static void readProperties(ModuleInfo moduleInfo, String file,
|
local: Boolean
|
||||||
String name, boolean local) throws IOException {
|
) {
|
||||||
readProperties(moduleInfo, SuFileInputStream.open(file), name, local);
|
readProperties(moduleInfo, SuFileInputStream.open(file), file, local)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void readProperties(ModuleInfo moduleInfo, InputStream inputStream,
|
@Throws(IOException::class)
|
||||||
String name, boolean local) throws IOException {
|
fun readProperties(
|
||||||
boolean readId = false, readIdSec = false, readName = false,
|
moduleInfo: ModuleInfo, file: String?,
|
||||||
readVersionCode = false, readVersion = false, readDescription = false,
|
name: String, local: Boolean
|
||||||
readUpdateJson = false, invalid = false, readMinApi = false, readMaxApi = false,
|
) {
|
||||||
readMMTReborn = false;
|
readProperties(moduleInfo, SuFileInputStream.open(file!!), name, local)
|
||||||
try (BufferedReader bufferedReader = new BufferedReader(
|
}
|
||||||
new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
|
||||||
String line;
|
@Throws(IOException::class)
|
||||||
int lineNum = 0;
|
fun readProperties(
|
||||||
while ((line = bufferedReader.readLine()) != null) {
|
moduleInfo: ModuleInfo, inputStream: InputStream?,
|
||||||
|
name: String, local: Boolean
|
||||||
|
) {
|
||||||
|
var readId = false
|
||||||
|
var readIdSec = false
|
||||||
|
var readName = false
|
||||||
|
var readVersionCode = false
|
||||||
|
var readVersion = false
|
||||||
|
var readDescription = false
|
||||||
|
var readUpdateJson = false
|
||||||
|
var invalid = false
|
||||||
|
var readMinApi = false
|
||||||
|
var readMaxApi = false
|
||||||
|
var readMMTReborn = false
|
||||||
|
BufferedReader(
|
||||||
|
InputStreamReader(inputStream, StandardCharsets.UTF_8)
|
||||||
|
).use { bufferedReader ->
|
||||||
|
var line: String
|
||||||
|
var lineNum = 0
|
||||||
|
while (bufferedReader.readLine().also { line = it } != null) {
|
||||||
if (lineNum == 0 && line.startsWith("\u0000")) {
|
if (lineNum == 0 && line.startsWith("\u0000")) {
|
||||||
while (line.startsWith("\u0000"))
|
while (line.startsWith("\u0000")) line = line.substring(1)
|
||||||
line = line.substring(1);
|
}
|
||||||
}
|
lineNum++
|
||||||
lineNum++;
|
val index = line.indexOf('=')
|
||||||
int index = line.indexOf('=');
|
if (index == -1 || line.startsWith("#")) continue
|
||||||
if (index == -1 || line.startsWith("#"))
|
val key = line.substring(0, index)
|
||||||
continue;
|
val value = line.substring(index + 1).trim { it <= ' ' }
|
||||||
String key = line.substring(0, index);
|
|
||||||
String value = line.substring(index + 1).trim();
|
|
||||||
// check if field is defined on the moduleInfo object we are reading
|
// check if field is defined on the moduleInfo object we are reading
|
||||||
if (moduleInfo.toString().contains(key)) {
|
if (moduleInfo.toString().contains(key)) {
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
// name and id have their own implementation
|
// name and id have their own implementation
|
||||||
if (isInvalidValue(key)) {
|
if (isInvalidValue(key)) {
|
||||||
if (local) {
|
if (local) {
|
||||||
invalid = true;
|
invalid = true
|
||||||
continue;
|
continue
|
||||||
} else throw new IOException("Invalid key at line " + lineNum);
|
} else throw IOException("Invalid key at line $lineNum")
|
||||||
} else {
|
} else {
|
||||||
if (value.isEmpty() && !moduleImportantProp.contains(key))
|
if (value.isEmpty() && !moduleImportantProp.contains(key)) continue // allow empty values to pass.
|
||||||
continue; // allow empty values to pass.
|
|
||||||
if (isInvalidValue(value)) {
|
if (isInvalidValue(value)) {
|
||||||
if (local) {
|
if (local) {
|
||||||
invalid = true;
|
invalid = true
|
||||||
continue;
|
continue
|
||||||
} else throw new IOException("Invalid value for key " + key);
|
} else throw IOException("Invalid value for key $key")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (key) {
|
when (key) {
|
||||||
case "id":
|
"id" -> {
|
||||||
if (isInvalidValue(value)) {
|
if (isInvalidValue(value)) {
|
||||||
if (local) {
|
if (local) {
|
||||||
invalid = true;
|
invalid = true
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
throw new IOException("Invalid module id!");
|
throw IOException("Invalid module id!")
|
||||||
}
|
}
|
||||||
readId = true;
|
readId = true
|
||||||
if (!moduleInfo.id.equals(value)) {
|
if (moduleInfo.id != value) {
|
||||||
if (local) {
|
invalid = if (local) {
|
||||||
invalid = true;
|
true
|
||||||
} else {
|
} else {
|
||||||
throw new IOException(name + " has an non matching module id! " +
|
throw IOException(
|
||||||
"(Expected \"" + moduleInfo.id + "\" got \"" + value + "\"");
|
name + " has an non matching module id! " +
|
||||||
|
"(Expected \"" + moduleInfo.id + "\" got \"" + value + "\""
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case "name":
|
"name" -> {
|
||||||
if (readName) {
|
if (readName) {
|
||||||
if (local) {
|
if (local) {
|
||||||
invalid = true;
|
invalid = true
|
||||||
break;
|
break
|
||||||
} else throw new IOException("Duplicate module name!");
|
} else throw IOException("Duplicate module name!")
|
||||||
}
|
}
|
||||||
if (isInvalidValue(value)) {
|
if (isInvalidValue(value)) {
|
||||||
if (local) {
|
if (local) {
|
||||||
invalid = true;
|
invalid = true
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
throw new IOException("Invalid module name!");
|
throw IOException("Invalid module name!")
|
||||||
}
|
}
|
||||||
readName = true;
|
readName = true
|
||||||
moduleInfo.name = value;
|
moduleInfo.name = value
|
||||||
if (moduleInfo.id.equals(value)) {
|
if (moduleInfo.id == value) {
|
||||||
readIdSec = true;
|
readIdSec = true
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case "version":
|
|
||||||
readVersion = true;
|
"version" -> {
|
||||||
moduleInfo.version = value;
|
readVersion = true
|
||||||
break;
|
moduleInfo.version = value
|
||||||
case "versionCode":
|
}
|
||||||
readVersionCode = true;
|
|
||||||
|
"versionCode" -> {
|
||||||
|
readVersionCode = true
|
||||||
try {
|
try {
|
||||||
moduleInfo.versionCode = Long.parseLong(value);
|
moduleInfo.versionCode = value.toLong()
|
||||||
} catch (RuntimeException e) {
|
} catch (e: RuntimeException) {
|
||||||
if (local) {
|
if (local) {
|
||||||
invalid = true;
|
invalid = true
|
||||||
moduleInfo.versionCode = 0;
|
moduleInfo.versionCode = 0
|
||||||
} else throw e;
|
} else throw e
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case "author":
|
|
||||||
moduleInfo.author = value.endsWith(" development team") ?
|
"author" -> moduleInfo.author =
|
||||||
value.substring(0, value.length() - 17) : value;
|
if (value.endsWith(" development team")) value.substring(
|
||||||
break;
|
0,
|
||||||
case "description":
|
value.length - 17
|
||||||
moduleInfo.description = value;
|
) else value
|
||||||
readDescription = true;
|
|
||||||
break;
|
"description" -> {
|
||||||
case "updateJsonAk3":
|
moduleInfo.description = value
|
||||||
|
readDescription = true
|
||||||
|
}
|
||||||
|
|
||||||
|
"updateJsonAk3" -> {
|
||||||
// Only allow AnyKernel3 helper to use "updateJsonAk3"
|
// Only allow AnyKernel3 helper to use "updateJsonAk3"
|
||||||
if (!"ak3-helper".equals(moduleInfo.id)) break;
|
if ("ak3-helper" != moduleInfo.id) break
|
||||||
case "updateJson":
|
if (isInvalidURL(value)) break
|
||||||
if (isInvalidURL(value)) break;
|
moduleInfo.updateJson = value
|
||||||
moduleInfo.updateJson = value;
|
readUpdateJson = true
|
||||||
readUpdateJson = true;
|
}
|
||||||
break;
|
|
||||||
case "changeBoot":
|
"updateJson" -> {
|
||||||
moduleInfo.changeBoot = Boolean.parseBoolean(value);
|
if (isInvalidURL(value)) break
|
||||||
break;
|
moduleInfo.updateJson = value
|
||||||
case "mmtReborn":
|
readUpdateJson = true
|
||||||
moduleInfo.mmtReborn = Boolean.parseBoolean(value);
|
}
|
||||||
readMMTReborn = true;
|
|
||||||
break;
|
"changeBoot" -> moduleInfo.changeBoot =
|
||||||
case "support":
|
java.lang.Boolean.parseBoolean(value)
|
||||||
|
|
||||||
|
"mmtReborn" -> {
|
||||||
|
moduleInfo.mmtReborn = java.lang.Boolean.parseBoolean(value)
|
||||||
|
readMMTReborn = true
|
||||||
|
}
|
||||||
|
|
||||||
|
"support" -> {
|
||||||
// Do not accept invalid or too broad support links
|
// Do not accept invalid or too broad support links
|
||||||
if (isInvalidURL(value) ||
|
if (isInvalidURL(value) || "https://forum.xda-developers.com/" == value) break
|
||||||
"https://forum.xda-developers.com/".equals(value))
|
moduleInfo.support = value
|
||||||
break;
|
}
|
||||||
moduleInfo.support = value;
|
|
||||||
break;
|
"donate" -> {
|
||||||
case "donate":
|
|
||||||
// Do not accept invalid donate links
|
// Do not accept invalid donate links
|
||||||
if (isInvalidURL(value)) break;
|
if (isInvalidURL(value)) break
|
||||||
moduleInfo.donate = value;
|
moduleInfo.donate = value
|
||||||
break;
|
}
|
||||||
case "config":
|
|
||||||
moduleInfo.config = value;
|
"config" -> moduleInfo.config = value
|
||||||
break;
|
"needRamdisk" -> moduleInfo.needRamdisk =
|
||||||
case "needRamdisk":
|
java.lang.Boolean.parseBoolean(value)
|
||||||
moduleInfo.needRamdisk = Boolean.parseBoolean(value);
|
|
||||||
break;
|
"minMagisk" -> try {
|
||||||
case "minMagisk":
|
val i = value.indexOf('.')
|
||||||
try {
|
|
||||||
int i = value.indexOf('.');
|
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
moduleInfo.minMagisk = Integer.parseInt(value);
|
moduleInfo.minMagisk = value.toInt()
|
||||||
} else {
|
} else {
|
||||||
moduleInfo.minMagisk = // Allow 24.1 to mean 24100
|
moduleInfo.minMagisk = // Allow 24.1 to mean 24100
|
||||||
(Integer.parseInt(value.substring(0, i)) * 1000) +
|
value.substring(0, i).toInt() * 1000 + value.substring(i + 1)
|
||||||
(Integer.parseInt(value.substring(i + 1)) * 100);
|
.toInt() * 100
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (e: Exception) {
|
||||||
moduleInfo.minMagisk = 0;
|
moduleInfo.minMagisk = 0
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case "minApi":
|
"minApi" -> {
|
||||||
// Special case for Riru EdXposed because
|
// Special case for Riru EdXposed because
|
||||||
// minApi don't mean the same thing for them
|
// minApi don't mean the same thing for them
|
||||||
if ("10".equals(value)) break;
|
if ("10" == value) break
|
||||||
case "minSdkVersion": // Improve compatibility
|
|
||||||
try {
|
try {
|
||||||
moduleInfo.minApi = Integer.parseInt(value);
|
moduleInfo.minApi = value.toInt()
|
||||||
readMinApi = true;
|
readMinApi = true
|
||||||
} catch (Exception e) {
|
} catch (e: Exception) {
|
||||||
if (!readMinApi) moduleInfo.minApi = 0;
|
if (!readMinApi) moduleInfo.minApi = 0
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case "maxSdkVersion": // Improve compatibility
|
|
||||||
case "maxApi":
|
"minSdkVersion" -> try {
|
||||||
try {
|
moduleInfo.minApi = value.toInt()
|
||||||
moduleInfo.maxApi = Integer.parseInt(value);
|
readMinApi = true
|
||||||
readMaxApi = true;
|
} catch (e: Exception) {
|
||||||
} catch (Exception e) {
|
if (!readMinApi) moduleInfo.minApi = 0
|
||||||
if (!readMaxApi) moduleInfo.maxApi = 0;
|
}
|
||||||
|
|
||||||
|
"maxSdkVersion", "maxApi" -> try {
|
||||||
|
moduleInfo.maxApi = value.toInt()
|
||||||
|
readMaxApi = true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (!readMaxApi) moduleInfo.maxApi = 0
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!readId) {
|
if (!readId) {
|
||||||
if (readIdSec && local) {
|
if (readIdSec && local) {
|
||||||
// Using the name for module id is not really appropriate, so beautify it a bit
|
// Using the name for module id is not really appropriate, so beautify it a bit
|
||||||
moduleInfo.name = makeNameFromId(moduleInfo.id);
|
moduleInfo.name = makeNameFromId(moduleInfo.id)
|
||||||
} else if (!local) { // Allow local modules to not declare ids
|
} else if (!local) { // Allow local modules to not declare ids
|
||||||
throw new IOException("Didn't read module id at least once!");
|
throw IOException("Didn't read module id at least once!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!readVersionCode) {
|
if (!readVersionCode) {
|
||||||
if (local) {
|
if (local) {
|
||||||
invalid = true;
|
invalid = true
|
||||||
moduleInfo.versionCode = 0;
|
moduleInfo.versionCode = 0
|
||||||
} else {
|
} else {
|
||||||
throw new IOException("Didn't read module versionCode at least once!");
|
throw IOException("Didn't read module versionCode at least once!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!readName || isInvalidValue(moduleInfo.name)) {
|
if (!readName || isInvalidValue(moduleInfo.name)) {
|
||||||
moduleInfo.name = makeNameFromId(moduleInfo.id);
|
moduleInfo.name = makeNameFromId(moduleInfo.id)
|
||||||
}
|
}
|
||||||
if (!readVersion) {
|
if (!readVersion) {
|
||||||
moduleInfo.version = "v" + moduleInfo.versionCode;
|
moduleInfo.version = "v" + moduleInfo.versionCode
|
||||||
} else {
|
} else {
|
||||||
moduleInfo.version = shortenVersionName(
|
moduleInfo.version = shortenVersionName(
|
||||||
moduleInfo.version, moduleInfo.versionCode);
|
moduleInfo.version, moduleInfo.versionCode
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (!readDescription || isInvalidValue(moduleInfo.description)) {
|
if (!readDescription || isInvalidValue(moduleInfo.description)) {
|
||||||
moduleInfo.description = "";
|
moduleInfo.description = ""
|
||||||
}
|
}
|
||||||
if (!readUpdateJson) {
|
if (!readUpdateJson) {
|
||||||
moduleInfo.updateJson = moduleUpdateJsonFallbacks.get(moduleInfo.id);
|
moduleInfo.updateJson = moduleUpdateJsonFallbacks[moduleInfo.id]
|
||||||
}
|
}
|
||||||
if (moduleInfo.minApi == 0 || !readMinApi) {
|
if (moduleInfo.minApi == 0 || !readMinApi) {
|
||||||
Integer minApiFallback = moduleMinApiFallbacks.get(moduleInfo.id);
|
val minApiFallback = moduleMinApiFallbacks[moduleInfo.id]
|
||||||
if (minApiFallback != null)
|
if (minApiFallback != null) moduleInfo.minApi =
|
||||||
moduleInfo.minApi = minApiFallback;
|
minApiFallback else if (moduleInfo.id.startsWith("riru_")
|
||||||
else if (moduleInfo.id.startsWith("riru_")
|
|| moduleInfo.id.startsWith("riru-")
|
||||||
|| moduleInfo.id.startsWith("riru-"))
|
) moduleInfo.minApi = RIRU_MIN_API
|
||||||
moduleInfo.minApi = RIRU_MIN_API;
|
|
||||||
}
|
}
|
||||||
if (moduleInfo.support == null) {
|
if (moduleInfo.support == null) {
|
||||||
moduleInfo.support = moduleSupportsFallbacks.get(moduleInfo.id);
|
moduleInfo.support = moduleSupportsFallbacks[moduleInfo.id]
|
||||||
}
|
}
|
||||||
if (moduleInfo.config == null) {
|
if (moduleInfo.config == null) {
|
||||||
moduleInfo.config = moduleConfigsFallbacks.get(moduleInfo.id);
|
moduleInfo.config = moduleConfigsFallbacks[moduleInfo.id]
|
||||||
}
|
}
|
||||||
if (!readMMTReborn) {
|
if (!readMMTReborn) {
|
||||||
moduleInfo.mmtReborn = moduleMTTRebornFallback.contains(moduleInfo.id) ||
|
moduleInfo.mmtReborn = moduleMTTRebornFallback.contains(moduleInfo.id) ||
|
||||||
(AppUpdateManager.getFlagsForModule(moduleInfo.id) &
|
AppUpdateManager.getFlagsForModule(moduleInfo.id) and
|
||||||
AppUpdateManager.FLAG_COMPAT_MMT_REBORN) != 0;
|
AppUpdateManager.FLAG_COMPAT_MMT_REBORN != 0
|
||||||
}
|
}
|
||||||
// All local modules should have an author
|
// All local modules should have an author
|
||||||
// set to "Unknown" if author is missing.
|
// set to "Unknown" if author is missing.
|
||||||
if (local && moduleInfo.author == null) {
|
if (local && moduleInfo.author == null) {
|
||||||
moduleInfo.author = "Unknown";
|
moduleInfo.author = "Unknown"
|
||||||
}
|
}
|
||||||
if (invalid) {
|
if (invalid) {
|
||||||
moduleInfo.flags |= ModuleInfo.FLAG_METADATA_INVALID;
|
moduleInfo.flags = moduleInfo.flags or ModuleInfo.FLAG_METADATA_INVALID
|
||||||
// This shouldn't happen but just in case
|
// This shouldn't happen but just in case
|
||||||
if (!local) throw new IOException("Invalid properties!");
|
if (!local) throw IOException("Invalid properties!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String readModulePropSimple(InputStream inputStream, String what) {
|
@JvmStatic
|
||||||
if (inputStream == null) return null;
|
fun readModulePropSimple(inputStream: InputStream?, what: String): String? {
|
||||||
String moduleId = null;
|
if (inputStream == null) return null
|
||||||
try (BufferedReader bufferedReader = new BufferedReader(
|
var moduleId: String? = null
|
||||||
new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
try {
|
||||||
String line;
|
BufferedReader(
|
||||||
while ((line = bufferedReader.readLine()) != null) {
|
InputStreamReader(inputStream, StandardCharsets.UTF_8)
|
||||||
while (line.startsWith("\u0000"))
|
).use { bufferedReader ->
|
||||||
line = line.substring(1);
|
var line: String
|
||||||
if (line.startsWith(what + "=")) {
|
while (bufferedReader.readLine().also { line = it } != null) {
|
||||||
moduleId = line.substring(what.length() + 1).trim();
|
while (line.startsWith("\u0000")) line = line.substring(1)
|
||||||
|
if (line.startsWith("$what=")) {
|
||||||
|
moduleId = line.substring(what.length + 1).trim { it <= ' ' }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (e: IOException) {
|
||||||
Timber.i(e);
|
Timber.i(e)
|
||||||
}
|
}
|
||||||
return moduleId;
|
return moduleId
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String readModuleId(InputStream inputStream) {
|
fun readModuleId(inputStream: InputStream?): String? {
|
||||||
return readModulePropSimple(inputStream, "id");
|
return readModulePropSimple(inputStream, "id")
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void applyFallbacks(ModuleInfo moduleInfo) {
|
@JvmStatic
|
||||||
if (moduleInfo.support == null || moduleInfo.support.isEmpty()) {
|
fun applyFallbacks(moduleInfo: ModuleInfo) {
|
||||||
moduleInfo.support = moduleSupportsFallbacks.get(moduleInfo.id);
|
if (moduleInfo.support == null || moduleInfo.support!!.isEmpty()) {
|
||||||
|
moduleInfo.support = moduleSupportsFallbacks[moduleInfo.id]
|
||||||
}
|
}
|
||||||
if (moduleInfo.config == null || moduleInfo.config.isEmpty()) {
|
if (moduleInfo.config == null || moduleInfo.config!!.isEmpty()) {
|
||||||
moduleInfo.config = moduleConfigsFallbacks.get(moduleInfo.id);
|
moduleInfo.config = moduleConfigsFallbacks[moduleInfo.id]
|
||||||
}
|
}
|
||||||
if (moduleInfo.minApi == 0) {
|
if (moduleInfo.minApi == 0) {
|
||||||
Integer minApiFallback = moduleMinApiFallbacks.get(moduleInfo.id);
|
val minApiFallback = moduleMinApiFallbacks[moduleInfo.id]
|
||||||
if (minApiFallback != null)
|
if (minApiFallback != null) moduleInfo.minApi =
|
||||||
moduleInfo.minApi = minApiFallback;
|
minApiFallback else if (moduleInfo.id.startsWith("riru_")
|
||||||
else if (moduleInfo.id.startsWith("riru_")
|
|| moduleInfo.id.startsWith("riru-")
|
||||||
|| moduleInfo.id.startsWith("riru-"))
|
) moduleInfo.minApi = RIRU_MIN_API
|
||||||
moduleInfo.minApi = RIRU_MIN_API;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some module are really so low quality that it has become very annoying.
|
// Some module are really so low quality that it has become very annoying.
|
||||||
public static boolean isLowQualityModule(ModuleInfo moduleInfo) {
|
@JvmStatic
|
||||||
final String description;
|
fun isLowQualityModule(moduleInfo: ModuleInfo?): Boolean {
|
||||||
return moduleInfo == null || moduleInfo.hasFlag(ModuleInfo.FLAG_METADATA_INVALID)
|
var description: String = moduleInfo?.description ?: return true
|
||||||
|| moduleInfo.name.length() < 3 || moduleInfo.versionCode < 0
|
return (moduleInfo.hasFlag(ModuleInfo.FLAG_METADATA_INVALID) || moduleInfo.name!!.length < 3 || moduleInfo.versionCode < 0 || moduleInfo.author == null || !TextUtils.isGraphic(
|
||||||
|| moduleInfo.author == null || !TextUtils.isGraphic(moduleInfo.author)
|
moduleInfo.author
|
||||||
|| isNullString(description = moduleInfo.description) || !TextUtils.isGraphic(description)
|
) || isNullString(moduleInfo.description.also {
|
||||||
|| description.toLowerCase(Locale.ROOT).equals(moduleInfo.name.toLowerCase(Locale.ROOT))
|
description = it!!
|
||||||
|| (getFlagsForModule(moduleInfo.id) & FLAG_COMPAT_LOW_QUALITY) != 0
|
}) || !TextUtils.isGraphic(description)) || description.lowercase() == moduleInfo.name!!.lowercase() || AppUpdateManager.getFlagsForModule(
|
||||||
|| (moduleInfo.id.startsWith("."));
|
moduleInfo.id
|
||||||
|
) and AppUpdateManager.FLAG_COMPAT_LOW_QUALITY != 0 || moduleInfo.id.startsWith(".")
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isInvalidValue(String name) {
|
private fun isInvalidValue(name: String?): Boolean {
|
||||||
return !TextUtils.isGraphic(name) || name.indexOf('\0') != -1;
|
return !TextUtils.isGraphic(name) || name!!.indexOf('\u0000') != -1
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInvalidURL(String url) {
|
@JvmStatic
|
||||||
int i = url.indexOf('/', 8);
|
fun isInvalidURL(url: String): Boolean {
|
||||||
int e = url.indexOf('.', 8);
|
val i = url.indexOf('/', 8)
|
||||||
return i == -1 || e == -1 || e >= i || !url.startsWith("https://")
|
val e = url.indexOf('.', 8)
|
||||||
|| url.length() <= 12 || url.indexOf('\0') != -1;
|
return i == -1 || e == -1 || e >= i || !url.startsWith("https://") || url.length <= 12 || url.indexOf(
|
||||||
|
'\u0000'
|
||||||
|
) != -1
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String makeNameFromId(String moduleId) {
|
private fun makeNameFromId(moduleId: String): String {
|
||||||
return moduleId.substring(0, 1).toUpperCase(Locale.ROOT) +
|
return moduleId.substring(0, 1).uppercase() +
|
||||||
moduleId.substring(1).replace('_', ' ');
|
moduleId.substring(1).replace('_', ' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isNullString(String string) {
|
@JvmStatic
|
||||||
return string == null || string.isEmpty() || "null".equals(string);
|
fun isNullString(string: String?): Boolean {
|
||||||
|
return string.isNullOrEmpty() || "null" == string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make versionName no longer than 16 charters to avoid UI overflow.
|
// Make versionName no longer than 16 charters to avoid UI overflow.
|
||||||
public static String shortenVersionName(String versionName, long versionCode) {
|
fun shortenVersionName(versionName: String?, versionCode: Long): String {
|
||||||
if (isNullString(versionName)) return "v" + versionCode;
|
if (isNullString(versionName)) return "v$versionCode"
|
||||||
if (versionName.length() <= 16) return versionName;
|
if (versionName!!.length <= 16) return versionName
|
||||||
int i = versionName.lastIndexOf('.');
|
val i = versionName.lastIndexOf('.')
|
||||||
if (i != -1 && i <= 16 && versionName.indexOf('.') != i
|
return if (i != -1 && i <= 16 && versionName.indexOf('.') != i && versionName.indexOf(
|
||||||
&& versionName.indexOf(' ') == -1)
|
' '
|
||||||
return versionName.substring(0, i);
|
) == -1
|
||||||
return "v" + versionCode;
|
) versionName.substring(0, i) else "v$versionCode"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue