parent
4638823c4d
commit
bf8578de2a
@ -1,231 +0,0 @@
|
|||||||
package com.fox2code.mmm;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.AttrRes;
|
|
||||||
import androidx.annotation.DrawableRes;
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
|
|
||||||
import com.fox2code.foxcompat.app.FoxActivity;
|
|
||||||
import com.fox2code.mmm.installer.InstallerInitializer;
|
|
||||||
import com.fox2code.mmm.module.ModuleViewListBuilder;
|
|
||||||
import com.fox2code.mmm.repo.RepoManager;
|
|
||||||
import com.fox2code.mmm.utils.IntentHelper;
|
|
||||||
import com.fox2code.mmm.utils.io.Files;
|
|
||||||
import com.fox2code.mmm.utils.io.net.Http;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipFile;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public enum NotificationType implements NotificationTypeCst {
|
|
||||||
DEBUG(R.string.debug_build, R.drawable.ic_baseline_bug_report_24, com.google.android.material.R.attr.colorSecondary, com.google.android.material.R.attr.colorOnSecondary) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return !BuildConfig.DEBUG;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
SHOWCASE_MODE(R.string.showcase_mode, R.drawable.ic_baseline_lock_24,
|
|
||||||
androidx.appcompat.R.attr.colorPrimary, com.google.android.material.R.attr.colorOnPrimary) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return !MainApplication.isShowcaseMode();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NO_MAGISK(R.string.fail_magisk_missing, R.drawable.ic_baseline_numbers_24, v ->
|
|
||||||
IntentHelper.openUrl(v.getContext(),
|
|
||||||
"https://github.com/topjohnwu/Magisk/blob/master/docs/install.md")) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return InstallerInitializer.getErrorNotification() != this;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NO_ROOT(R.string.fail_root_magisk, R.drawable.ic_baseline_numbers_24) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return InstallerInitializer.getErrorNotification() != this;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ROOT_DENIED(R.string.fail_root_denied, R.drawable.ic_baseline_numbers_24) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return InstallerInitializer.getErrorNotification() != this;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MAGISK_OUTDATED(R.string.magisk_outdated, R.drawable.ic_baseline_update_24, v -> IntentHelper.openUrl(v.getContext(), "https://github.com/topjohnwu/Magisk/releases")) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return InstallerInitializer.peekMagiskPath() == null ||
|
|
||||||
InstallerInitializer.peekMagiskVersion() >=
|
|
||||||
Constants.MAGISK_VER_CODE_INSTALL_COMMAND;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NO_INTERNET(R.string.fail_internet, R.drawable.ic_baseline_cloud_off_24) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return RepoManager.getINSTANCE().hasConnectivity();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
REPO_UPDATE_FAILED(R.string.repo_update_failed, R.drawable.ic_baseline_cloud_off_24) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return RepoManager.getINSTANCE().isLastUpdateSuccess();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NEED_CAPTCHA_ANDROIDACY(R.string.androidacy_need_captcha, R.drawable.ic_baseline_refresh_24, v ->
|
|
||||||
IntentHelper.openUrlAndroidacy(v.getContext(),
|
|
||||||
"https://" + Http.needCaptchaAndroidacyHost() + "/", false)) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return !RepoManager.isAndroidacyRepoEnabled()
|
|
||||||
|| !Http.needCaptchaAndroidacy();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NO_WEB_VIEW(R.string.no_web_view, R.drawable.ic_baseline_android_24) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return Http.hasWebView();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UPDATE_AVAILABLE(R.string.app_update_available, R.drawable.ic_baseline_system_update_24,
|
|
||||||
androidx.appcompat.R.attr.colorPrimary, com.google.android.material.R.attr.colorOnPrimary, v -> IntentHelper.openUrl(v.getContext(),
|
|
||||||
"https://github.com/Androidacy/MagiskModuleManager/releases"), false) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return !AppUpdateManager.getAppUpdateManager().peekShouldUpdate();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
INSTALL_FROM_STORAGE(R.string.install_from_storage, R.drawable.ic_baseline_storage_24,
|
|
||||||
androidx.appcompat.R.attr.colorBackgroundFloating, com.google.android.material.R.attr.colorOnBackground, v -> {
|
|
||||||
FoxActivity compatActivity = FoxActivity.getFoxActivity(v);
|
|
||||||
final File module = new File(compatActivity.getCacheDir(),
|
|
||||||
"installer" + File.separator + "module.zip");
|
|
||||||
IntentHelper.openFileTo(compatActivity, module, (d, u, s) -> {
|
|
||||||
if (s == IntentHelper.RESPONSE_FILE) {
|
|
||||||
try {
|
|
||||||
if (needPatch(d)) {
|
|
||||||
Files.patchModuleSimple(Files.read(d),
|
|
||||||
new FileOutputStream(d));
|
|
||||||
}
|
|
||||||
if (needPatch(d)) {
|
|
||||||
if (d.exists() && !d.delete())
|
|
||||||
Timber.w("Failed to delete non module zip");
|
|
||||||
Toast.makeText(compatActivity,
|
|
||||||
R.string.invalid_format, Toast.LENGTH_SHORT).show();
|
|
||||||
} else {
|
|
||||||
IntentHelper.openInstaller(compatActivity, d.getAbsolutePath(),
|
|
||||||
compatActivity.getString(
|
|
||||||
R.string.local_install_title), null, null, false,
|
|
||||||
BuildConfig.DEBUG && // Use debug mode if no root
|
|
||||||
InstallerInitializer.peekMagiskPath() == null);
|
|
||||||
}
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
if (d.exists() && !d.delete())
|
|
||||||
Timber.w("Failed to delete invalid module");
|
|
||||||
Toast.makeText(compatActivity,
|
|
||||||
R.string.invalid_format, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
} else if (s == IntentHelper.RESPONSE_URL) {
|
|
||||||
IntentHelper.openInstaller(compatActivity, u.toString(),
|
|
||||||
compatActivity.getString(
|
|
||||||
R.string.remote_install_title), null, null, false,
|
|
||||||
BuildConfig.DEBUG && // Use debug mode if no root
|
|
||||||
InstallerInitializer.peekMagiskPath() == null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, false) {
|
|
||||||
@Override
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
return !BuildConfig.DEBUG &&
|
|
||||||
(MainApplication.isShowcaseMode() ||
|
|
||||||
InstallerInitializer.peekMagiskPath() == null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static boolean needPatch(File target) {
|
|
||||||
try (ZipFile zipFile = new ZipFile(target)) {
|
|
||||||
boolean validEntries = zipFile.getEntry("module.prop") != null;
|
|
||||||
// ensure there's no anykernel.sh
|
|
||||||
validEntries &= zipFile.getEntry("anykernel.sh") == null;
|
|
||||||
if (validEntries) {
|
|
||||||
// Ensure id of module is not empty and matches ^[a-zA-Z][a-zA-Z0-9._-]+$ regex
|
|
||||||
// We need to get the module.prop and parse the id= line
|
|
||||||
ZipEntry moduleProp = zipFile.getEntry("module.prop");
|
|
||||||
// Parse the module.prop
|
|
||||||
if (moduleProp != null) {
|
|
||||||
// Find the line with id=, and check if it matches the regex
|
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(zipFile.getInputStream(moduleProp)))) {
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
if (line.startsWith("id=")) {
|
|
||||||
String id = line.substring(3);
|
|
||||||
return id.isEmpty() || !id.matches("^[a-zA-Z][a-zA-Z0-9._-]+$");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@StringRes
|
|
||||||
public final int textId;
|
|
||||||
@DrawableRes
|
|
||||||
public final int iconId;
|
|
||||||
@AttrRes
|
|
||||||
public final int backgroundAttr;
|
|
||||||
@AttrRes
|
|
||||||
public final int foregroundAttr;
|
|
||||||
public final View.OnClickListener onClickListener;
|
|
||||||
public final boolean special;
|
|
||||||
|
|
||||||
NotificationType(@StringRes int textId, int iconId) {
|
|
||||||
this(textId, iconId, androidx.appcompat.R.attr.colorError, com.google.android.material.R.attr.colorOnPrimary);
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationType(@StringRes int textId, int iconId, View.OnClickListener onClickListener) {
|
|
||||||
this(textId, iconId, androidx.appcompat.R.attr.colorError, com.google.android.material.R.attr.colorOnPrimary, onClickListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationType(@StringRes int textId, int iconId, int backgroundAttr, int foregroundAttr) {
|
|
||||||
this(textId, iconId, backgroundAttr, foregroundAttr, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationType(@StringRes int textId, int iconId, int backgroundAttr, int foregroundAttr,
|
|
||||||
View.OnClickListener onClickListener) {
|
|
||||||
this(textId, iconId, backgroundAttr, foregroundAttr, onClickListener, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationType(@StringRes int textId, int iconId, int backgroundAttr, int foregroundAttr,
|
|
||||||
View.OnClickListener onClickListener, @SuppressWarnings("SameParameterValue") boolean special) {
|
|
||||||
this.textId = textId;
|
|
||||||
this.iconId = iconId;
|
|
||||||
this.backgroundAttr = backgroundAttr;
|
|
||||||
this.foregroundAttr = foregroundAttr;
|
|
||||||
this.onClickListener = onClickListener;
|
|
||||||
this.special = special;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldRemove() {
|
|
||||||
// By default, remove the notification`
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void autoAdd(ModuleViewListBuilder moduleViewListBuilder) {
|
|
||||||
if (!shouldRemove()) moduleViewListBuilder.addNotification(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,256 @@
|
|||||||
|
@file:Suppress("KotlinConstantConditions", "UNINITIALIZED_ENUM_COMPANION_WARNING",
|
||||||
|
"ktConcatNullable", "BlockingMethodInNonBlockingContext"
|
||||||
|
)
|
||||||
|
|
||||||
|
package com.fox2code.mmm
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.AttrRes
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import com.fox2code.foxcompat.app.FoxActivity
|
||||||
|
import com.fox2code.mmm.installer.InstallerInitializer
|
||||||
|
import com.fox2code.mmm.module.ModuleViewListBuilder
|
||||||
|
import com.fox2code.mmm.repo.RepoManager
|
||||||
|
import com.fox2code.mmm.utils.IntentHelper
|
||||||
|
import com.fox2code.mmm.utils.io.Files.Companion.patchModuleSimple
|
||||||
|
import com.fox2code.mmm.utils.io.Files.Companion.read
|
||||||
|
import com.fox2code.mmm.utils.io.net.Http
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
|
||||||
|
enum class NotificationType constructor(
|
||||||
|
@field:StringRes @param:StringRes val textId: Int,
|
||||||
|
@field:DrawableRes val iconId: Int,
|
||||||
|
@field:AttrRes val backgroundAttr: Int = androidx.appcompat.R.attr.colorError,
|
||||||
|
@field:AttrRes val foregroundAttr: Int = com.google.android.material.R.attr.colorOnPrimary,
|
||||||
|
val onClickListener: View.OnClickListener? = null,
|
||||||
|
val special: Boolean = false
|
||||||
|
) : NotificationTypeCst {
|
||||||
|
DEBUG(
|
||||||
|
R.string.debug_build,
|
||||||
|
R.drawable.ic_baseline_bug_report_24,
|
||||||
|
com.google.android.material.R.attr.colorSecondary,
|
||||||
|
com.google.android.material.R.attr.colorOnSecondary
|
||||||
|
) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return !BuildConfig.DEBUG
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SHOWCASE_MODE(
|
||||||
|
R.string.showcase_mode, R.drawable.ic_baseline_lock_24,
|
||||||
|
androidx.appcompat.R.attr.colorPrimary, com.google.android.material.R.attr.colorOnPrimary
|
||||||
|
) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return !MainApplication.isShowcaseMode()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NO_MAGISK(
|
||||||
|
R.string.fail_magisk_missing,
|
||||||
|
R.drawable.ic_baseline_numbers_24,
|
||||||
|
View.OnClickListener { v: View ->
|
||||||
|
IntentHelper.openUrl(
|
||||||
|
v.context,
|
||||||
|
"https://github.com/topjohnwu/Magisk/blob/master/docs/install.md"
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return InstallerInitializer.getErrorNotification() !== this
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NO_ROOT(R.string.fail_root_magisk, R.drawable.ic_baseline_numbers_24) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return InstallerInitializer.getErrorNotification() !== this
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ROOT_DENIED(R.string.fail_root_denied, R.drawable.ic_baseline_numbers_24) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return InstallerInitializer.getErrorNotification() !== this
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MAGISK_OUTDATED(
|
||||||
|
R.string.magisk_outdated,
|
||||||
|
R.drawable.ic_baseline_update_24,
|
||||||
|
View.OnClickListener { v: View ->
|
||||||
|
IntentHelper.openUrl(
|
||||||
|
v.context,
|
||||||
|
"https://github.com/topjohnwu/Magisk/releases"
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return InstallerInitializer.peekMagiskPath() == null ||
|
||||||
|
InstallerInitializer.peekMagiskVersion() >=
|
||||||
|
Constants.MAGISK_VER_CODE_INSTALL_COMMAND
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NO_INTERNET(R.string.fail_internet, R.drawable.ic_baseline_cloud_off_24) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return RepoManager.getINSTANCE().hasConnectivity()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
REPO_UPDATE_FAILED(R.string.repo_update_failed, R.drawable.ic_baseline_cloud_off_24) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return RepoManager.getINSTANCE().isLastUpdateSuccess
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NEED_CAPTCHA_ANDROIDACY(
|
||||||
|
R.string.androidacy_need_captcha,
|
||||||
|
R.drawable.ic_baseline_refresh_24,
|
||||||
|
View.OnClickListener { v: View ->
|
||||||
|
IntentHelper.openUrlAndroidacy(
|
||||||
|
v.context,
|
||||||
|
"https://" + Http.needCaptchaAndroidacyHost() + "/", false
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return (!RepoManager.isAndroidacyRepoEnabled()
|
||||||
|
|| !Http.needCaptchaAndroidacy())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NO_WEB_VIEW(R.string.no_web_view, R.drawable.ic_baseline_android_24) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return Http.hasWebView()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UPDATE_AVAILABLE(
|
||||||
|
R.string.app_update_available,
|
||||||
|
R.drawable.ic_baseline_system_update_24,
|
||||||
|
androidx.appcompat.R.attr.colorPrimary,
|
||||||
|
com.google.android.material.R.attr.colorOnPrimary,
|
||||||
|
View.OnClickListener { v: View ->
|
||||||
|
IntentHelper.openUrl(
|
||||||
|
v.context,
|
||||||
|
"https://github.com/Androidacy/MagiskModuleManager/releases"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
false
|
||||||
|
) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return !AppUpdateManager.getAppUpdateManager().peekShouldUpdate()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
INSTALL_FROM_STORAGE(
|
||||||
|
R.string.install_from_storage,
|
||||||
|
R.drawable.ic_baseline_storage_24,
|
||||||
|
androidx.appcompat.R.attr.colorBackgroundFloating,
|
||||||
|
com.google.android.material.R.attr.colorOnBackground,
|
||||||
|
View.OnClickListener { v: View? ->
|
||||||
|
val compatActivity = FoxActivity.getFoxActivity(v)
|
||||||
|
val module = File(
|
||||||
|
compatActivity.cacheDir,
|
||||||
|
"installer" + File.separator + "module.zip"
|
||||||
|
)
|
||||||
|
IntentHelper.openFileTo(compatActivity, module) { d: File, u: Uri, s: Int ->
|
||||||
|
if (s == IntentHelper.RESPONSE_FILE) {
|
||||||
|
try {
|
||||||
|
if (needPatch(d)) {
|
||||||
|
patchModuleSimple(
|
||||||
|
read(d),
|
||||||
|
FileOutputStream(d)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (needPatch(d)) {
|
||||||
|
if (d.exists() && !d.delete()) Timber.w("Failed to delete non module zip")
|
||||||
|
Toast.makeText(
|
||||||
|
compatActivity,
|
||||||
|
R.string.invalid_format, Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
} else {
|
||||||
|
IntentHelper.openInstaller(
|
||||||
|
compatActivity, d.absolutePath,
|
||||||
|
compatActivity.getString(
|
||||||
|
R.string.local_install_title
|
||||||
|
), null, null, false,
|
||||||
|
BuildConfig.DEBUG && // Use debug mode if no root
|
||||||
|
InstallerInitializer.peekMagiskPath() == null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (ignored: IOException) {
|
||||||
|
if (d.exists() && !d.delete()) Timber.w("Failed to delete invalid module")
|
||||||
|
Toast.makeText(
|
||||||
|
compatActivity,
|
||||||
|
R.string.invalid_format, Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
} else if (s == IntentHelper.RESPONSE_URL) {
|
||||||
|
IntentHelper.openInstaller(
|
||||||
|
compatActivity, u.toString(),
|
||||||
|
compatActivity.getString(
|
||||||
|
R.string.remote_install_title
|
||||||
|
), null, null, false,
|
||||||
|
BuildConfig.DEBUG && // Use debug mode if no root
|
||||||
|
InstallerInitializer.peekMagiskPath() == null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false
|
||||||
|
) {
|
||||||
|
override fun shouldRemove(): Boolean {
|
||||||
|
return !BuildConfig.DEBUG &&
|
||||||
|
(MainApplication.isShowcaseMode() ||
|
||||||
|
InstallerInitializer.peekMagiskPath() == null)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(@StringRes textId: Int, iconId: Int, onClickListener: View.OnClickListener) : this(
|
||||||
|
textId,
|
||||||
|
iconId,
|
||||||
|
androidx.appcompat.R.attr.colorError,
|
||||||
|
com.google.android.material.R.attr.colorOnPrimary,
|
||||||
|
onClickListener
|
||||||
|
)
|
||||||
|
|
||||||
|
open fun shouldRemove(): Boolean {
|
||||||
|
// By default, remove the notification`
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun autoAdd(moduleViewListBuilder: ModuleViewListBuilder) {
|
||||||
|
if (!shouldRemove()) moduleViewListBuilder.addNotification(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun needPatch(target: File?): Boolean {
|
||||||
|
try {
|
||||||
|
ZipFile(target).use { zipFile ->
|
||||||
|
var validEntries = zipFile.getEntry("module.prop") != null
|
||||||
|
// ensure there's no anykernel.sh
|
||||||
|
validEntries = validEntries and (zipFile.getEntry("anykernel.sh") == null)
|
||||||
|
if (validEntries) {
|
||||||
|
// Ensure id of module is not empty and matches ^[a-zA-Z][a-zA-Z0-9._-]+$ regex
|
||||||
|
// We need to get the module.prop and parse the id= line
|
||||||
|
val moduleProp = zipFile.getEntry("module.prop")
|
||||||
|
// Parse the module.prop
|
||||||
|
if (moduleProp != null) {
|
||||||
|
// Find the line with id=, and check if it matches the regex
|
||||||
|
BufferedReader(InputStreamReader(zipFile.getInputStream(moduleProp))).use { reader ->
|
||||||
|
var line: String
|
||||||
|
while (reader.readLine().also { line = it } != null) {
|
||||||
|
if (line.startsWith("id=")) {
|
||||||
|
val id = line.substring(3)
|
||||||
|
return id.isEmpty() || !id.matches(Regex("^[a-zA-Z][a-zA-Z0-9._-]+$"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue