You've already forked Magisk
mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-09-06 06:36:58 +00:00
Rewrite configs with Kotlin delagate properties
This commit is contained in:
@@ -6,6 +6,7 @@ import com.topjohnwu.magisk.App;
|
||||
import com.topjohnwu.magisk.BuildConfig;
|
||||
import com.topjohnwu.magisk.ClassMap;
|
||||
import com.topjohnwu.magisk.Config;
|
||||
import com.topjohnwu.magisk.Info;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.ui.SplashActivity;
|
||||
import com.topjohnwu.magisk.view.ProgressNotification;
|
||||
@@ -24,8 +25,8 @@ public class DownloadApp {
|
||||
}
|
||||
|
||||
public static void restore() {
|
||||
String name = Utils.fmt("MagiskManager v%s(%d)",
|
||||
Config.remoteManagerVersionString, Config.remoteManagerVersionCode);
|
||||
String name = Utils.INSTANCE.fmt("MagiskManager v%s(%d)",
|
||||
Info.remoteManagerVersionString, Info.remoteManagerVersionCode);
|
||||
dlInstall(name, new RestoreManager());
|
||||
}
|
||||
|
||||
@@ -33,7 +34,7 @@ public class DownloadApp {
|
||||
File apk = new File(App.self.getCacheDir(), "manager.apk");
|
||||
ProgressNotification progress = new ProgressNotification(name);
|
||||
listener.progress = progress;
|
||||
Networking.get(Config.managerLink)
|
||||
Networking.get(Info.managerLink)
|
||||
.setExecutor(App.THREAD_POOL)
|
||||
.setDownloadProgressListener(progress)
|
||||
.setErrorHandler((conn, e) -> progress.dlFail())
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.KeyguardManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Build;
|
||||
import android.os.CancellationSignal;
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
import android.security.keystore.KeyPermanentlyInvalidatedException;
|
||||
import android.security.keystore.KeyProperties;
|
||||
|
||||
import com.topjohnwu.magisk.App;
|
||||
import com.topjohnwu.magisk.Config;
|
||||
import com.topjohnwu.magisk.Const;
|
||||
|
||||
import java.security.KeyStore;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public abstract class FingerprintHelper {
|
||||
|
||||
private FingerprintManager manager;
|
||||
private Cipher cipher;
|
||||
private CancellationSignal cancel;
|
||||
private static final String SU_KEYSTORE_KEY = "su_key";
|
||||
|
||||
public static boolean useFingerprint() {
|
||||
boolean fp = Config.get(Config.Key.SU_FINGERPRINT);
|
||||
if (fp && !canUseFingerprint()) {
|
||||
Config.set(Config.Key.SU_FINGERPRINT, false);
|
||||
fp = false;
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
public static boolean canUseFingerprint() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||
return false;
|
||||
KeyguardManager km = App.self.getSystemService(KeyguardManager.class);
|
||||
FingerprintManager fm = App.self.getSystemService(FingerprintManager.class);
|
||||
return km.isKeyguardSecure() && fm != null && fm.isHardwareDetected() && fm.hasEnrolledFingerprints();
|
||||
}
|
||||
|
||||
protected FingerprintHelper() throws Exception {
|
||||
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||
manager = App.self.getSystemService(FingerprintManager.class);
|
||||
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
|
||||
+ KeyProperties.BLOCK_MODE_CBC + "/"
|
||||
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
||||
keyStore.load(null);
|
||||
SecretKey key = (SecretKey) keyStore.getKey(SU_KEYSTORE_KEY, null);
|
||||
if (key == null) {
|
||||
key = generateKey();
|
||||
}
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
} catch (KeyPermanentlyInvalidatedException e) {
|
||||
// Only happens on Marshmallow
|
||||
key = generateKey();
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onAuthenticationError(int errorCode, CharSequence errString);
|
||||
|
||||
public abstract void onAuthenticationHelp(int helpCode, CharSequence helpString);
|
||||
|
||||
public abstract void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result);
|
||||
|
||||
public abstract void onAuthenticationFailed();
|
||||
|
||||
public void authenticate() {
|
||||
cancel = new CancellationSignal();
|
||||
FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
|
||||
manager.authenticate(cryptoObject, cancel, 0, new Callback(), null);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (cancel != null)
|
||||
cancel.cancel();
|
||||
}
|
||||
|
||||
private SecretKey generateKey() throws Exception {
|
||||
KeyGenerator keygen = KeyGenerator
|
||||
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
|
||||
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
|
||||
SU_KEYSTORE_KEY,
|
||||
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
|
||||
.setUserAuthenticationRequired(true)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
builder.setInvalidatedByBiometricEnrollment(false);
|
||||
}
|
||||
keygen.init(builder.build());
|
||||
return keygen.generateKey();
|
||||
}
|
||||
|
||||
private class Callback extends FingerprintManager.AuthenticationCallback {
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, CharSequence errString) {
|
||||
FingerprintHelper.this.onAuthenticationError(errorCode, errString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
|
||||
FingerprintHelper.this.onAuthenticationHelp(helpCode, helpString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
|
||||
FingerprintHelper.this.onAuthenticationSucceeded(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
FingerprintHelper.this.onAuthenticationFailed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.KeyguardManager
|
||||
import android.content.Context
|
||||
import android.hardware.fingerprint.FingerprintManager
|
||||
import android.os.Build
|
||||
import android.os.CancellationSignal
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyProperties
|
||||
import com.topjohnwu.magisk.Config
|
||||
import java.security.KeyStore
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.KeyGenerator
|
||||
import javax.crypto.SecretKey
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
abstract class FingerprintHelper @Throws(Exception::class)
|
||||
protected constructor() {
|
||||
|
||||
private val manager: FingerprintManager?
|
||||
private val cipher: Cipher
|
||||
private var cancel: CancellationSignal? = null
|
||||
private val context: Context by inject()
|
||||
|
||||
init {
|
||||
val keyStore = KeyStore.getInstance("AndroidKeyStore")
|
||||
manager = context.getSystemService(FingerprintManager::class.java)
|
||||
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
|
||||
+ KeyProperties.BLOCK_MODE_CBC + "/"
|
||||
+ KeyProperties.ENCRYPTION_PADDING_PKCS7)
|
||||
keyStore.load(null)
|
||||
var key = keyStore.getKey(SU_KEYSTORE_KEY, null) as SecretKey? ?: generateKey()
|
||||
runCatching {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key)
|
||||
}.onFailure {
|
||||
// Only happens on Marshmallow
|
||||
key = generateKey()
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key)
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun onAuthenticationError(errorCode: Int, errString: CharSequence)
|
||||
|
||||
abstract fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence)
|
||||
|
||||
abstract fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult)
|
||||
|
||||
abstract fun onAuthenticationFailed()
|
||||
|
||||
fun authenticate() {
|
||||
cancel = CancellationSignal()
|
||||
val cryptoObject = FingerprintManager.CryptoObject(cipher)
|
||||
manager!!.authenticate(cryptoObject, cancel, 0, Callback(), null)
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
if (cancel != null)
|
||||
cancel!!.cancel()
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
private fun generateKey(): SecretKey {
|
||||
val keygen = KeyGenerator
|
||||
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
|
||||
val builder = KeyGenParameterSpec.Builder(
|
||||
SU_KEYSTORE_KEY,
|
||||
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
|
||||
.setUserAuthenticationRequired(true)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
builder.setInvalidatedByBiometricEnrollment(false)
|
||||
}
|
||||
keygen.init(builder.build())
|
||||
return keygen.generateKey()
|
||||
}
|
||||
|
||||
private inner class Callback : FingerprintManager.AuthenticationCallback() {
|
||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||
this@FingerprintHelper.onAuthenticationError(errorCode, errString)
|
||||
}
|
||||
|
||||
override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence) {
|
||||
this@FingerprintHelper.onAuthenticationHelp(helpCode, helpString)
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) {
|
||||
this@FingerprintHelper.onAuthenticationSucceeded(result)
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
this@FingerprintHelper.onAuthenticationFailed()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SU_KEYSTORE_KEY = "su_key"
|
||||
|
||||
fun useFingerprint(): Boolean {
|
||||
var fp = Config.suFingerprint
|
||||
if (fp && !canUseFingerprint()) {
|
||||
Config.suFingerprint = false
|
||||
fp = false
|
||||
}
|
||||
return fp
|
||||
}
|
||||
|
||||
fun canUseFingerprint(context: Context = get()): Boolean {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||
return false
|
||||
val km = context.getSystemService(KeyguardManager::class.java)
|
||||
val fm = context.getSystemService(FingerprintManager::class.java)
|
||||
return km?.isKeyguardSecure ?: false &&
|
||||
fm != null && fm.isHardwareDetected && fm.hasEnrolledFingerprints()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,9 +107,9 @@ object LocaleManager {
|
||||
|
||||
@JvmStatic
|
||||
fun setLocale(wrapper: ContextWrapper) {
|
||||
val localeConfig = Config.get<String>(Config.Key.LOCALE)
|
||||
val localeConfig = Config.locale
|
||||
locale = when {
|
||||
localeConfig.isNullOrEmpty() -> defaultLocale
|
||||
localeConfig.isEmpty() -> defaultLocale
|
||||
else -> forLanguageTag(localeConfig)
|
||||
}
|
||||
Locale.setDefault(locale)
|
||||
|
||||
@@ -13,7 +13,7 @@ public class Logger {
|
||||
}
|
||||
|
||||
public static void debug(String fmt, Object... args) {
|
||||
debug(Utils.fmt(fmt, args));
|
||||
debug(Utils.INSTANCE.fmt(fmt, args));
|
||||
}
|
||||
|
||||
public static void error(String line) {
|
||||
@@ -21,6 +21,6 @@ public class Logger {
|
||||
}
|
||||
|
||||
public static void error(String fmt, Object... args) {
|
||||
error(Utils.fmt(fmt, args));
|
||||
error(Utils.INSTANCE.fmt(fmt, args));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.topjohnwu.magisk.utils;
|
||||
import android.content.ComponentName;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import com.topjohnwu.magisk.App;
|
||||
import com.topjohnwu.magisk.BuildConfig;
|
||||
import com.topjohnwu.magisk.ClassMap;
|
||||
@@ -27,8 +29,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
public class PatchAPK {
|
||||
|
||||
public static final String LOWERALPHA = "abcdefghijklmnopqrstuvwxyz";
|
||||
@@ -110,7 +110,7 @@ public class PatchAPK {
|
||||
if (!Shell.su("pm install " + repack).exec().isSuccess())
|
||||
return false;
|
||||
|
||||
Config.set(Config.Key.SU_MANAGER, pkg);
|
||||
Config.setSuManager(pkg);
|
||||
Config.export();
|
||||
RootUtils.rmAndLaunch(BuildConfig.APPLICATION_ID,
|
||||
new ComponentName(pkg, ClassMap.get(SplashActivity.class).getName()));
|
||||
@@ -145,7 +145,7 @@ public class PatchAPK {
|
||||
Notifications.progress(app.getString(R.string.hide_manager_title));
|
||||
Notifications.mgr.notify(Const.ID.HIDE_MANAGER_NOTIFICATION_ID, progress.build());
|
||||
if(!patchAndHide())
|
||||
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
|
||||
Utils.INSTANCE.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
|
||||
Notifications.mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.ShellUtils
|
||||
@@ -132,7 +132,7 @@ class RootUtils : Shell.Initializer() {
|
||||
job.add(context.rawResource(R.raw.util_functions))
|
||||
.add(context.rawResource(R.raw.utils))
|
||||
Const.MAGISK_DISABLE_FILE = SuFile("/cache/.disable_magisk")
|
||||
Config.loadMagiskInfo()
|
||||
Info.loadMagiskInfo()
|
||||
} else {
|
||||
job.add(context.rawResource(R.raw.nonroot_utils))
|
||||
}
|
||||
@@ -143,9 +143,9 @@ class RootUtils : Shell.Initializer() {
|
||||
"export BOOTMODE=true")
|
||||
.exec()
|
||||
|
||||
Config.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean()
|
||||
Config.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean()
|
||||
Config.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean()
|
||||
Info.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean()
|
||||
Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean()
|
||||
Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ class RootUtils : Shell.Initializer() {
|
||||
|
||||
@JvmStatic
|
||||
fun reboot() {
|
||||
Shell.su("/system/bin/reboot ${if (Config.recovery) "recovery" else ""}").submit()
|
||||
Shell.su("/system/bin/reboot ${if (Info.recovery) "recovery" else ""}").submit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Process
|
||||
import android.widget.Toast
|
||||
import com.topjohnwu.magisk.App
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.data.repository.AppRepository
|
||||
@@ -17,6 +17,8 @@ import java.util.*
|
||||
|
||||
object SuLogger {
|
||||
|
||||
private val context: Context by inject()
|
||||
|
||||
@JvmStatic
|
||||
fun handleLogs(intent: Intent) {
|
||||
|
||||
@@ -66,9 +68,9 @@ object SuLogger {
|
||||
}
|
||||
|
||||
private fun handleNotify(policy: MagiskPolicy) {
|
||||
if (policy.notification && Config.get<Any>(Config.Key.SU_NOTIFICATION) as Int == Config.Value.NOTIFICATION_TOAST) {
|
||||
if (policy.notification && Config.suNotification == Config.Value.NOTIFICATION_TOAST) {
|
||||
Utils.toast(
|
||||
App.self.getString(
|
||||
context.getString(
|
||||
if (policy.policy == Policy.ALLOW)
|
||||
R.string.su_allow_toast
|
||||
else
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.App;
|
||||
import com.topjohnwu.magisk.BuildConfig;
|
||||
import com.topjohnwu.magisk.ClassMap;
|
||||
import com.topjohnwu.magisk.Config;
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.model.entity.OldModule;
|
||||
import com.topjohnwu.magisk.model.update.UpdateCheckService;
|
||||
import com.topjohnwu.net.Networking;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.work.Constraints;
|
||||
import androidx.work.ExistingPeriodicWorkPolicy;
|
||||
import androidx.work.ListenableWorker;
|
||||
import androidx.work.NetworkType;
|
||||
import androidx.work.PeriodicWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
public class Utils {
|
||||
|
||||
public static void toast(CharSequence msg, int duration) {
|
||||
UiThreadHandler.run(() -> Toast.makeText(App.self, msg, duration).show());
|
||||
}
|
||||
|
||||
public static void toast(int resId, int duration) {
|
||||
UiThreadHandler.run(() -> Toast.makeText(App.self, resId, duration).show());
|
||||
}
|
||||
|
||||
public static String dlString(String url) {
|
||||
String s = Networking.get(url).execForString().getResult();
|
||||
return s == null ? "" : s;
|
||||
}
|
||||
|
||||
public static int getPrefsInt(SharedPreferences prefs, String key, int def) {
|
||||
return Integer.parseInt(prefs.getString(key, String.valueOf(def)));
|
||||
}
|
||||
|
||||
public static int getPrefsInt(SharedPreferences prefs, String key) {
|
||||
return getPrefsInt(prefs, key, 0);
|
||||
}
|
||||
|
||||
public static int dpInPx(int dp) {
|
||||
float scale = App.self.getResources().getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5);
|
||||
}
|
||||
|
||||
public static String fmt(String fmt, Object... args) {
|
||||
return String.format(Locale.US, fmt, args);
|
||||
}
|
||||
|
||||
public static String getAppLabel(ApplicationInfo info, PackageManager pm) {
|
||||
try {
|
||||
if (info.labelRes > 0) {
|
||||
Resources res = pm.getResourcesForApplication(info);
|
||||
Configuration config = new Configuration();
|
||||
config.setLocale(LocaleManager.getLocale());
|
||||
res.updateConfiguration(config, res.getDisplayMetrics());
|
||||
return res.getString(info.labelRes);
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return info.loadLabel(pm).toString();
|
||||
}
|
||||
|
||||
public static String getLegalFilename(CharSequence filename) {
|
||||
return filename.toString().replace(" ", "_").replace("'", "").replace("\"", "")
|
||||
.replace("$", "").replace("`", "").replace("*", "").replace("/", "_")
|
||||
.replace("#", "").replace("@", "").replace("\\", "_");
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static Map<String, OldModule> loadModulesLeanback() {
|
||||
final Map<String, OldModule> moduleMap = new ValueSortedMap<>();
|
||||
final SuFile path = new SuFile(Const.MAGISK_PATH);
|
||||
final SuFile[] modules = path.listFiles((file, name) ->
|
||||
!name.equals("lost+found") && !name.equals(".core")
|
||||
);
|
||||
for (SuFile file : modules) {
|
||||
if (file.isFile()) continue;
|
||||
OldModule module = new OldModule(Const.MAGISK_PATH + "/" + file.getName());
|
||||
moduleMap.put(module.getId(), module);
|
||||
}
|
||||
return moduleMap;
|
||||
}
|
||||
|
||||
public static boolean showSuperUser() {
|
||||
return Shell.rootAccess() && (Const.USER_ID == 0 ||
|
||||
(int) Config.get(Config.Key.SU_MULTIUSER_MODE) !=
|
||||
Config.Value.MULTIUSER_MODE_OWNER_MANAGED);
|
||||
}
|
||||
|
||||
public static boolean isCanary() {
|
||||
return BuildConfig.VERSION_NAME.contains("-");
|
||||
}
|
||||
|
||||
public static void scheduleUpdateCheck() {
|
||||
if (Config.get(Config.Key.CHECK_UPDATES)) {
|
||||
Constraints constraints = new Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.setRequiresDeviceIdle(true)
|
||||
.build();
|
||||
PeriodicWorkRequest request = new PeriodicWorkRequest
|
||||
.Builder(ClassMap.get(UpdateCheckService.class), 12, TimeUnit.HOURS)
|
||||
.setConstraints(constraints)
|
||||
.build();
|
||||
WorkManager.getInstance().enqueueUniquePeriodicWork(
|
||||
Const.ID.CHECK_MAGISK_UPDATE_WORKER_ID,
|
||||
ExistingPeriodicWorkPolicy.REPLACE, request);
|
||||
} else {
|
||||
WorkManager.getInstance().cancelUniqueWork(Const.ID.CHECK_MAGISK_UPDATE_WORKER_ID);
|
||||
}
|
||||
}
|
||||
|
||||
public static void openLink(Context context, Uri link) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, link);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
if (intent.resolveActivity(context.getPackageManager()) != null) {
|
||||
context.startActivity(intent);
|
||||
} else {
|
||||
toast(R.string.open_link_failed_toast, Toast.LENGTH_SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.work.*
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.model.entity.OldModule
|
||||
import com.topjohnwu.magisk.model.update.UpdateCheckService
|
||||
import com.topjohnwu.net.Networking
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
object Utils {
|
||||
|
||||
val isCanary: Boolean
|
||||
get() = BuildConfig.VERSION_NAME.contains("-")
|
||||
|
||||
fun toast(msg: CharSequence, duration: Int) {
|
||||
UiThreadHandler.run { Toast.makeText(get(), msg, duration).show() }
|
||||
}
|
||||
|
||||
fun toast(resId: Int, duration: Int) {
|
||||
UiThreadHandler.run { Toast.makeText(get(), resId, duration).show() }
|
||||
}
|
||||
|
||||
fun dlString(url: String): String {
|
||||
val s = Networking.get(url).execForString().result
|
||||
return s ?: ""
|
||||
}
|
||||
|
||||
fun getPrefsInt(prefs: SharedPreferences, key: String, def: Int = 0): Int {
|
||||
return prefs.getString(key, def.toString())!!.toInt()
|
||||
}
|
||||
|
||||
fun dpInPx(dp: Int): Int {
|
||||
val scale = get<Resources>().displayMetrics.density
|
||||
return (dp * scale + 0.5).toInt()
|
||||
}
|
||||
|
||||
fun fmt(fmt: String, vararg args: Any): String {
|
||||
return String.format(Locale.US, fmt, *args)
|
||||
}
|
||||
|
||||
fun getAppLabel(info: ApplicationInfo, pm: PackageManager): String {
|
||||
try {
|
||||
if (info.labelRes > 0) {
|
||||
val res = pm.getResourcesForApplication(info)
|
||||
val config = Configuration()
|
||||
config.setLocale(LocaleManager.locale)
|
||||
res.updateConfiguration(config, res.displayMetrics)
|
||||
return res.getString(info.labelRes)
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
return info.loadLabel(pm).toString()
|
||||
}
|
||||
|
||||
fun getLegalFilename(filename: CharSequence): String {
|
||||
return filename.toString().replace(" ", "_").replace("'", "").replace("\"", "")
|
||||
.replace("$", "").replace("`", "").replace("*", "").replace("/", "_")
|
||||
.replace("#", "").replace("@", "").replace("\\", "_")
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun loadModulesLeanback(): Map<String, OldModule> {
|
||||
val moduleMap = ValueSortedMap<String, OldModule>()
|
||||
val path = SuFile(Const.MAGISK_PATH)
|
||||
val modules = path.listFiles { _, name -> name != "lost+found" && name != ".core" }
|
||||
for (file in modules!!) {
|
||||
if (file.isFile) continue
|
||||
val module = OldModule(Const.MAGISK_PATH + "/" + file.name)
|
||||
moduleMap[module.id] = module
|
||||
}
|
||||
return moduleMap
|
||||
}
|
||||
|
||||
fun showSuperUser(): Boolean {
|
||||
return Shell.rootAccess() && (Const.USER_ID == 0
|
||||
|| Config.suMultiuserMode != Config.Value.MULTIUSER_MODE_OWNER_MANAGED)
|
||||
}
|
||||
|
||||
fun scheduleUpdateCheck() {
|
||||
if (Config.checkUpdate) {
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.setRequiresDeviceIdle(true)
|
||||
.build()
|
||||
val request = PeriodicWorkRequest
|
||||
.Builder(ClassMap[UpdateCheckService::class.java], 12, TimeUnit.HOURS)
|
||||
.setConstraints(constraints)
|
||||
.build()
|
||||
WorkManager.getInstance().enqueueUniquePeriodicWork(
|
||||
Const.ID.CHECK_MAGISK_UPDATE_WORKER_ID,
|
||||
ExistingPeriodicWorkPolicy.REPLACE, request)
|
||||
} else {
|
||||
WorkManager.getInstance().cancelUniqueWork(Const.ID.CHECK_MAGISK_UPDATE_WORKER_ID)
|
||||
}
|
||||
}
|
||||
|
||||
fun openLink(context: Context, link: Uri) {
|
||||
val intent = Intent(Intent.ACTION_VIEW, link)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
if (intent.resolveActivity(context.packageManager) != null) {
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
toast(R.string.open_link_failed_toast, Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,6 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import com.topjohnwu.magisk.KConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import okhttp3.ResponseBody
|
||||
import java.io.File
|
||||
|
||||
@@ -19,36 +13,3 @@ fun ResponseBody.writeToFile(context: Context, fileName: String): File {
|
||||
}
|
||||
|
||||
fun ResponseBody.writeToString() = string()
|
||||
|
||||
fun String.launch() = if (KConfig.useCustomTabs) {
|
||||
launchWithCustomTabs()
|
||||
} else {
|
||||
launchWithIntent()
|
||||
}
|
||||
|
||||
|
||||
private fun String.launchWithCustomTabs() {
|
||||
val context: Context by inject()
|
||||
val primaryColor = ContextCompat.getColor(context, R.color.colorPrimary)
|
||||
val secondaryColor = ContextCompat.getColor(context, R.color.colorSecondary)
|
||||
|
||||
CustomTabsIntent.Builder()
|
||||
.enableUrlBarHiding()
|
||||
.setShowTitle(true)
|
||||
.setToolbarColor(primaryColor)
|
||||
.setSecondaryToolbarColor(secondaryColor)
|
||||
.build()
|
||||
.apply { intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK }
|
||||
.launchUrl(context, this.toUri())
|
||||
}
|
||||
|
||||
private fun String.launchWithIntent() {
|
||||
val context: Context by inject()
|
||||
|
||||
Intent(Intent.ACTION_VIEW)
|
||||
.apply {
|
||||
data = toUri()
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
.startActivity(context)
|
||||
}
|
||||
Reference in New Issue
Block a user