From ff3d66a661a00dffc5879c9a67ef080f6ceb483d Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 13 Dec 2018 04:35:50 -0500 Subject: [PATCH] Separate backend logic from frontend UI --- app/.gitignore | 1 - app/build.gradle | 1 + app/proguard-rules.pro | 9 +- app/src/full/AndroidManifest.xml | 3 - app/src/full/java/a/a.java | 2 +- app/src/full/java/a/g.java | 7 - app/src/full/java/a/q.java | 4 +- .../com/topjohnwu/magisk/AboutActivity.java | 11 +- .../java/com/topjohnwu/magisk/ClassMap.java | 34 ++ .../topjohnwu/magisk/DonationActivity.java | 7 +- .../com/topjohnwu/magisk/FlashActivity.java | 200 +++++++--- .../com/topjohnwu/magisk/MainActivity.java | 16 +- .../com/topjohnwu/magisk/NoUIActivity.java | 13 - .../com/topjohnwu/magisk/SplashActivity.java | 25 +- .../topjohnwu/magisk/SuRequestActivity.java | 10 +- .../magisk/adapters/ApplicationAdapter.java | 6 +- .../magisk/adapters/ModulesAdapter.java | 2 +- .../magisk/adapters/PolicyAdapter.java | 4 +- .../magisk/adapters/ReposAdapter.java | 10 +- .../magisk/adapters/SuLogAdapter.java | 4 +- .../com/topjohnwu/magisk/asyncs/FlashZip.java | 104 ----- .../magisk/asyncs/InstallMagisk.java | 354 ------------------ .../magisk/components/BaseActivity.java | 46 ++- .../magisk/components/BaseFragment.java | 9 +- .../magisk/components/EnvFixDialog.java | 27 +- .../components/InstallMethodDialog.java | 20 +- .../components/MagiskInstallDialog.java | 30 +- .../components/ManagerInstallDialog.java | 21 +- .../MarkDownWindow.java | 20 +- .../magisk/components/Notifications.java | 59 +-- .../components/ProgressNotification.java | 14 +- .../magisk/components/SnackbarMaker.java | 2 +- .../magisk/components/UninstallDialog.java | 9 +- .../magisk/fragments/MagiskFragment.java | 22 +- .../magisk/fragments/MagiskHideFragment.java | 2 +- .../magisk/fragments/MagiskLogFragment.java | 4 +- .../magisk/fragments/ModulesFragment.java | 12 +- .../magisk/fragments/ReposFragment.java | 18 +- .../magisk/fragments/SettingsFragment.java | 60 +-- .../magisk/fragments/SuLogFragment.java | 4 +- .../magisk/fragments/SuperuserFragment.java | 6 +- .../magisk/receivers/GeneralReceiver.java | 25 +- .../magisk/receivers/ShortcutReceiver.java | 50 +-- .../magisk/services/OnBootService.java | 6 +- .../magisk/services/UpdateCheckService.java | 14 +- .../com/topjohnwu/magisk/utils/AppUtils.java | 50 +++ ...DlInstallManager.java => DownloadApp.java} | 28 +- .../{asyncs => utils}/DownloadModule.java | 20 +- .../magisk/utils/FingerprintHelper.java | 18 +- .../magisk/{asyncs => utils}/PatchAPK.java | 26 +- .../topjohnwu/magisk/utils/SuConnector.java | 25 +- .../com/topjohnwu/magisk/utils/Download.java | 6 - build.py | 2 +- core/.gitignore | 2 + core/build.gradle | 33 ++ core/proguard-rules.pro | 21 ++ core/src/main/AndroidManifest.xml | 2 + .../src/main/java/com/topjohnwu/core/App.java | 29 +- .../main/java/com/topjohnwu/core}/Const.java | 4 +- .../main/java/com/topjohnwu/core}/Data.java | 68 +--- .../topjohnwu/core}/container/BaseModule.java | 2 +- .../com/topjohnwu/core}/container/Module.java | 2 +- .../com/topjohnwu/core}/container/Policy.java | 4 +- .../com/topjohnwu/core}/container/Repo.java | 11 +- .../topjohnwu/core}/container/SuLogEntry.java | 4 +- .../topjohnwu/core}/container/TarEntry.java | 2 +- .../core}/container/ValueSortedMap.java | 2 +- .../topjohnwu/core}/database/MagiskDB.java | 16 +- .../core}/database/RepoDatabaseHelper.java | 29 +- .../topjohnwu/core/tasks}/CheckUpdates.java | 24 +- .../com/topjohnwu/core/tasks/FlashZip.java | 83 ++++ .../topjohnwu/core/tasks/MagiskInstaller.java | 288 ++++++++++++++ .../topjohnwu/core/tasks}/ParallelTask.java | 2 +- .../com/topjohnwu/core/tasks}/SafetyNet.java | 12 +- .../topjohnwu/core/tasks}/UpdateRepos.java | 41 +- .../com/topjohnwu/core}/utils/BootSigner.java | 2 +- .../core}/utils/ISafetyNetHelper.java | 2 +- .../topjohnwu/core}/utils/LocaleManager.java | 22 +- .../com/topjohnwu/core}/utils/Logger.java | 6 +- .../com/topjohnwu/core}/utils/RootUtils.java | 8 +- .../java/com/topjohnwu/core}/utils/Topic.java | 6 +- .../java/com/topjohnwu/core}/utils/Utils.java | 113 ++---- .../com/topjohnwu/core}/utils/ZipUtils.java | 2 +- .../full => core/src/main}/res/raw/bootctl | Bin .../src/main}/res/raw/nonroot_utils.sh | 0 .../full => core/src/main}/res/raw/utils.sh | 6 +- settings.gradle | 2 +- 87 files changed, 1194 insertions(+), 1138 deletions(-) delete mode 100644 app/src/full/java/a/g.java create mode 100644 app/src/full/java/com/topjohnwu/magisk/ClassMap.java delete mode 100644 app/src/full/java/com/topjohnwu/magisk/NoUIActivity.java delete mode 100644 app/src/full/java/com/topjohnwu/magisk/asyncs/FlashZip.java delete mode 100644 app/src/full/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java rename app/src/full/java/com/topjohnwu/magisk/{asyncs => components}/MarkDownWindow.java (83%) create mode 100644 app/src/full/java/com/topjohnwu/magisk/utils/AppUtils.java rename app/src/full/java/com/topjohnwu/magisk/utils/{DlInstallManager.java => DownloadApp.java} (79%) rename app/src/full/java/com/topjohnwu/magisk/{asyncs => utils}/DownloadModule.java (80%) rename app/src/full/java/com/topjohnwu/magisk/{asyncs => utils}/PatchAPK.java (89%) create mode 100644 core/.gitignore create mode 100644 core/build.gradle create mode 100644 core/proguard-rules.pro create mode 100644 core/src/main/AndroidManifest.xml rename app/src/full/java/com/topjohnwu/magisk/MagiskManager.java => core/src/main/java/com/topjohnwu/core/App.java (67%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/Const.java (99%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/Data.java (70%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/container/BaseModule.java (98%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/container/Module.java (97%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/container/Policy.java (96%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/container/Repo.java (87%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/container/SuLogEntry.java (95%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/container/TarEntry.java (98%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/container/ValueSortedMap.java (95%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/database/MagiskDB.java (94%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/database/RepoDatabaseHelper.java (84%) rename {app/src/full/java/com/topjohnwu/magisk/asyncs => core/src/main/java/com/topjohnwu/core/tasks}/CheckUpdates.java (81%) create mode 100644 core/src/main/java/com/topjohnwu/core/tasks/FlashZip.java create mode 100644 core/src/main/java/com/topjohnwu/core/tasks/MagiskInstaller.java rename {app/src/full/java/com/topjohnwu/magisk/asyncs => core/src/main/java/com/topjohnwu/core/tasks}/ParallelTask.java (94%) rename {app/src/full/java/com/topjohnwu/magisk/asyncs => core/src/main/java/com/topjohnwu/core/tasks}/SafetyNet.java (85%) rename {app/src/full/java/com/topjohnwu/magisk/asyncs => core/src/main/java/com/topjohnwu/core/tasks}/UpdateRepos.java (82%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/utils/BootSigner.java (97%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/utils/ISafetyNetHelper.java (88%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/utils/LocaleManager.java (77%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/utils/Logger.java (81%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/utils/RootUtils.java (91%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/utils/Topic.java (95%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/utils/Utils.java (59%) rename {app/src/full/java/com/topjohnwu/magisk => core/src/main/java/com/topjohnwu/core}/utils/ZipUtils.java (98%) rename {app/src/full => core/src/main}/res/raw/bootctl (100%) rename {app/src/full => core/src/main}/res/raw/nonroot_utils.sh (100%) rename {app/src/full => core/src/main}/res/raw/utils.sh (90%) diff --git a/app/.gitignore b/app/.gitignore index 0c1a13c1e..88ab538f6 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -6,7 +6,6 @@ app/release *.hprof .externalNativeBuild/ -src/full/res/raw/util_functions.sh public.certificate.x509.pem private.key.pk8 *.apk diff --git a/app/build.gradle b/app/build.gradle index 0a9bf4a5f..8420fbaf1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -73,6 +73,7 @@ dependencies { implementation 'androidx.core:core:1.0.1' implementation project(':net') fullImplementation project(':utils') + fullImplementation project(':core') fullImplementation 'androidx.appcompat:appcompat:1.0.2' fullImplementation "androidx.preference:preference:${rootProject.ext.androidXVersion}" fullImplementation "androidx.recyclerview:recyclerview:${rootProject.ext.androidXVersion}" diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 6fcb0576d..7b07f3baa 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -23,14 +23,11 @@ -dontwarn javax.naming.** # Snet extention --keepclassmembers class com.topjohnwu.magisk.utils.ISafetyNetHelper { *; } --keepclassmembers class com.topjohnwu.magisk.utils.BootSigner { *; } - -# Fast Android Networking Library --dontwarn okhttp3.** +-keepclassmembers class com.topjohnwu.core.utils.ISafetyNetHelper { *; } +-keepclassmembers class com.topjohnwu.core.utils.BootSigner { *; } # Strip logging --assumenosideeffects class com.topjohnwu.magisk.utils.Logger { +-assumenosideeffects class com.topjohnwu.core.utils.Logger { public *** debug(...); } diff --git a/app/src/full/AndroidManifest.xml b/app/src/full/AndroidManifest.xml index b8dd6e416..88133c0e1 100644 --- a/app/src/full/AndroidManifest.xml +++ b/app/src/full/AndroidManifest.xml @@ -40,9 +40,6 @@ android:configChanges="keyboardHidden|orientation|screenSize" android:screenOrientation="nosensor" android:theme="@style/AppTheme.StatusBar" /> - diff --git a/app/src/full/java/a/a.java b/app/src/full/java/a/a.java index f3ebc910e..e2481e07e 100644 --- a/app/src/full/java/a/a.java +++ b/app/src/full/java/a/a.java @@ -1,6 +1,6 @@ package a; -import com.topjohnwu.magisk.utils.BootSigner; +import com.topjohnwu.core.utils.BootSigner; import androidx.annotation.Keep; diff --git a/app/src/full/java/a/g.java b/app/src/full/java/a/g.java deleted file mode 100644 index 1a7300c84..000000000 --- a/app/src/full/java/a/g.java +++ /dev/null @@ -1,7 +0,0 @@ -package a; - -import com.topjohnwu.magisk.NoUIActivity; - -public class g extends NoUIActivity { - /* stub */ -} diff --git a/app/src/full/java/a/q.java b/app/src/full/java/a/q.java index 19dfec84f..e1025ae7c 100644 --- a/app/src/full/java/a/q.java +++ b/app/src/full/java/a/q.java @@ -1,7 +1,7 @@ package a; -import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.core.App; -public class q extends MagiskManager { +public class q extends App { /* stub */ } diff --git a/app/src/full/java/com/topjohnwu/magisk/AboutActivity.java b/app/src/full/java/com/topjohnwu/magisk/AboutActivity.java index de6b34aa1..bc079bf0e 100644 --- a/app/src/full/java/com/topjohnwu/magisk/AboutActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/AboutActivity.java @@ -5,10 +5,11 @@ import android.os.Bundle; import android.text.TextUtils; import android.view.View; -import com.topjohnwu.magisk.asyncs.MarkDownWindow; +import com.topjohnwu.core.Const; import com.topjohnwu.magisk.components.AboutCardRow; import com.topjohnwu.magisk.components.BaseActivity; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.components.MarkDownWindow; +import com.topjohnwu.magisk.utils.AppUtils; import java.util.Locale; @@ -62,9 +63,9 @@ public class AboutActivity extends BaseActivity { appTranslators.setSummary(translators); } - appSourceCode.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.SOURCE_CODE_URL))); - supportThread.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.XDA_THREAD))); - twitter.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.TWITTER_URL))); + appSourceCode.setOnClickListener(v -> AppUtils.openLink(this, Uri.parse(Const.Url.SOURCE_CODE_URL))); + supportThread.setOnClickListener(v -> AppUtils.openLink(this, Uri.parse(Const.Url.XDA_THREAD))); + twitter.setOnClickListener(v -> AppUtils.openLink(this, Uri.parse(Const.Url.TWITTER_URL))); setFloating(); } diff --git a/app/src/full/java/com/topjohnwu/magisk/ClassMap.java b/app/src/full/java/com/topjohnwu/magisk/ClassMap.java new file mode 100644 index 000000000..580f2af63 --- /dev/null +++ b/app/src/full/java/com/topjohnwu/magisk/ClassMap.java @@ -0,0 +1,34 @@ +package com.topjohnwu.magisk; + +import com.topjohnwu.core.App; +import com.topjohnwu.magisk.components.AboutCardRow; +import com.topjohnwu.magisk.receivers.GeneralReceiver; +import com.topjohnwu.magisk.receivers.ShortcutReceiver; +import com.topjohnwu.magisk.services.OnBootService; +import com.topjohnwu.magisk.services.UpdateCheckService; + +import java.util.HashMap; +import java.util.Map; + +public class ClassMap { + private static Map classMap = new HashMap<>(); + + static { + classMap.put(App.class, a.q.class); + classMap.put(MainActivity.class, a.b.class); + classMap.put(SplashActivity.class, a.c.class); + classMap.put(AboutActivity.class, a.d.class); + classMap.put(DonationActivity.class, a.e.class); + classMap.put(FlashActivity.class, a.f.class); + classMap.put(GeneralReceiver.class, a.h.class); + classMap.put(ShortcutReceiver.class, a.i.class); + classMap.put(OnBootService.class, a.j.class); + classMap.put(UpdateCheckService.class, a.k.class); + classMap.put(AboutCardRow.class, a.l.class); + classMap.put(SuRequestActivity.class, a.m.class); + } + + public static Class get(Class c) { + return classMap.get(c); + } +} diff --git a/app/src/full/java/com/topjohnwu/magisk/DonationActivity.java b/app/src/full/java/com/topjohnwu/magisk/DonationActivity.java index 254ee6c9b..d26316850 100644 --- a/app/src/full/java/com/topjohnwu/magisk/DonationActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/DonationActivity.java @@ -3,9 +3,10 @@ package com.topjohnwu.magisk; import android.net.Uri; import android.os.Bundle; +import com.topjohnwu.core.Const; import com.topjohnwu.magisk.components.AboutCardRow; import com.topjohnwu.magisk.components.BaseActivity; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.AppUtils; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; @@ -38,7 +39,7 @@ public class DonationActivity extends BaseActivity { ab.setDisplayHomeAsUpEnabled(true); } - paypal.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.PAYPAL_URL))); - patreon.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.PATREON_URL))); + paypal.setOnClickListener(v -> AppUtils.openLink(this, Uri.parse(Const.Url.PAYPAL_URL))); + patreon.setOnClickListener(v -> AppUtils.openLink(this, Uri.parse(Const.Url.PATREON_URL))); } } diff --git a/app/src/full/java/com/topjohnwu/magisk/FlashActivity.java b/app/src/full/java/com/topjohnwu/magisk/FlashActivity.java index 0911572ea..d5db8075e 100644 --- a/app/src/full/java/com/topjohnwu/magisk/FlashActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/FlashActivity.java @@ -1,6 +1,5 @@ package com.topjohnwu.magisk; -import android.Manifest; import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -12,18 +11,22 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; -import com.topjohnwu.magisk.asyncs.FlashZip; -import com.topjohnwu.magisk.asyncs.InstallMagisk; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.tasks.FlashZip; +import com.topjohnwu.core.tasks.MagiskInstaller; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.components.BaseActivity; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.CallbackList; import com.topjohnwu.superuser.Shell; +import com.topjohnwu.superuser.ShellUtils; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.List; import java.util.Locale; @@ -40,7 +43,7 @@ public class FlashActivity extends BaseActivity { @BindView(R.id.reboot) public Button reboot; @BindView(R.id.scrollView) ScrollView sv; - private List logs; + private List console, logs; @OnClick(R.id.reboot) void reboot() { @@ -49,7 +52,7 @@ public class FlashActivity extends BaseActivity { @OnClick(R.id.save_logs) void saveLogs() { - runWithPermission(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, () -> { + runWithExternalRW(() -> { Calendar now = Calendar.getInstance(); String filename = String.format(Locale.US, "magisk_install_log_%04d%02d%02d_%02d%02d%02d.log", @@ -71,6 +74,17 @@ public class FlashActivity extends BaseActivity { }); } + @OnClick(R.id.close) + @Override + public void finish() { + super.finish(); + } + + @Override + public void onBackPressed() { + // Prevent user accidentally press back button + } + @Override public int getDarkTheme() { return R.style.AppTheme_StatusBar_Dark; @@ -92,77 +106,155 @@ public class FlashActivity extends BaseActivity { if (!Shell.rootAccess()) reboot.setVisibility(View.GONE); - logs = new ArrayList<>(); - CallbackList console = new CallbackList(new ArrayList<>()) { + logs = Collections.synchronizedList(new ArrayList<>()); + console = new ConsoleList(); - private void updateUI() { - flashLogs.setText(TextUtils.join("\n", this)); - sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10); - } - - @Override - public void onAddElement(String s) { - logs.add(s); - updateUI(); - } - - @Override - public String set(int i, String s) { - String ret = super.set(i, s); - Data.mainHandler.post(this::updateUI); - return ret; - } - }; - - // We must receive a Uri of the target zip Intent intent = getIntent(); Uri uri = intent.getData(); switch (intent.getStringExtra(Const.Key.FLASH_ACTION)) { case Const.Value.FLASH_ZIP: - new FlashZip(this, uri, console, logs).exec(); + new FlashModule(uri).exec(); break; case Const.Value.UNINSTALL: - new UninstallMagisk(this, uri, console, logs).exec(); + new Uninstall(uri).exec(); break; case Const.Value.FLASH_MAGISK: - new InstallMagisk(this, console, logs, InstallMagisk.DIRECT_MODE).exec(); + new DirectInstall().exec(); break; case Const.Value.FLASH_INACTIVE_SLOT: - new InstallMagisk(this, console, logs, InstallMagisk.SECOND_SLOT_MODE).exec(); + new SecondSlot().exec(); break; case Const.Value.PATCH_BOOT: - new InstallMagisk(this, console, logs, - intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT)).exec(); + new PatchBoot(uri).exec(); break; } } - @OnClick(R.id.close) - @Override - public void finish() { - super.finish(); - } + private class ConsoleList extends CallbackList { - @Override - public void onBackPressed() { - // Prevent user accidentally press back button - } + ConsoleList() { + super(new ArrayList<>()); + } - private static class UninstallMagisk extends FlashZip { - - private UninstallMagisk(BaseActivity context, Uri uri, List console, List logs) { - super(context, uri, console, logs); + private void updateUI() { + flashLogs.setText(TextUtils.join("\n", this)); + sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10); } @Override - protected void onPostExecute(Integer result) { - if (result == 1) { - Data.mainHandler.postDelayed(() -> - Shell.su("pm uninstall " + getActivity().getPackageName()).exec(), 3000); - } else { - super.onPostExecute(result); - } + public void onAddElement(String s) { + logs.add(s); + updateUI(); + } + + @Override + public String set(int i, String s) { + String ret = super.set(i, s); + App.mainHandler.post(this::updateUI); + return ret; } } + + private class FlashModule extends FlashZip { + + FlashModule(Uri uri) { + super(uri, console, logs); + } + + @Override + protected void onResult(boolean success) { + if (success) { + Utils.loadModules(); + } else { + console.add("! Installation failed"); + reboot.setVisibility(View.GONE); + } + buttonPanel.setVisibility(View.VISIBLE); + } + } + + private class Uninstall extends FlashModule { + + Uninstall(Uri uri) { + super(uri); + } + + @Override + protected void onResult(boolean success) { + if (success) + App.mainHandler.postDelayed(Shell.su("pm uninstall " + getPackageName())::exec, 3000); + else + super.onResult(false); + } + } + + private abstract class BaseInstaller extends MagiskInstaller { + BaseInstaller() { + super(console, logs); + } + + @Override + protected void onResult(boolean success) { + if (success) { + console.add("- All done!"); + } else { + Shell.sh("rm -rf " + installDir).submit(); + console.add("! Installation failed"); + reboot.setVisibility(View.GONE); + } + buttonPanel.setVisibility(View.VISIBLE); + } + } + + private class DirectInstall extends BaseInstaller { + + @Override + protected boolean operations() { + console.add("- Detecting target image"); + srcBoot = ShellUtils.fastCmd("find_boot_image", "echo \"$BOOTIMAGE\""); + if (srcBoot.isEmpty()) { + console.add("! Unable to detect target image"); + return false; + } + return extractZip() && patchBoot() && flashBoot(); + } + } + + private class SecondSlot extends BaseInstaller { + + @Override + protected boolean operations() { + String slot = ShellUtils.fastCmd("echo $SLOT"); + String target = (TextUtils.equals(slot, "_a") ? "_b" : "_a"); + console.add("- Target slot: " + target); + console.add("- Detecting target image"); + srcBoot = ShellUtils.fastCmd( + "SLOT=" + target, + "find_boot_image", + "SLOT=" + slot, + "echo \"$BOOTIMAGE\"" + ); + if (srcBoot.isEmpty()) { + console.add("! Unable to detect target image"); + return false; + } + return extractZip() && patchBoot() && flashBoot() && postOTA(); + } + } + + private class PatchBoot extends BaseInstaller { + + private Uri uri; + + PatchBoot(Uri u) { + uri = u; + } + + @Override + protected boolean operations() { + return copyBoot(uri) && extractZip() && patchBoot() && storeBoot(); + } + } + } diff --git a/app/src/full/java/com/topjohnwu/magisk/MainActivity.java b/app/src/full/java/com/topjohnwu/magisk/MainActivity.java index 8ffff2fb0..344eb0f37 100644 --- a/app/src/full/java/com/topjohnwu/magisk/MainActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/MainActivity.java @@ -8,6 +8,10 @@ import android.view.MenuItem; import android.view.View; import com.google.android.material.navigation.NavigationView; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.Topic; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.components.BaseActivity; import com.topjohnwu.magisk.fragments.LogFragment; import com.topjohnwu.magisk.fragments.MagiskFragment; @@ -17,8 +21,6 @@ import com.topjohnwu.magisk.fragments.ReposFragment; import com.topjohnwu.magisk.fragments.SettingsFragment; import com.topjohnwu.magisk.fragments.SuperuserFragment; import com.topjohnwu.magisk.utils.Download; -import com.topjohnwu.magisk.utils.Topic; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.Shell; import androidx.annotation.NonNull; @@ -49,8 +51,8 @@ public class MainActivity extends BaseActivity @Override protected void onCreate(final Bundle savedInstanceState) { - if (!mm.hasInit) { - startActivity(new Intent(this, Data.classMap.get(SplashActivity.class))); + if (!app.init) { + startActivity(new Intent(this, ClassMap.get(SplashActivity.class))); finish(); } @@ -120,7 +122,7 @@ public class MainActivity extends BaseActivity public void checkHideSection() { Menu menu = navigationView.getMenu(); menu.findItem(R.id.magiskhide).setVisible(Shell.rootAccess() && - mm.prefs.getBoolean(Const.Key.MAGISKHIDE, false)); + app.prefs.getBoolean(Const.Key.MAGISKHIDE, false)); menu.findItem(R.id.modules).setVisible(Shell.rootAccess() && Data.magiskVersionCode >= 0); menu.findItem(R.id.downloads).setVisible(Download.checkNetworkStatus(this) && Shell.rootAccess() && Data.magiskVersionCode >= 0); @@ -189,11 +191,11 @@ public class MainActivity extends BaseActivity displayFragment(new SettingsFragment(), true); break; case R.id.app_about: - startActivity(new Intent(this, Data.classMap.get(AboutActivity.class))); + startActivity(new Intent(this, ClassMap.get(AboutActivity.class))); mDrawerItem = bak; break; case R.id.donation: - startActivity(new Intent(this, Data.classMap.get(DonationActivity.class))); + startActivity(new Intent(this, ClassMap.get(DonationActivity.class))); mDrawerItem = bak; break; } diff --git a/app/src/full/java/com/topjohnwu/magisk/NoUIActivity.java b/app/src/full/java/com/topjohnwu/magisk/NoUIActivity.java deleted file mode 100644 index a79c15d9f..000000000 --- a/app/src/full/java/com/topjohnwu/magisk/NoUIActivity.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.topjohnwu.magisk; - -import com.topjohnwu.magisk.components.BaseActivity; - -import androidx.annotation.NonNull; - -public class NoUIActivity extends BaseActivity { - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - finish(); - } -} diff --git a/app/src/full/java/com/topjohnwu/magisk/SplashActivity.java b/app/src/full/java/com/topjohnwu/magisk/SplashActivity.java index 43a97a608..d06f61d89 100644 --- a/app/src/full/java/com/topjohnwu/magisk/SplashActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/SplashActivity.java @@ -5,14 +5,17 @@ import android.content.pm.PackageManager; import android.os.Bundle; import android.text.TextUtils; -import com.topjohnwu.magisk.asyncs.CheckUpdates; -import com.topjohnwu.magisk.asyncs.UpdateRepos; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.tasks.CheckUpdates; +import com.topjohnwu.core.tasks.UpdateRepos; +import com.topjohnwu.core.utils.LocaleManager; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.components.BaseActivity; import com.topjohnwu.magisk.components.Notifications; import com.topjohnwu.magisk.receivers.ShortcutReceiver; +import com.topjohnwu.magisk.utils.AppUtils; import com.topjohnwu.magisk.utils.Download; -import com.topjohnwu.magisk.utils.LocaleManager; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.Shell; public class SplashActivity extends BaseActivity { @@ -21,9 +24,9 @@ public class SplashActivity extends BaseActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - String pkg = mm.mDB.getStrings(Const.Key.SU_MANAGER, null); + String pkg = app.mDB.getStrings(Const.Key.SU_MANAGER, null); if (pkg != null && getPackageName().equals(BuildConfig.APPLICATION_ID)) { - mm.mDB.setStrings(Const.Key.SU_MANAGER, null); + app.mDB.setStrings(Const.Key.SU_MANAGER, null); Shell.su("pm uninstall " + pkg).exec(); } if (TextUtils.equals(pkg, getPackageName())) { @@ -37,7 +40,7 @@ public class SplashActivity extends BaseActivity { // Magisk working as expected if (Shell.rootAccess() && Data.magiskVersionCode > 0) { // Update check service - Utils.setupUpdateCheck(); + AppUtils.setupUpdateCheck(); // Load modules Utils.loadModules(); } @@ -45,13 +48,13 @@ public class SplashActivity extends BaseActivity { Data.importPrefs(); // Dynamic detect all locales - LocaleManager.loadAvailableLocales(); + LocaleManager.loadAvailableLocales(R.string.download_file_error); // Create notification channel on Android O Notifications.setup(this); // Setup shortcuts - sendBroadcast(new Intent(this, Data.classMap.get(ShortcutReceiver.class))); + sendBroadcast(new Intent(this, ClassMap.get(ShortcutReceiver.class))); if (Download.checkNetworkStatus(this)) { // Fire update check @@ -63,9 +66,9 @@ public class SplashActivity extends BaseActivity { // Write back default values Data.writeConfig(); - mm.hasInit = true; + app.init = true; - Intent intent = new Intent(this, Data.classMap.get(MainActivity.class)); + Intent intent = new Intent(this, ClassMap.get(MainActivity.class)); intent.putExtra(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION)); intent.putExtra(BaseActivity.INTENT_PERM, getIntent().getStringExtra(BaseActivity.INTENT_PERM)); startActivity(intent); diff --git a/app/src/full/java/com/topjohnwu/magisk/SuRequestActivity.java b/app/src/full/java/com/topjohnwu/magisk/SuRequestActivity.java index ed28b0987..e6f4bb699 100644 --- a/app/src/full/java/com/topjohnwu/magisk/SuRequestActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/SuRequestActivity.java @@ -15,8 +15,10 @@ import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.container.Policy; import com.topjohnwu.magisk.components.BaseActivity; -import com.topjohnwu.magisk.container.Policy; import com.topjohnwu.magisk.utils.FingerprintHelper; import com.topjohnwu.magisk.utils.SuConnector; @@ -70,7 +72,7 @@ public class SuRequestActivity extends BaseActivity { supportRequestWindowFeature(Window.FEATURE_NO_TITLE); PackageManager pm = getPackageManager(); - mm.mDB.clearOutdated(); + app.mDB.clearOutdated(); // Get policy Intent intent = getIntent(); @@ -84,7 +86,7 @@ public class SuRequestActivity extends BaseActivity { }; Bundle bundle = connector.readSocketInput(); int uid = Integer.parseInt(bundle.getString("uid")); - policy = mm.mDB.getPolicy(uid); + policy = app.mDB.getPolicy(uid); if (policy == null) { policy = new Policy(uid, pm); } @@ -212,7 +214,7 @@ public class SuRequestActivity extends BaseActivity { policy.policy = action; if (time >= 0) { policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60); - mm.mDB.updatePolicy(policy); + app.mDB.updatePolicy(policy); } handleAction(); } diff --git a/app/src/full/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java b/app/src/full/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java index 65c860dd4..b7f3b3b5e 100644 --- a/app/src/full/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java +++ b/app/src/full/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java @@ -13,10 +13,10 @@ import android.widget.Filter; import android.widget.ImageView; import android.widget.TextView; -import com.topjohnwu.magisk.Const; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.utils.Topic; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Topic; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.Shell; import java.util.ArrayList; diff --git a/app/src/full/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java b/app/src/full/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java index 662ef0cd7..d46fe2171 100644 --- a/app/src/full/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java +++ b/app/src/full/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java @@ -10,9 +10,9 @@ import android.widget.ImageView; import android.widget.TextView; import com.google.android.material.snackbar.Snackbar; +import com.topjohnwu.core.container.Module; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.components.SnackbarMaker; -import com.topjohnwu.magisk.container.Module; import com.topjohnwu.superuser.Shell; import java.util.List; diff --git a/app/src/full/java/com/topjohnwu/magisk/adapters/PolicyAdapter.java b/app/src/full/java/com/topjohnwu/magisk/adapters/PolicyAdapter.java index cd430aa77..c9bf2434d 100644 --- a/app/src/full/java/com/topjohnwu/magisk/adapters/PolicyAdapter.java +++ b/app/src/full/java/com/topjohnwu/magisk/adapters/PolicyAdapter.java @@ -10,12 +10,12 @@ import android.widget.Switch; import android.widget.TextView; import com.google.android.material.snackbar.Snackbar; +import com.topjohnwu.core.container.Policy; +import com.topjohnwu.core.database.MagiskDB; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.components.CustomAlertDialog; import com.topjohnwu.magisk.components.ExpandableView; import com.topjohnwu.magisk.components.SnackbarMaker; -import com.topjohnwu.magisk.container.Policy; -import com.topjohnwu.magisk.database.MagiskDB; import com.topjohnwu.magisk.utils.FingerprintHelper; import java.util.HashSet; diff --git a/app/src/full/java/com/topjohnwu/magisk/adapters/ReposAdapter.java b/app/src/full/java/com/topjohnwu/magisk/adapters/ReposAdapter.java index a72e12184..157d9098a 100644 --- a/app/src/full/java/com/topjohnwu/magisk/adapters/ReposAdapter.java +++ b/app/src/full/java/com/topjohnwu/magisk/adapters/ReposAdapter.java @@ -11,14 +11,14 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import com.topjohnwu.core.container.Module; +import com.topjohnwu.core.container.Repo; +import com.topjohnwu.core.database.RepoDatabaseHelper; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.asyncs.DownloadModule; -import com.topjohnwu.magisk.asyncs.MarkDownWindow; import com.topjohnwu.magisk.components.BaseActivity; import com.topjohnwu.magisk.components.CustomAlertDialog; -import com.topjohnwu.magisk.container.Module; -import com.topjohnwu.magisk.container.Repo; -import com.topjohnwu.magisk.database.RepoDatabaseHelper; +import com.topjohnwu.magisk.components.MarkDownWindow; +import com.topjohnwu.magisk.utils.DownloadModule; import java.util.ArrayList; import java.util.List; diff --git a/app/src/full/java/com/topjohnwu/magisk/adapters/SuLogAdapter.java b/app/src/full/java/com/topjohnwu/magisk/adapters/SuLogAdapter.java index 0d6a0568a..5fbcd4e5f 100644 --- a/app/src/full/java/com/topjohnwu/magisk/adapters/SuLogAdapter.java +++ b/app/src/full/java/com/topjohnwu/magisk/adapters/SuLogAdapter.java @@ -8,10 +8,10 @@ import android.view.animation.RotateAnimation; import android.widget.ImageView; import android.widget.TextView; +import com.topjohnwu.core.container.SuLogEntry; +import com.topjohnwu.core.database.MagiskDB; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.components.ExpandableView; -import com.topjohnwu.magisk.container.SuLogEntry; -import com.topjohnwu.magisk.database.MagiskDB; import java.util.Collections; import java.util.HashSet; diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/FlashZip.java b/app/src/full/java/com/topjohnwu/magisk/asyncs/FlashZip.java deleted file mode 100644 index f14a520cd..000000000 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/FlashZip.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.topjohnwu.magisk.asyncs; - -import android.app.Activity; -import android.net.Uri; -import android.view.View; - -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.FlashActivity; -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.components.SnackbarMaker; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.utils.ZipUtils; -import com.topjohnwu.superuser.Shell; -import com.topjohnwu.superuser.ShellUtils; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.List; - -public class FlashZip extends ParallelTask { - - private Uri mUri; - private File mCachedFile; - private List console, logs; - - public FlashZip(Activity context, Uri uri, List console, List logs) { - super(context); - mUri = uri; - this.console = console; - this.logs = logs; - mCachedFile = new File(context.getCacheDir(), "install.zip"); - } - - private boolean unzipAndCheck() throws Exception { - ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", true); - return ShellUtils.fastCmdResult("grep -q '#MAGISK' " + new File(mCachedFile.getParentFile(), "updater-script")); - } - - @Override - protected Integer doInBackground(Void... voids) { - MagiskManager mm = Data.MM(); - try { - console.add("- Copying zip to temp directory"); - - mCachedFile.delete(); - try ( - InputStream in = mm.getContentResolver().openInputStream(mUri); - OutputStream out = new BufferedOutputStream(new FileOutputStream(mCachedFile)) - ) { - if (in == null) throw new FileNotFoundException(); - InputStream buf= new BufferedInputStream(in); - ShellUtils.pump(buf, out); - } catch (FileNotFoundException e) { - console.add("! Invalid Uri"); - throw e; - } catch (IOException e) { - console.add("! Cannot copy to cache"); - throw e; - } - if (!unzipAndCheck()) return 0; - console.add("- Installing " + Utils.getNameFromUri(mm, mUri)); - if (!Shell.su("cd " + mCachedFile.getParent(), - "BOOTMODE=true sh update-binary dummy 1 " + mCachedFile) - .to(console, logs) - .exec().isSuccess()) - return -1; - - } catch (Exception e) { - e.printStackTrace(); - return -1; - } - console.add("- All done!"); - return 1; - } - - // -1 = error, manual install; 0 = invalid zip; 1 = success - @Override - protected void onPostExecute(Integer result) { - FlashActivity activity = (FlashActivity) getActivity(); - Shell.su("rm -rf " + mCachedFile.getParent(), "rm -rf " + Const.TMP_FOLDER_PATH).submit(); - switch (result) { - case -1: - console.add("! Installation failed"); - SnackbarMaker.showUri(getActivity(), mUri); - break; - case 0: - console.add("! This zip is not a Magisk Module!"); - break; - case 1: - // Reload modules - Utils.loadModules(); - break; - } - activity.reboot.setVisibility(result > 0 ? View.VISIBLE : View.GONE); - activity.buttonPanel.setVisibility(View.VISIBLE); - } -} diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java b/app/src/full/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java deleted file mode 100644 index 103ea6eb4..000000000 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java +++ /dev/null @@ -1,354 +0,0 @@ -package com.topjohnwu.magisk.asyncs; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.net.Uri; -import android.os.Build; -import android.text.TextUtils; -import android.view.View; -import android.widget.Toast; - -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.FlashActivity; -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.container.TarEntry; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.utils.ZipUtils; -import com.topjohnwu.net.DownloadProgressListener; -import com.topjohnwu.net.Networking; -import com.topjohnwu.superuser.Shell; -import com.topjohnwu.superuser.ShellUtils; -import com.topjohnwu.superuser.internal.NOPList; -import com.topjohnwu.superuser.io.SuFile; -import com.topjohnwu.superuser.io.SuFileInputStream; -import com.topjohnwu.superuser.io.SuFileOutputStream; -import com.topjohnwu.utils.SignBoot; - -import org.kamranzafar.jtar.TarInputStream; -import org.kamranzafar.jtar.TarOutputStream; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Arrays; -import java.util.List; - -public class InstallMagisk extends ParallelTask { - - private static final int PATCH_MODE = 0; - public static final int DIRECT_MODE = 1; - private static final int FIX_ENV_MODE = 2; - public static final int SECOND_SLOT_MODE = 3; - - private Uri bootUri; - private List console, logs; - private String mBoot; - private int mode; - private File installDir; - private ProgressDialog dialog; - private MagiskManager mm; - - public InstallMagisk(Activity context) { - super(context); - mm = Data.MM(); - mode = FIX_ENV_MODE; - } - - public InstallMagisk(Activity context, List console, List logs, int mode) { - this(context); - this.console = console; - this.logs = logs; - this.mode = mode; - } - - public InstallMagisk(FlashActivity context, List console, List logs, Uri boot) { - this(context, console, logs, PATCH_MODE); - bootUri = boot; - } - - @Override - protected void onPreExecute() { - if (mode == FIX_ENV_MODE) { - Activity a = getActivity(); - dialog = ProgressDialog.show(a, a.getString(R.string.setup_title), a.getString(R.string.setup_msg)); - console = NOPList.getInstance(); - } - } - - class ProgressLog implements DownloadProgressListener { - - private int prev = -1; - private int location; - - @Override - public void onProgress(long bytesDownloaded, long totalBytes) { - if (prev < 0) { - location = console.size(); - console.add("... 0%"); - } - int curr = (int) (100 * bytesDownloaded / totalBytes); - if (prev != curr) { - prev = curr; - console.set(location, "... " + prev + "%"); - } - } - } - - private void extractFiles(String arch) throws IOException { - File zip = new File(mm.getFilesDir(), "magisk.zip"); - - if (!ShellUtils.checkSum("MD5", zip, Data.magiskMD5)) { - console.add("- Downloading zip"); - Networking.get(Data.magiskLink) - .setDownloadProgressListener(new ProgressLog()) - .execForFile(zip); - } else { - console.add("- Existing zip found"); - } - - BufferedInputStream buf = new BufferedInputStream(new FileInputStream(zip), (int) zip.length()); - buf.mark((int) zip.length() + 1); - - console.add("- Extracting files"); - try (InputStream in = buf) { - ZipUtils.unzip(in, installDir, arch + "/", true); - in.reset(); - ZipUtils.unzip(in, installDir, "common/", true); - in.reset(); - ZipUtils.unzip(in, installDir, "chromeos/", false); - in.reset(); - ZipUtils.unzip(in, installDir, "META-INF/com/google/android/update-binary", true); - } catch (IOException e) { - console.add("! Cannot unzip zip"); - throw e; - } - Shell.sh(Utils.fmt("chmod -R 755 %s/*; %s/magiskinit -x magisk %s/magisk", - installDir, installDir, installDir)).exec(); - } - - private boolean dumpBoot() { - console.add("- Copying image to cache"); - // Copy boot image to local - try (InputStream in = mm.getContentResolver().openInputStream(bootUri); - OutputStream out = new FileOutputStream(mBoot) - ) { - if (in == null) - throw new FileNotFoundException(); - - InputStream src; - if (Utils.getNameFromUri(mm, bootUri).endsWith(".tar")) { - // Extract boot.img from tar - TarInputStream tar = new TarInputStream(new BufferedInputStream(in)); - org.kamranzafar.jtar.TarEntry entry; - while ((entry = tar.getNextEntry()) != null) { - if (entry.getName().equals("boot.img")) - break; - } - src = tar; - } else { - // Direct copy raw image - src = new BufferedInputStream(in); - } - ShellUtils.pump(src, out); - } catch (FileNotFoundException e) { - console.add("! Invalid Uri"); - return false; - } catch (IOException e) { - console.add("! Copy failed"); - return false; - } - return true; - } - - private File patchBoot() throws IOException { - boolean isSigned; - try (InputStream in = new SuFileInputStream(mBoot)) { - isSigned = SignBoot.verifySignature(in, null); - if (isSigned) { - console.add("- Boot image is signed with AVB 1.0"); - } - } catch (IOException e) { - console.add("! Unable to check signature"); - throw e; - } - - // Patch boot image - if (!Shell.sh("cd " + installDir, Utils.fmt( - "KEEPFORCEENCRYPT=%b KEEPVERITY=%b sh update-binary indep boot_patch.sh %s", - Data.keepEnc, Data.keepVerity, mBoot)) - .to(console, logs).exec().isSuccess()) - return null; - - Shell.Job job = Shell.sh("mv bin/busybox busybox", - "rm -rf magisk.apk bin boot.img update-binary", - "cd /"); - - File patched = new File(installDir, "new-boot.img"); - if (isSigned) { - console.add("- Signing boot image with test keys"); - File signed = new File(installDir, "signed.img"); - try (InputStream in = new SuFileInputStream(patched); - OutputStream out = new BufferedOutputStream(new FileOutputStream(signed)) - ) { - SignBoot.doSignature("/boot", in, out, null, null); - } - job.add("mv -f " + signed + " " + patched); - } - job.exec(); - return patched; - } - - private boolean outputBoot(File patched) throws IOException { - switch (mode) { - case PATCH_MODE: - String fmt = mm.prefs.getString(Const.Key.BOOT_FORMAT, ".img"); - File dest = new File(Const.EXTERNAL_PATH, "patched_boot" + fmt); - dest.getParentFile().mkdirs(); - OutputStream out; - switch (fmt) { - case ".img.tar": - out = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest))); - ((TarOutputStream) out).putNextEntry(new TarEntry(patched, "boot.img")); - break; - default: - case ".img": - out = new BufferedOutputStream(new FileOutputStream(dest)); - break; - } - try (InputStream in = new SuFileInputStream(patched)) { - ShellUtils.pump(in, out); - out.close(); - } - Shell.sh("rm -f " + patched).exec(); - console.add(""); - console.add("****************************"); - console.add(" Patched image is placed in "); - console.add(" " + dest + " "); - console.add("****************************"); - break; - case SECOND_SLOT_MODE: - case DIRECT_MODE: - if (!Shell.su(Utils.fmt("direct_install %s %s", installDir, mBoot)) - .to(console, logs).exec().isSuccess()) - return false; - if (!Data.keepVerity) - Shell.su("find_dtbo_image", "patch_dtbo_image").to(console, logs).exec(); - break; - } - return true; - } - - private void postOTA() { - SuFile bootctl = new SuFile(Const.MAGISK_PATH + "/.core/bootctl"); - try (InputStream in = mm.getResources().openRawResource(R.raw.bootctl); - OutputStream out = new SuFileOutputStream(bootctl)) { - ShellUtils.pump(in, out); - Shell.su("post_ota " + bootctl.getParent()).exec(); - console.add("***************************************"); - console.add(" Next reboot will boot to second slot!"); - console.add("***************************************"); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - protected Boolean doInBackground(Void... voids) { - if (mode == FIX_ENV_MODE) { - installDir = new File("/data/adb/magisk"); - Shell.su("rm -rf /data/adb/magisk/*").exec(); - } else { - installDir = new File( - (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? - mm.createDeviceProtectedStorageContext() : mm) - .getFilesDir().getParent() - , "install"); - Shell.sh("rm -rf " + installDir).exec(); - installDir.mkdirs(); - } - - switch (mode) { - case PATCH_MODE: - mBoot = new File(installDir, "boot.img").getAbsolutePath(); - if (!dumpBoot()) - return false; - break; - case DIRECT_MODE: - console.add("- Detecting target image"); - mBoot = ShellUtils.fastCmd("find_boot_image", "echo \"$BOOTIMAGE\""); - break; - case SECOND_SLOT_MODE: - String slot = ShellUtils.fastCmd("echo $SLOT"); - String target = (TextUtils.equals(slot, "_a") ? "_b" : "_a"); - console.add("- Target slot: " + target); - console.add("- Detecting target image"); - mBoot = ShellUtils.fastCmd( - "SLOT=" + target, - "find_boot_image", - "SLOT=" + slot, - "echo \"$BOOTIMAGE\"" - ); - break; - case FIX_ENV_MODE: - mBoot = ""; - break; - } - if (mBoot == null) { - console.add("! Unable to detect target image"); - return false; - } - - if (mode == DIRECT_MODE || mode == SECOND_SLOT_MODE) - console.add("- Target image: " + mBoot); - - List abis = Arrays.asList(Build.SUPPORTED_ABIS); - String arch = abis.contains("x86") ? "x86" : "arm"; - - console.add("- Device platform: " + Build.SUPPORTED_ABIS[0]); - - try { - extractFiles(arch); - if (mode == FIX_ENV_MODE) { - Shell.su("fix_env").exec(); - } else { - File patched = patchBoot(); - if (patched == null) - return false; - if (!outputBoot(patched)) - return false; - if (mode == SECOND_SLOT_MODE) - postOTA(); - console.add("- All done!"); - } - } catch (Exception e) { - e.printStackTrace(); - return false; - } - return true; - } - - @Override - protected void onPostExecute(Boolean result) { - if (mode == FIX_ENV_MODE) { - dialog.dismiss(); - Utils.toast(result ? R.string.setup_done : R.string.setup_fail, Toast.LENGTH_LONG); - } else { - // Running in FlashActivity - FlashActivity activity = (FlashActivity) getActivity(); - if (!result) { - Shell.sh("rm -rf " + installDir).submit(); - console.add("! Installation failed"); - activity.reboot.setVisibility(View.GONE); - } - activity.buttonPanel.setVisibility(View.VISIBLE); - } - } -} diff --git a/app/src/full/java/com/topjohnwu/magisk/components/BaseActivity.java b/app/src/full/java/com/topjohnwu/magisk/components/BaseActivity.java index 631dbcbd7..85ff2cc25 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/BaseActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/BaseActivity.java @@ -1,5 +1,6 @@ package com.topjohnwu.magisk.components; +import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -8,13 +9,12 @@ import android.os.Bundle; import android.view.WindowManager; import android.widget.Toast; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.NoUIActivity; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.LocaleManager; +import com.topjohnwu.core.utils.Topic; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.LocaleManager; -import com.topjohnwu.magisk.utils.Topic; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -26,12 +26,12 @@ import androidx.core.content.ContextCompat; public abstract class BaseActivity extends AppCompatActivity implements Topic.AutoSubscriber { public static final String INTENT_PERM = "perm_dialog"; + private static Runnable grantCallback; - protected static Runnable permissionGrantCallback; static int[] EMPTY_INT_ARRAY = new int[0]; private ActivityResultListener activityResultListener; - public MagiskManager mm; + public App app; @Override public int[] getSubscribedTopics() { @@ -49,7 +49,7 @@ public abstract class BaseActivity extends AppCompatActivity implements Topic.Au Configuration config = base.getResources().getConfiguration(); config.setLocale(LocaleManager.locale); applyOverrideConfiguration(config); - mm = Data.MM(); + app = App.self; } @Override @@ -84,6 +84,14 @@ public abstract class BaseActivity extends AppCompatActivity implements Topic.Au } } + public void runWithExternalRW(Runnable callback) { + runWithPermission(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, callback); + } + + public void runWithPermission(String[] permissions, Runnable callback) { + runWithPermission(this, permissions, callback); + } + public static void runWithPermission(Context context, String[] permissions, Runnable callback) { boolean granted = true; for (String perm : permissions) { @@ -95,23 +103,13 @@ public abstract class BaseActivity extends AppCompatActivity implements Topic.Au callback.run(); } else { // Passed in context should be an activity if not granted, need to show dialog! - permissionGrantCallback = callback; - if (!(context instanceof BaseActivity)) { - // Start NoUIActivity to show dialog - Intent intent = new Intent(context, Data.classMap.get(NoUIActivity.class)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(INTENT_PERM, permissions); - context.startActivity(intent); - } else { + if (context instanceof BaseActivity) { + grantCallback = callback; ActivityCompat.requestPermissions((BaseActivity) context, permissions, 0); } } } - public void runWithPermission(String[] permissions, Runnable callback) { - runWithPermission(this, permissions, callback); - } - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (activityResultListener != null) @@ -132,13 +130,13 @@ public abstract class BaseActivity extends AppCompatActivity implements Topic.Au grant = false; } if (grant) { - if (permissionGrantCallback != null) { - permissionGrantCallback.run(); + if (grantCallback != null) { + grantCallback.run(); } } else { Toast.makeText(this, R.string.no_rw_storage, Toast.LENGTH_LONG).show(); } - permissionGrantCallback = null; + grantCallback = null; } public interface ActivityResultListener { diff --git a/app/src/full/java/com/topjohnwu/magisk/components/BaseFragment.java b/app/src/full/java/com/topjohnwu/magisk/components/BaseFragment.java index c442fb462..9cd5ae3f7 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/BaseFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/BaseFragment.java @@ -2,20 +2,19 @@ package com.topjohnwu.magisk.components; import android.content.Intent; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.utils.Topic; +import com.topjohnwu.core.App; +import com.topjohnwu.core.utils.Topic; import androidx.fragment.app.Fragment; import butterknife.Unbinder; public class BaseFragment extends Fragment implements Topic.AutoSubscriber { - public MagiskManager mm; + public App app; protected Unbinder unbinder = null; public BaseFragment() { - mm = Data.MM(); + app = App.self; } @Override diff --git a/app/src/full/java/com/topjohnwu/magisk/components/EnvFixDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/EnvFixDialog.java index bb2226583..1696e01f7 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/EnvFixDialog.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/EnvFixDialog.java @@ -1,9 +1,14 @@ package com.topjohnwu.magisk.components; import android.app.Activity; +import android.app.ProgressDialog; +import android.widget.Toast; +import com.topjohnwu.core.tasks.MagiskInstaller; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.asyncs.InstallMagisk; +import com.topjohnwu.superuser.Shell; +import com.topjohnwu.superuser.io.SuFile; import androidx.annotation.NonNull; @@ -14,7 +19,25 @@ public class EnvFixDialog extends CustomAlertDialog { setTitle(R.string.env_fix_title); setMessage(R.string.env_fix_msg); setCancelable(true); - setPositiveButton(R.string.yes, (d, i) -> new InstallMagisk(activity).exec()); + setPositiveButton(R.string.yes, (d, i) -> { + ProgressDialog pd = ProgressDialog.show(activity, + activity.getString(R.string.setup_title), + activity.getString(R.string.setup_msg)); + new MagiskInstaller() { + @Override + protected boolean operations() { + installDir = new SuFile("/data/adb/magisk"); + Shell.su("rm -rf /data/adb/magisk/*").exec(); + return extractZip() && Shell.su("fix_env").exec().isSuccess(); + } + + @Override + protected void onResult(boolean success) { + pd.dismiss(); + Utils.toast(success ? R.string.setup_done : R.string.setup_fail, Toast.LENGTH_LONG); + } + }.exec(); + }); setNegativeButton(R.string.no_thanks, null); } } diff --git a/app/src/full/java/com/topjohnwu/magisk/components/InstallMethodDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/InstallMethodDialog.java index 187e21ff1..83a84c25f 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/InstallMethodDialog.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/InstallMethodDialog.java @@ -1,16 +1,16 @@ package com.topjohnwu.magisk.components; -import android.Manifest; import android.app.Activity; import android.content.Intent; import android.widget.Toast; import com.google.android.material.snackbar.Snackbar; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.Utils; +import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.FlashActivity; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.net.Networking; import java.io.File; @@ -33,7 +33,7 @@ class InstallMethodDialog extends AlertDialog.Builder { downloadOnly(activity); break; case 2: - intent = new Intent(activity, Data.classMap.get(FlashActivity.class)) + intent = new Intent(activity, ClassMap.get(FlashActivity.class)) .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_MAGISK); activity.startActivity(intent); break; @@ -48,13 +48,13 @@ class InstallMethodDialog extends AlertDialog.Builder { private void patchBoot(BaseActivity a) { Utils.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG); Intent intent = new Intent(Intent.ACTION_GET_CONTENT).setType("*/*"); - a.runWithPermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, () -> + a.runWithExternalRW(() -> a.startActivityForResult(intent, Const.ID.SELECT_BOOT, (requestCode, resultCode, data) -> { if (requestCode == Const.ID.SELECT_BOOT && resultCode == Activity.RESULT_OK && data != null) { - Intent i = new Intent(a, Data.classMap.get(FlashActivity.class)) - .putExtra(Const.Key.FLASH_SET_BOOT, data.getData()) + Intent i = new Intent(a, ClassMap.get(FlashActivity.class)) + .setData(data.getData()) .putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_BOOT); a.startActivity(i); } @@ -63,7 +63,7 @@ class InstallMethodDialog extends AlertDialog.Builder { } private void downloadOnly(BaseActivity a) { - a.runWithPermission(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, () -> { + a.runWithExternalRW(() -> { String filename = Utils.fmt("Magisk-v%s(%d).zip", Data.remoteMagiskVersionString, Data.remoteMagiskVersionCode); File zip = new File(Const.EXTERNAL_PATH, filename); @@ -86,7 +86,7 @@ class InstallMethodDialog extends AlertDialog.Builder { .setMessage(R.string.install_inactive_slot_msg) .setCancelable(true) .setPositiveButton(R.string.yes, (d, i) -> { - Intent intent = new Intent(activity, Data.classMap.get(FlashActivity.class)) + Intent intent = new Intent(activity, ClassMap.get(FlashActivity.class)) .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_INACTIVE_SLOT); activity.startActivity(intent); }) diff --git a/app/src/full/java/com/topjohnwu/magisk/components/MagiskInstallDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/MagiskInstallDialog.java index ebc675058..1adc9ef79 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/MagiskInstallDialog.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/MagiskInstallDialog.java @@ -3,11 +3,10 @@ package com.topjohnwu.magisk.components; import android.net.Uri; import android.text.TextUtils; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.asyncs.MarkDownWindow; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.AppUtils; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; @@ -15,35 +14,34 @@ import java.util.ArrayList; import java.util.List; public class MagiskInstallDialog extends CustomAlertDialog { - public MagiskInstallDialog(BaseActivity activity) { - super(activity); - MagiskManager mm = Data.MM(); + public MagiskInstallDialog(BaseActivity a) { + super(a); String filename = Utils.fmt("Magisk-v%s(%d).zip", Data.remoteMagiskVersionString, Data.remoteMagiskVersionCode); - setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.magisk))); - setMessage(mm.getString(R.string.repo_install_msg, filename)); + setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.magisk))); + setMessage(a.getString(R.string.repo_install_msg, filename)); setCancelable(true); setPositiveButton(R.string.install, (d, i) -> { List options = new ArrayList<>(); - options.add(mm.getString(R.string.download_zip_only)); - options.add(mm.getString(R.string.patch_boot_file)); + options.add(a.getString(R.string.download_zip_only)); + options.add(a.getString(R.string.patch_boot_file)); if (Shell.rootAccess()) { - options.add(mm.getString(R.string.direct_install)); + options.add(a.getString(R.string.direct_install)); String s = ShellUtils.fastCmd("grep_prop ro.build.ab_update"); if (!s.isEmpty() && Boolean.parseBoolean(s)) { - options.add(mm.getString(R.string.install_inactive_slot)); + options.add(a.getString(R.string.install_inactive_slot)); } } - new InstallMethodDialog(activity, options).show(); + new InstallMethodDialog(a, options).show(); }); setNegativeButton(R.string.no_thanks, null); if (!TextUtils.isEmpty(Data.magiskNoteLink)) { setNeutralButton(R.string.release_notes, (d, i) -> { if (Data.magiskNoteLink.contains("forum.xda-developers")) { // Open forum links in browser - Utils.openLink(activity, Uri.parse(Data.magiskNoteLink)); + AppUtils.openLink(a, Uri.parse(Data.magiskNoteLink)); } else { - new MarkDownWindow(activity, null, Data.magiskNoteLink).exec(); + new MarkDownWindow(a, null, Data.magiskNoteLink).exec(); } }); } diff --git a/app/src/full/java/com/topjohnwu/magisk/components/ManagerInstallDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/ManagerInstallDialog.java index 34e942647..58446ee21 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/ManagerInstallDialog.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/ManagerInstallDialog.java @@ -2,30 +2,27 @@ package com.topjohnwu.magisk.components; import android.text.TextUtils; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.asyncs.MarkDownWindow; -import com.topjohnwu.magisk.utils.DlInstallManager; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.DownloadApp; import androidx.annotation.NonNull; public class ManagerInstallDialog extends CustomAlertDialog { - public ManagerInstallDialog(@NonNull BaseActivity activity) { - super(activity); - MagiskManager mm = Data.MM(); + public ManagerInstallDialog(@NonNull BaseActivity a) { + super(a); String name = Utils.fmt("MagiskManager v%s(%d)", Data.remoteManagerVersionString, Data.remoteManagerVersionCode); - setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.app_name))); - setMessage(mm.getString(R.string.repo_install_msg, name)); + setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.app_name))); + setMessage(a.getString(R.string.repo_install_msg, name)); setCancelable(true); - setPositiveButton(R.string.install, (d, i) -> DlInstallManager.upgrade(name)); + setPositiveButton(R.string.install, (d, i) -> DownloadApp.upgrade(name)); setNegativeButton(R.string.no_thanks, null); if (!TextUtils.isEmpty(Data.managerNoteLink)) { setNeutralButton(R.string.app_changelog, (d, i) -> - new MarkDownWindow(activity, null, Data.managerNoteLink).exec()); + new MarkDownWindow(a, null, Data.managerNoteLink).exec()); } } } diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/MarkDownWindow.java b/app/src/full/java/com/topjohnwu/magisk/components/MarkDownWindow.java similarity index 83% rename from app/src/full/java/com/topjohnwu/magisk/asyncs/MarkDownWindow.java rename to app/src/full/java/com/topjohnwu/magisk/components/MarkDownWindow.java index 76694e03e..c52fc7fba 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/MarkDownWindow.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/MarkDownWindow.java @@ -1,12 +1,13 @@ -package com.topjohnwu.magisk.asyncs; +package com.topjohnwu.magisk.components; import android.app.Activity; import android.webkit.WebView; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.tasks.ParallelTask; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.ShellUtils; import org.commonmark.node.Node; @@ -40,7 +41,7 @@ public class MarkDownWindow extends ParallelTask { @Override protected String doInBackground(Void... voids) { - MagiskManager mm = Data.MM(); + App app = App.self; String md; if (mUrl != null) { md = Utils.dlString(mUrl); @@ -55,14 +56,11 @@ public class MarkDownWindow extends ParallelTask { } } String css; - try ( - InputStream in = mm.getResources().openRawResource( - Data.isDarkTheme ? R.raw.dark : R.raw.light); - ByteArrayOutputStream out = new ByteArrayOutputStream() - ) { + try (InputStream in = app.getResources() + .openRawResource(Data.isDarkTheme ? R.raw.dark : R.raw.light); + ByteArrayOutputStream out = new ByteArrayOutputStream()) { ShellUtils.pump(in, out); css = out.toString(); - in.close(); } catch (IOException e) { e.printStackTrace(); return ""; diff --git a/app/src/full/java/com/topjohnwu/magisk/components/Notifications.java b/app/src/full/java/com/topjohnwu/magisk/components/Notifications.java index 36c8f34ae..bdbc196d0 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/Notifications.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/Notifications.java @@ -7,13 +7,14 @@ import android.content.Context; import android.content.Intent; import android.os.Build; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.Utils; +import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.SplashActivity; import com.topjohnwu.magisk.receivers.GeneralReceiver; -import com.topjohnwu.magisk.utils.Utils; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; @@ -36,74 +37,74 @@ public class Notifications { } public static void magiskUpdate() { - MagiskManager mm = Data.MM(); + App app = App.self; - Intent intent = new Intent(mm, Data.classMap.get(SplashActivity.class)); + Intent intent = new Intent(app, ClassMap.get(SplashActivity.class)); intent.putExtra(Const.Key.OPEN_SECTION, "magisk"); - TaskStackBuilder stackBuilder = TaskStackBuilder.create(mm); - stackBuilder.addParentStack(Data.classMap.get(SplashActivity.class)); + TaskStackBuilder stackBuilder = TaskStackBuilder.create(app); + stackBuilder.addParentStack(ClassMap.get(SplashActivity.class)); stackBuilder.addNextIntent(intent); PendingIntent pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, PendingIntent.FLAG_UPDATE_CURRENT); - NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.UPDATE_NOTIFICATION_CHANNEL); + NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.UPDATE_NOTIFICATION_CHANNEL); builder.setSmallIcon(R.drawable.ic_magisk_outline) - .setContentTitle(mm.getString(R.string.magisk_update_title)) - .setContentText(mm.getString(R.string.magisk_update_available, Data.remoteMagiskVersionString)) + .setContentTitle(app.getString(R.string.magisk_update_title)) + .setContentText(app.getString(R.string.magisk_update_available, Data.remoteMagiskVersionString)) .setVibrate(new long[]{0, 100, 100, 100}) .setAutoCancel(true) .setContentIntent(pendingIntent); - NotificationManagerCompat mgr = NotificationManagerCompat.from(mm); + NotificationManagerCompat mgr = NotificationManagerCompat.from(app); mgr.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build()); } public static void managerUpdate() { - MagiskManager mm = Data.MM(); + App app = App.self; String name = Utils.fmt("MagiskManager v%s(%d)", Data.remoteManagerVersionString, Data.remoteManagerVersionCode); - Intent intent = new Intent(mm, Data.classMap.get(GeneralReceiver.class)); + Intent intent = new Intent(app, ClassMap.get(GeneralReceiver.class)); intent.setAction(Const.Key.BROADCAST_MANAGER_UPDATE); intent.putExtra(Const.Key.INTENT_SET_LINK, Data.managerLink); intent.putExtra(Const.Key.INTENT_SET_NAME, name); - PendingIntent pendingIntent = PendingIntent.getBroadcast(mm, + PendingIntent pendingIntent = PendingIntent.getBroadcast(app, Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); - NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.UPDATE_NOTIFICATION_CHANNEL); + NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.UPDATE_NOTIFICATION_CHANNEL); builder.setSmallIcon(R.drawable.ic_magisk_outline) - .setContentTitle(mm.getString(R.string.manager_update_title)) - .setContentText(mm.getString(R.string.manager_download_install)) + .setContentTitle(app.getString(R.string.manager_update_title)) + .setContentText(app.getString(R.string.manager_download_install)) .setVibrate(new long[]{0, 100, 100, 100}) .setAutoCancel(true) .setContentIntent(pendingIntent); - NotificationManagerCompat mgr = NotificationManagerCompat.from(mm); + NotificationManagerCompat mgr = NotificationManagerCompat.from(app); mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build()); } public static void dtboPatched() { - MagiskManager mm = Data.MM(); + App app = App.self; - Intent intent = new Intent(mm, Data.classMap.get(GeneralReceiver.class)) + Intent intent = new Intent(app, ClassMap.get(GeneralReceiver.class)) .setAction(Const.Key.BROADCAST_REBOOT); - PendingIntent pendingIntent = PendingIntent.getBroadcast(mm, + PendingIntent pendingIntent = PendingIntent.getBroadcast(app, Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); - NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.UPDATE_NOTIFICATION_CHANNEL); + NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.UPDATE_NOTIFICATION_CHANNEL); builder.setSmallIcon(R.drawable.ic_magisk_outline) - .setContentTitle(mm.getString(R.string.dtbo_patched_title)) - .setContentText(mm.getString(R.string.dtbo_patched_reboot)) + .setContentTitle(app.getString(R.string.dtbo_patched_title)) + .setContentText(app.getString(R.string.dtbo_patched_reboot)) .setVibrate(new long[]{0, 100, 100, 100}) - .addAction(R.drawable.ic_refresh, mm.getString(R.string.reboot), pendingIntent); + .addAction(R.drawable.ic_refresh, app.getString(R.string.reboot), pendingIntent); - NotificationManagerCompat mgr = NotificationManagerCompat.from(mm); + NotificationManagerCompat mgr = NotificationManagerCompat.from(app); mgr.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build()); } public static NotificationCompat.Builder progress(String title) { - MagiskManager mm = Data.MM(); - NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.PROGRESS_NOTIFICATION_CHANNEL); + App app = App.self; + NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.PROGRESS_NOTIFICATION_CHANNEL); builder.setPriority(NotificationCompat.PRIORITY_LOW) .setSmallIcon(android.R.drawable.stat_sys_download) .setContentTitle(title) diff --git a/app/src/full/java/com/topjohnwu/magisk/components/ProgressNotification.java b/app/src/full/java/com/topjohnwu/magisk/components/ProgressNotification.java index 5b8e5ded9..35b91457c 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/ProgressNotification.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/ProgressNotification.java @@ -2,10 +2,9 @@ package com.topjohnwu.magisk.components; import android.widget.Toast; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.core.App; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.net.DownloadProgressListener; import androidx.core.app.NotificationCompat; @@ -17,12 +16,11 @@ public class ProgressNotification implements DownloadProgressListener { private long prevTime; public ProgressNotification(String title) { - MagiskManager mm = Data.MM(); - mgr = NotificationManagerCompat.from(mm); + mgr = NotificationManagerCompat.from(App.self); builder = Notifications.progress(title); prevTime = System.currentTimeMillis(); update(); - Utils.toast(mm.getString(R.string.downloading_toast, title), Toast.LENGTH_SHORT); + Utils.toast(App.self.getString(R.string.downloading_toast, title), Toast.LENGTH_SHORT); } @Override @@ -47,7 +45,7 @@ public class ProgressNotification implements DownloadProgressListener { public void dlDone() { builder.setProgress(0, 0, false) - .setContentText(Data.MM().getString(R.string.download_complete)) + .setContentText(App.self.getString(R.string.download_complete)) .setSmallIcon(R.drawable.ic_check_circle) .setOngoing(false); update(); @@ -55,7 +53,7 @@ public class ProgressNotification implements DownloadProgressListener { public void dlFail() { builder.setProgress(0, 0, false) - .setContentText(Data.MM().getString(R.string.download_file_error)) + .setContentText(App.self.getString(R.string.download_file_error)) .setSmallIcon(R.drawable.ic_cancel) .setOngoing(false); update(); diff --git a/app/src/full/java/com/topjohnwu/magisk/components/SnackbarMaker.java b/app/src/full/java/com/topjohnwu/magisk/components/SnackbarMaker.java index 120f70861..d943fd810 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/SnackbarMaker.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/SnackbarMaker.java @@ -6,8 +6,8 @@ import android.view.View; import android.widget.TextView; import com.google.android.material.snackbar.Snackbar; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Utils; import androidx.annotation.StringRes; diff --git a/app/src/full/java/com/topjohnwu/magisk/components/UninstallDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/UninstallDialog.java index c685a22fe..4dffab030 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/UninstallDialog.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/UninstallDialog.java @@ -7,11 +7,12 @@ import android.net.Uri; import android.text.TextUtils; import android.widget.Toast; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.Utils; +import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.FlashActivity; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.net.Networking; import com.topjohnwu.superuser.Shell; @@ -47,7 +48,7 @@ public class UninstallDialog extends CustomAlertDialog { .setErrorHandler(((conn, e) -> progress.dlFail())) .getAsFile(f -> { progress.dismiss(); - Intent intent = new Intent(activity, Data.classMap.get(FlashActivity.class)) + Intent intent = new Intent(activity, ClassMap.get(FlashActivity.class)) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .setData(Uri.fromFile(f)) .putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL); diff --git a/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskFragment.java b/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskFragment.java index 4da8ab0ce..2104f1d42 100644 --- a/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskFragment.java @@ -15,13 +15,15 @@ import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.tasks.CheckUpdates; +import com.topjohnwu.core.tasks.SafetyNet; +import com.topjohnwu.core.utils.ISafetyNetHelper; +import com.topjohnwu.core.utils.Topic; import com.topjohnwu.magisk.BuildConfig; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; import com.topjohnwu.magisk.MainActivity; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.asyncs.CheckUpdates; -import com.topjohnwu.magisk.asyncs.SafetyNet; import com.topjohnwu.magisk.components.BaseActivity; import com.topjohnwu.magisk.components.BaseFragment; import com.topjohnwu.magisk.components.CustomAlertDialog; @@ -31,8 +33,6 @@ import com.topjohnwu.magisk.components.MagiskInstallDialog; import com.topjohnwu.magisk.components.ManagerInstallDialog; import com.topjohnwu.magisk.components.UninstallDialog; import com.topjohnwu.magisk.utils.Download; -import com.topjohnwu.magisk.utils.ISafetyNetHelper; -import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; @@ -119,7 +119,7 @@ public class MagiskFragment extends BaseFragment return; } - ((NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll(); + ((NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll(); new MagiskInstallDialog((BaseActivity) getActivity()).show(); } @@ -169,7 +169,7 @@ public class MagiskFragment extends BaseFragment shownDialog = false; // Trigger state check - if (Download.checkNetworkStatus(mm)) { + if (Download.checkNetworkStatus(app)) { CheckUpdates.check(); } else { mSwipeRefreshLayout.setRefreshing(false); @@ -199,7 +199,7 @@ public class MagiskFragment extends BaseFragment } private boolean hasGms() { - PackageManager pm = mm.getPackageManager(); + PackageManager pm = app.getPackageManager(); PackageInfo info; try { info = pm.getPackageInfo("com.google.android.gms", 0); @@ -212,13 +212,13 @@ public class MagiskFragment extends BaseFragment private void updateUI() { ((MainActivity) requireActivity()).checkHideSection(); - boolean hasNetwork = Download.checkNetworkStatus(mm); + boolean hasNetwork = Download.checkNetworkStatus(app); boolean hasRoot = Shell.rootAccess(); magiskUpdate.setVisibility(hasNetwork ? View.VISIBLE : View.GONE); installOptionCard.setVisibility(hasNetwork ? View.VISIBLE : View.GONE); uninstallButton.setVisibility(hasRoot ? View.VISIBLE : View.GONE); - coreOnlyNotice.setVisibility(mm.prefs.getBoolean(Const.Key.COREONLY, false) ? View.VISIBLE : View.GONE); + coreOnlyNotice.setVisibility(app.prefs.getBoolean(Const.Key.COREONLY, false) ? View.VISIBLE : View.GONE); int image, color; diff --git a/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskHideFragment.java b/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskHideFragment.java index ac9599db4..56c95a42c 100644 --- a/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskHideFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskHideFragment.java @@ -8,10 +8,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.SearchView; +import com.topjohnwu.core.utils.Topic; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.adapters.ApplicationAdapter; import com.topjohnwu.magisk.components.BaseFragment; -import com.topjohnwu.magisk.utils.Topic; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskLogFragment.java b/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskLogFragment.java index 10d2b298c..b956cfc1c 100644 --- a/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskLogFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/fragments/MagiskLogFragment.java @@ -15,11 +15,11 @@ import android.widget.ScrollView; import android.widget.TextView; import com.google.android.material.snackbar.Snackbar; -import com.topjohnwu.magisk.Const; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.components.BaseFragment; import com.topjohnwu.magisk.components.SnackbarMaker; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.Shell; import java.io.File; diff --git a/app/src/full/java/com/topjohnwu/magisk/fragments/ModulesFragment.java b/app/src/full/java/com/topjohnwu/magisk/fragments/ModulesFragment.java index dbb6c4813..7ff40e84a 100644 --- a/app/src/full/java/com/topjohnwu/magisk/fragments/ModulesFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/fragments/ModulesFragment.java @@ -12,15 +12,15 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.container.Module; +import com.topjohnwu.core.utils.Topic; +import com.topjohnwu.core.utils.Utils; +import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.FlashActivity; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.adapters.ModulesAdapter; import com.topjohnwu.magisk.components.BaseFragment; -import com.topjohnwu.magisk.container.Module; -import com.topjohnwu.magisk.utils.Topic; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.Shell; import java.util.ArrayList; @@ -94,7 +94,7 @@ public class ModulesFragment extends BaseFragment implements Topic.Subscriber { public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) { // Get the URI of the selected file - Intent intent = new Intent(getActivity(), Data.classMap.get(FlashActivity.class)); + Intent intent = new Intent(getActivity(), ClassMap.get(FlashActivity.class)); intent.setData(data.getData()).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP); startActivity(intent); } diff --git a/app/src/full/java/com/topjohnwu/magisk/fragments/ReposFragment.java b/app/src/full/java/com/topjohnwu/magisk/fragments/ReposFragment.java index a352f4b30..447e3a976 100644 --- a/app/src/full/java/com/topjohnwu/magisk/fragments/ReposFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/fragments/ReposFragment.java @@ -11,14 +11,14 @@ import android.view.ViewGroup; import android.widget.SearchView; import android.widget.TextView; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.container.Module; +import com.topjohnwu.core.tasks.UpdateRepos; +import com.topjohnwu.core.utils.Topic; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.adapters.ReposAdapter; -import com.topjohnwu.magisk.asyncs.UpdateRepos; import com.topjohnwu.magisk.components.BaseFragment; -import com.topjohnwu.magisk.container.Module; -import com.topjohnwu.magisk.utils.Topic; import java.util.Map; @@ -70,8 +70,8 @@ public class ReposFragment extends BaseFragment implements Topic.Subscriber { @Override public void onPublish(int topic, Object[] result) { if (topic == Topic.MODULE_LOAD_DONE) { - adapter = new ReposAdapter(mm.repoDB, (Map) result[0]); - mm.repoDB.registerAdapter(adapter); + adapter = new ReposAdapter(app.repoDB, (Map) result[0]); + app.repoDB.registerAdapterCallback(adapter::notifyDBChanged); recyclerView.setAdapter(adapter); recyclerView.setVisibility(View.VISIBLE); emptyRv.setVisibility(View.GONE); @@ -108,7 +108,7 @@ public class ReposFragment extends BaseFragment implements Topic.Subscriber { .setTitle(R.string.sorting_order) .setSingleChoiceItems(R.array.sorting_orders, Data.repoOrder, (d, which) -> { Data.repoOrder = which; - mm.prefs.edit().putInt(Const.Key.REPO_ORDER, Data.repoOrder).apply(); + app.prefs.edit().putInt(Const.Key.REPO_ORDER, Data.repoOrder).apply(); adapter.notifyDBChanged(); d.dismiss(); }).show(); @@ -119,6 +119,6 @@ public class ReposFragment extends BaseFragment implements Topic.Subscriber { @Override public void onDestroyView() { super.onDestroyView(); - mm.repoDB.unregisterAdapter(); + app.repoDB.unregisterAdapterCallback(); } } diff --git a/app/src/full/java/com/topjohnwu/magisk/fragments/SettingsFragment.java b/app/src/full/java/com/topjohnwu/magisk/fragments/SettingsFragment.java index 332acfcc5..137b9310c 100644 --- a/app/src/full/java/com/topjohnwu/magisk/fragments/SettingsFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/fragments/SettingsFragment.java @@ -10,19 +10,20 @@ import android.view.ViewGroup; import android.widget.EditText; import android.widget.Toast; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.tasks.CheckUpdates; +import com.topjohnwu.core.utils.LocaleManager; +import com.topjohnwu.core.utils.Topic; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.BuildConfig; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.asyncs.CheckUpdates; -import com.topjohnwu.magisk.asyncs.PatchAPK; -import com.topjohnwu.magisk.utils.DlInstallManager; +import com.topjohnwu.magisk.utils.AppUtils; import com.topjohnwu.magisk.utils.Download; +import com.topjohnwu.magisk.utils.DownloadApp; import com.topjohnwu.magisk.utils.FingerprintHelper; -import com.topjohnwu.magisk.utils.LocaleManager; -import com.topjohnwu.magisk.utils.Topic; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.PatchAPK; import com.topjohnwu.superuser.Shell; import java.io.IOException; @@ -43,7 +44,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener, Topic.Subscriber, Topic.AutoSubscriber { - private MagiskManager mm; + private App app = App.self; private ListPreference updateChannel, autoRes, suNotification, requestTimeout, rootConfig, multiuserConfig, nsConfig; @@ -52,10 +53,10 @@ public class SettingsFragment extends PreferenceFragmentCompat private boolean showSuperuser; private void prefsSync() { - rootState = mm.mDB.getSettings(Const.Key.ROOT_ACCESS, Const.Value.ROOT_ACCESS_APPS_AND_ADB); - namespaceState = mm.mDB.getSettings(Const.Key.SU_MNT_NS, Const.Value.NAMESPACE_MODE_REQUESTER); + rootState = app.mDB.getSettings(Const.Key.ROOT_ACCESS, Const.Value.ROOT_ACCESS_APPS_AND_ADB); + namespaceState = app.mDB.getSettings(Const.Key.SU_MNT_NS, Const.Value.NAMESPACE_MODE_REQUESTER); showSuperuser = Utils.showSuperUser(); - mm.prefs.edit() + app.prefs.edit() .putString(Const.Key.ROOT_ACCESS, String.valueOf(rootState)) .putString(Const.Key.SU_MNT_NS, String.valueOf(namespaceState)) .putString(Const.Key.SU_MULTIUSER_MODE, String.valueOf(Data.multiuserState)) @@ -65,7 +66,6 @@ public class SettingsFragment extends PreferenceFragmentCompat @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - mm = Data.MM(); prefsSync(); setPreferencesFromResource(R.xml.app_settings, rootKey); @@ -82,12 +82,12 @@ public class SettingsFragment extends PreferenceFragmentCompat }); Preference restoreManager = findPreference("restore"); restoreManager.setOnPreferenceClickListener(pref -> { - DlInstallManager.restore(); + DownloadApp.restore(); return true; }); findPreference("clear").setOnPreferenceClickListener(pref -> { - mm.prefs.edit().remove(Const.Key.ETAG_KEY).apply(); - mm.repoDB.clearRepo(); + app.prefs.edit().remove(Const.Key.ETAG_KEY).apply(); + app.repoDB.clearRepo(); Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT); return true; }); @@ -114,17 +114,17 @@ public class SettingsFragment extends PreferenceFragmentCompat if (channel == Const.Value.CUSTOM_CHANNEL) { View v = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_channel_dialog, null); EditText url = v.findViewById(R.id.custom_url); - url.setText(mm.prefs.getString(Const.Key.CUSTOM_CHANNEL, "")); + url.setText(app.prefs.getString(Const.Key.CUSTOM_CHANNEL, "")); new AlertDialog.Builder(requireActivity()) .setTitle(R.string.settings_update_custom) .setView(v) .setPositiveButton(R.string.ok, (d, i) -> - mm.prefs.edit().putString(Const.Key.CUSTOM_CHANNEL, + app.prefs.edit().putString(Const.Key.CUSTOM_CHANNEL, url.getText().toString()).apply()) .setNegativeButton(R.string.close, (d, i) -> - mm.prefs.edit().putString(Const.Key.UPDATE_CHANNEL, prev).apply()) + app.prefs.edit().putString(Const.Key.UPDATE_CHANNEL, prev).apply()) .setOnCancelListener(d -> - mm.prefs.edit().putString(Const.Key.UPDATE_CHANNEL, prev).apply()) + app.prefs.edit().putString(Const.Key.UPDATE_CHANNEL, prev).apply()) .show(); } return true; @@ -152,10 +152,10 @@ public class SettingsFragment extends PreferenceFragmentCompat } if (Shell.rootAccess() && Const.USER_ID == 0) { - if (mm.getPackageName().equals(BuildConfig.APPLICATION_ID)) { + if (app.getPackageName().equals(BuildConfig.APPLICATION_ID)) { generalCatagory.removePreference(restoreManager); } else { - if (!Download.checkNetworkStatus(mm)) + if (!Download.checkNetworkStatus(app)) generalCatagory.removePreference(restoreManager); generalCatagory.removePreference(hideManager); } @@ -191,7 +191,7 @@ public class SettingsFragment extends PreferenceFragmentCompat @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - mm.prefs.registerOnSharedPreferenceChangeListener(this); + app.prefs.registerOnSharedPreferenceChangeListener(this); Topic.subscribe(this); requireActivity().setTitle(R.string.settings); return super.onCreateView(inflater, container, savedInstanceState); @@ -199,7 +199,7 @@ public class SettingsFragment extends PreferenceFragmentCompat @Override public void onDestroyView() { - mm.prefs.unregisterOnSharedPreferenceChangeListener(this); + app.prefs.unregisterOnSharedPreferenceChangeListener(this); Topic.unsubscribe(this); super.onDestroyView(); } @@ -210,7 +210,7 @@ public class SettingsFragment extends PreferenceFragmentCompat case Const.Key.ROOT_ACCESS: case Const.Key.SU_MULTIUSER_MODE: case Const.Key.SU_MNT_NS: - mm.mDB.setSettings(key, Utils.getPrefsInt(prefs, key)); + app.mDB.setSettings(key, Utils.getPrefsInt(prefs, key)); break; } switch (key) { @@ -244,7 +244,7 @@ public class SettingsFragment extends PreferenceFragmentCompat } break; case Const.Key.LOCALE: - LocaleManager.setLocale(mm); + LocaleManager.setLocale(app); requireActivity().recreate(); break; case Const.Key.UPDATE_CHANNEL: @@ -252,7 +252,7 @@ public class SettingsFragment extends PreferenceFragmentCompat CheckUpdates.check(); break; case Const.Key.CHECK_UPDATES: - Utils.setupUpdateCheck(); + AppUtils.setupUpdateCheck(); break; } Data.loadConfig(); @@ -268,7 +268,7 @@ public class SettingsFragment extends PreferenceFragmentCompat ((SwitchPreference) preference).setChecked(!checked); FingerprintHelper.showAuthDialog(requireActivity(), () -> { ((SwitchPreference) preference).setChecked(checked); - mm.mDB.setSettings(key, checked ? 1 : 0); + app.mDB.setSettings(key, checked ? 1 : 0); }); break; } @@ -286,7 +286,7 @@ public class SettingsFragment extends PreferenceFragmentCompat .getStringArray(R.array.su_notification)[Data.suNotificationType]); requestTimeout.setSummary( getString(R.string.request_timeout_summary, - mm.prefs.getString(Const.Key.SU_REQUEST_TIMEOUT, "10"))); + app.prefs.getString(Const.Key.SU_REQUEST_TIMEOUT, "10"))); multiuserConfig.setSummary(getResources() .getStringArray(R.array.multiuser_summary)[Data.multiuserState]); nsConfig.setSummary(getResources() diff --git a/app/src/full/java/com/topjohnwu/magisk/fragments/SuLogFragment.java b/app/src/full/java/com/topjohnwu/magisk/fragments/SuLogFragment.java index a982513ff..da0c87110 100644 --- a/app/src/full/java/com/topjohnwu/magisk/fragments/SuLogFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/fragments/SuLogFragment.java @@ -42,7 +42,7 @@ public class SuLogFragment extends BaseFragment { // Inflate the layout for this fragment View v = inflater.inflate(R.layout.fragment_su_log, container, false); unbinder = new SuLogFragment_ViewBinding(this, v); - adapter = new SuLogAdapter(mm.mDB); + adapter = new SuLogAdapter(app.mDB); recyclerView.setAdapter(adapter); updateList(); @@ -69,7 +69,7 @@ public class SuLogFragment extends BaseFragment { updateList(); return true; case R.id.menu_clear: - mm.mDB.clearLogs(); + app.mDB.clearLogs(); updateList(); return true; default: diff --git a/app/src/full/java/com/topjohnwu/magisk/fragments/SuperuserFragment.java b/app/src/full/java/com/topjohnwu/magisk/fragments/SuperuserFragment.java index b699554ce..8b291bb40 100644 --- a/app/src/full/java/com/topjohnwu/magisk/fragments/SuperuserFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/fragments/SuperuserFragment.java @@ -7,10 +7,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import com.topjohnwu.core.container.Policy; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.adapters.PolicyAdapter; import com.topjohnwu.magisk.components.BaseFragment; -import com.topjohnwu.magisk.container.Policy; import java.util.List; @@ -48,13 +48,13 @@ public class SuperuserFragment extends BaseFragment { } private void displayPolicyList() { - List policyList = mm.mDB.getPolicyList(); + List policyList = app.mDB.getPolicyList(); if (policyList.size() == 0) { emptyRv.setVisibility(View.VISIBLE); recyclerView.setVisibility(View.GONE); } else { - recyclerView.setAdapter(new PolicyAdapter(policyList, mm.mDB, pm)); + recyclerView.setAdapter(new PolicyAdapter(policyList, app.mDB, pm)); emptyRv.setVisibility(View.GONE); recyclerView.setVisibility(View.VISIBLE); } diff --git a/app/src/full/java/com/topjohnwu/magisk/receivers/GeneralReceiver.java b/app/src/full/java/com/topjohnwu/magisk/receivers/GeneralReceiver.java index e861c554b..e1e63323e 100644 --- a/app/src/full/java/com/topjohnwu/magisk/receivers/GeneralReceiver.java +++ b/app/src/full/java/com/topjohnwu/magisk/receivers/GeneralReceiver.java @@ -4,12 +4,13 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.SuRequestActivity; import com.topjohnwu.magisk.services.OnBootService; -import com.topjohnwu.magisk.utils.DlInstallManager; +import com.topjohnwu.magisk.utils.DownloadApp; import com.topjohnwu.magisk.utils.SuConnector; import com.topjohnwu.superuser.Shell; @@ -21,7 +22,7 @@ public class GeneralReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - MagiskManager mm = Data.MM(); + App app = App.self; if (intent == null) return; String action = intent.getAction(); @@ -34,10 +35,10 @@ public class GeneralReceiver extends BroadcastReceiver { bootAction = "boot"; switch (bootAction) { case "request": - Intent i = new Intent(mm, Data.classMap.get(SuRequestActivity.class)) + Intent i = new Intent(app, ClassMap.get(SuRequestActivity.class)) .putExtra("socket", intent.getStringExtra("socket")) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mm.startActivity(i); + app.startActivity(i); break; case "log": SuConnector.handleLogs(intent); @@ -48,24 +49,24 @@ public class GeneralReceiver extends BroadcastReceiver { case "boot": default: /* The actual on-boot trigger */ - OnBootService.enqueueWork(mm); + OnBootService.enqueueWork(app); break; } break; case Intent.ACTION_PACKAGE_REPLACED: // This will only work pre-O - if (mm.prefs.getBoolean(Const.Key.SU_REAUTH, false)) { - mm.mDB.deletePolicy(getPkg(intent)); + if (app.prefs.getBoolean(Const.Key.SU_REAUTH, false)) { + app.mDB.deletePolicy(getPkg(intent)); } break; case Intent.ACTION_PACKAGE_FULLY_REMOVED: String pkg = getPkg(intent); - mm.mDB.deletePolicy(pkg); + app.mDB.deletePolicy(pkg); Shell.su("magiskhide --rm " + pkg).submit(); break; case Const.Key.BROADCAST_MANAGER_UPDATE: Data.managerLink = intent.getStringExtra(Const.Key.INTENT_SET_LINK); - DlInstallManager.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME)); + DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME)); break; case Const.Key.BROADCAST_REBOOT: Shell.su("/system/bin/reboot").submit(); diff --git a/app/src/full/java/com/topjohnwu/magisk/receivers/ShortcutReceiver.java b/app/src/full/java/com/topjohnwu/magisk/receivers/ShortcutReceiver.java index e61a04335..1875a6bef 100644 --- a/app/src/full/java/com/topjohnwu/magisk/receivers/ShortcutReceiver.java +++ b/app/src/full/java/com/topjohnwu/magisk/receivers/ShortcutReceiver.java @@ -8,12 +8,13 @@ import android.content.pm.ShortcutManager; import android.graphics.drawable.Icon; import android.os.Build; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.Utils; +import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.SplashActivity; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.Shell; import java.util.ArrayList; @@ -24,55 +25,54 @@ public class ShortcutReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - MagiskManager mm = Data.MM(); ShortcutManager manager = context.getSystemService(ShortcutManager.class); - manager.setDynamicShortcuts(getShortCuts(mm)); + manager.setDynamicShortcuts(getShortCuts(App.self)); } } @RequiresApi(api = Build.VERSION_CODES.N_MR1) - private ArrayList getShortCuts(MagiskManager mm) { + private ArrayList getShortCuts(App app) { ArrayList shortCuts = new ArrayList<>(); boolean root = Shell.rootAccess(); if (Utils.showSuperUser()) { - shortCuts.add(new ShortcutInfo.Builder(mm, "superuser") - .setShortLabel(mm.getString(R.string.superuser)) - .setIntent(new Intent(mm, Data.classMap.get(SplashActivity.class)) + shortCuts.add(new ShortcutInfo.Builder(app, "superuser") + .setShortLabel(app.getString(R.string.superuser)) + .setIntent(new Intent(app, ClassMap.get(SplashActivity.class)) .putExtra(Const.Key.OPEN_SECTION, "superuser") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) - .setIcon(Icon.createWithResource(mm, R.drawable.sc_superuser)) + .setIcon(Icon.createWithResource(app, R.drawable.sc_superuser)) .setRank(0) .build()); } - if (root && mm.prefs.getBoolean(Const.Key.MAGISKHIDE, false)) { - shortCuts.add(new ShortcutInfo.Builder(mm, "magiskhide") - .setShortLabel(mm.getString(R.string.magiskhide)) - .setIntent(new Intent(mm, Data.classMap.get(SplashActivity.class)) + if (root && app.prefs.getBoolean(Const.Key.MAGISKHIDE, false)) { + shortCuts.add(new ShortcutInfo.Builder(app, "magiskhide") + .setShortLabel(app.getString(R.string.magiskhide)) + .setIntent(new Intent(app, ClassMap.get(SplashActivity.class)) .putExtra(Const.Key.OPEN_SECTION, "magiskhide") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) - .setIcon(Icon.createWithResource(mm, R.drawable.sc_magiskhide)) + .setIcon(Icon.createWithResource(app, R.drawable.sc_magiskhide)) .setRank(1) .build()); } - if (!mm.prefs.getBoolean(Const.Key.COREONLY, false) && root && Data.magiskVersionCode >= 0) { - shortCuts.add(new ShortcutInfo.Builder(mm, "modules") - .setShortLabel(mm.getString(R.string.modules)) - .setIntent(new Intent(mm, Data.classMap.get(SplashActivity.class)) + if (!app.prefs.getBoolean(Const.Key.COREONLY, false) && root && Data.magiskVersionCode >= 0) { + shortCuts.add(new ShortcutInfo.Builder(app, "modules") + .setShortLabel(app.getString(R.string.modules)) + .setIntent(new Intent(app, ClassMap.get(SplashActivity.class)) .putExtra(Const.Key.OPEN_SECTION, "modules") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) - .setIcon(Icon.createWithResource(mm, R.drawable.sc_extension)) + .setIcon(Icon.createWithResource(app, R.drawable.sc_extension)) .setRank(3) .build()); - shortCuts.add(new ShortcutInfo.Builder(mm, "downloads") - .setShortLabel(mm.getString(R.string.downloads)) - .setIntent(new Intent(mm, Data.classMap.get(SplashActivity.class)) + shortCuts.add(new ShortcutInfo.Builder(app, "downloads") + .setShortLabel(app.getString(R.string.downloads)) + .setIntent(new Intent(app, ClassMap.get(SplashActivity.class)) .putExtra(Const.Key.OPEN_SECTION, "downloads") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) - .setIcon(Icon.createWithResource(mm, R.drawable.sc_cloud_download)) + .setIcon(Icon.createWithResource(app, R.drawable.sc_cloud_download)) .setRank(2) .build()); } diff --git a/app/src/full/java/com/topjohnwu/magisk/services/OnBootService.java b/app/src/full/java/com/topjohnwu/magisk/services/OnBootService.java index 1605cfc33..4699c250c 100644 --- a/app/src/full/java/com/topjohnwu/magisk/services/OnBootService.java +++ b/app/src/full/java/com/topjohnwu/magisk/services/OnBootService.java @@ -3,8 +3,8 @@ package com.topjohnwu.magisk.services; import android.content.Context; import android.content.Intent; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; +import com.topjohnwu.core.Const; +import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.components.Notifications; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; @@ -15,7 +15,7 @@ import androidx.core.app.JobIntentService; public class OnBootService extends JobIntentService { public static void enqueueWork(Context context) { - enqueueWork(context, Data.classMap.get(OnBootService.class), Const.ID.ONBOOT_SERVICE_ID, new Intent()); + enqueueWork(context, ClassMap.get(OnBootService.class), Const.ID.ONBOOT_SERVICE_ID, new Intent()); } @Override diff --git a/app/src/full/java/com/topjohnwu/magisk/services/UpdateCheckService.java b/app/src/full/java/com/topjohnwu/magisk/services/UpdateCheckService.java index b5198ed50..620f91f05 100644 --- a/app/src/full/java/com/topjohnwu/magisk/services/UpdateCheckService.java +++ b/app/src/full/java/com/topjohnwu/magisk/services/UpdateCheckService.java @@ -3,7 +3,10 @@ package com.topjohnwu.magisk.services; import android.app.job.JobParameters; import android.app.job.JobService; -import com.topjohnwu.magisk.asyncs.CheckUpdates; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.tasks.CheckUpdates; +import com.topjohnwu.magisk.BuildConfig; +import com.topjohnwu.magisk.components.Notifications; import com.topjohnwu.superuser.Shell; public class UpdateCheckService extends JobService { @@ -11,7 +14,14 @@ public class UpdateCheckService extends JobService { @Override public boolean onStartJob(JobParameters params) { Shell.getShell(); - CheckUpdates.check(() -> jobFinished(params, false)); + CheckUpdates.check(() -> { + if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) { + Notifications.managerUpdate(); + } else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) { + Notifications.magiskUpdate(); + } + jobFinished(params, false); + }); return true; } diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/AppUtils.java b/app/src/full/java/com/topjohnwu/magisk/utils/AppUtils.java new file mode 100644 index 000000000..1bd572fb9 --- /dev/null +++ b/app/src/full/java/com/topjohnwu/magisk/utils/AppUtils.java @@ -0,0 +1,50 @@ +package com.topjohnwu.magisk.utils; + +import android.app.job.JobInfo; +import android.app.job.JobScheduler; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.widget.Toast; + +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.utils.Utils; +import com.topjohnwu.magisk.ClassMap; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.services.UpdateCheckService; + +public class AppUtils { + + public static void setupUpdateCheck() { + App app = App.self; + JobScheduler scheduler = (JobScheduler) app.getSystemService(Context.JOB_SCHEDULER_SERVICE); + + if (app.prefs.getBoolean(Const.Key.CHECK_UPDATES, true)) { + if (scheduler.getAllPendingJobs().isEmpty() || + Const.UPDATE_SERVICE_VER > app.prefs.getInt(Const.Key.UPDATE_SERVICE_VER, -1)) { + ComponentName service = new ComponentName(app, ClassMap.get(UpdateCheckService.class)); + JobInfo info = new JobInfo.Builder(Const.ID.UPDATE_SERVICE_ID, service) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .setPersisted(true) + .setPeriodic(8 * 60 * 60 * 1000) + .build(); + scheduler.schedule(info); + } + } else { + scheduler.cancel(Const.UPDATE_SERVICE_VER); + } + } + + 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 { + Utils.toast(R.string.open_link_failed_toast, Toast.LENGTH_SHORT); + } + } + +} \ No newline at end of file diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/DlInstallManager.java b/app/src/full/java/com/topjohnwu/magisk/utils/DownloadApp.java similarity index 79% rename from app/src/full/java/com/topjohnwu/magisk/utils/DlInstallManager.java rename to app/src/full/java/com/topjohnwu/magisk/utils/DownloadApp.java index 30c0ee58f..2c8274fde 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/DlInstallManager.java +++ b/app/src/full/java/com/topjohnwu/magisk/utils/DownloadApp.java @@ -2,11 +2,12 @@ package com.topjohnwu.magisk.utils; import android.os.AsyncTask; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.RootUtils; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.BuildConfig; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.asyncs.PatchAPK; import com.topjohnwu.magisk.components.ProgressNotification; import com.topjohnwu.net.Networking; import com.topjohnwu.net.ResponseListener; @@ -18,7 +19,7 @@ import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; -public class DlInstallManager { +public class DownloadApp { public static void upgrade(String name) { dlInstall(name, new PatchPackageName()); @@ -31,8 +32,7 @@ public class DlInstallManager { } private static void dlInstall(String name, ManagerDownloadListener listener) { - MagiskManager mm = Data.MM(); - File apk = new File(mm.getFilesDir(), "manager.apk"); + File apk = new File(App.self.getFilesDir(), "manager.apk"); ProgressNotification progress = new ProgressNotification(name); listener.setProgressNotification(progress); Networking.get(Data.managerLink) @@ -63,23 +63,23 @@ public class DlInstallManager { @Override public void onDownloadComplete(File apk, ProgressNotification progress) { File patched = apk; - MagiskManager mm = Data.MM(); - if (!mm.getPackageName().equals(BuildConfig.APPLICATION_ID)) { + App app = App.self; + if (!App.self.getPackageName().equals(BuildConfig.APPLICATION_ID)) { progress.getNotification() .setProgress(0, 0, true) - .setContentTitle(mm.getString(R.string.hide_manager_title)) + .setContentTitle(app.getString(R.string.hide_manager_title)) .setContentText(""); progress.update(); patched = new File(apk.getParent(), "patched.apk"); try { JarMap jarMap = new JarMap(apk); - PatchAPK.patch(jarMap, mm.getPackageName()); + PatchAPK.patch(jarMap, app.getPackageName()); SignAPK.sign(jarMap, new BufferedOutputStream(new FileOutputStream(patched))); } catch (Exception e) { return; } } - APKInstall.install(mm, patched); + APKInstall.install(app, patched); progress.dismiss(); } } @@ -88,17 +88,17 @@ public class DlInstallManager { @Override public void onDownloadComplete(File apk, ProgressNotification progress) { - MagiskManager mm = Data.MM(); + App app = App.self; progress.getNotification() .setProgress(0, 0, true) - .setContentTitle(mm.getString(R.string.restore_img_msg)) + .setContentTitle(app.getString(R.string.restore_img_msg)) .setContentText(""); progress.update(); Data.exportPrefs(); // Make it world readable apk.setReadable(true, false); if (ShellUtils.fastCmdResult("pm install " + apk)) - RootUtils.rmAndLaunch(mm.getPackageName(), BuildConfig.APPLICATION_ID); + RootUtils.rmAndLaunch(app.getPackageName(), BuildConfig.APPLICATION_ID); progress.dismiss(); } } diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/DownloadModule.java b/app/src/full/java/com/topjohnwu/magisk/utils/DownloadModule.java similarity index 80% rename from app/src/full/java/com/topjohnwu/magisk/asyncs/DownloadModule.java rename to app/src/full/java/com/topjohnwu/magisk/utils/DownloadModule.java index 221d282f9..ebf642467 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/DownloadModule.java +++ b/app/src/full/java/com/topjohnwu/magisk/utils/DownloadModule.java @@ -1,17 +1,16 @@ -package com.topjohnwu.magisk.asyncs; +package com.topjohnwu.magisk.utils; -import android.Manifest; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.container.Repo; +import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.FlashActivity; -import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.components.BaseActivity; import com.topjohnwu.magisk.components.ProgressNotification; -import com.topjohnwu.magisk.container.Repo; import com.topjohnwu.net.Networking; import com.topjohnwu.superuser.ShellUtils; @@ -28,26 +27,25 @@ import java.util.zip.ZipOutputStream; public class DownloadModule { public static void exec(BaseActivity activity, Repo repo, boolean install) { - activity.runWithPermission(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, - () -> AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> dlProcessInstall(repo, install))); + activity.runWithExternalRW(() -> AsyncTask.THREAD_POOL_EXECUTOR.execute( + () -> dlProcessInstall(repo, install))); } private static void dlProcessInstall(Repo repo, boolean install) { File output = new File(Const.EXTERNAL_PATH, repo.getDownloadFilename()); ProgressNotification progress = new ProgressNotification(output.getName()); try { - MagiskManager mm = Data.MM(); InputStream in = Networking.get(repo.getZipUrl()) .setDownloadProgressListener(progress) .execForInputStream().getResult(); removeTopFolder(in, new BufferedOutputStream(new FileOutputStream(output))); if (install) { progress.dismiss(); - Intent intent = new Intent(mm, Data.classMap.get(FlashActivity.class)); + Intent intent = new Intent(App.self, ClassMap.get(FlashActivity.class)); intent.setData(Uri.fromFile(output)) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP); - mm.startActivity(intent); + App.self.startActivity(intent); } else { progress.getNotification().setContentTitle(output.getName()); progress.dlDone(); diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/FingerprintHelper.java b/app/src/full/java/com/topjohnwu/magisk/utils/FingerprintHelper.java index e1382e3b6..2a9e7a64c 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/FingerprintHelper.java +++ b/app/src/full/java/com/topjohnwu/magisk/utils/FingerprintHelper.java @@ -16,9 +16,9 @@ import android.security.keystore.KeyProperties; import android.view.Gravity; import android.widget.Toast; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.components.CustomAlertDialog; @@ -36,10 +36,9 @@ public abstract class FingerprintHelper { private CancellationSignal cancel; public static boolean useFingerPrint() { - MagiskManager mm = Data.MM(); - boolean fp = mm.mDB.getSettings(Const.Key.SU_FINGERPRINT, 0) != 0; + boolean fp = App.self.mDB.getSettings(Const.Key.SU_FINGERPRINT, 0) != 0; if (fp && !canUseFingerprint()) { - mm.mDB.setSettings(Const.Key.SU_FINGERPRINT, 0); + App.self.mDB.setSettings(Const.Key.SU_FINGERPRINT, 0); fp = false; } return fp; @@ -48,9 +47,8 @@ public abstract class FingerprintHelper { public static boolean canUseFingerprint() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false; - MagiskManager mm = Data.MM(); - KeyguardManager km = mm.getSystemService(KeyguardManager.class); - FingerprintManager fm = mm.getSystemService(FingerprintManager.class); + KeyguardManager km = App.self.getSystemService(KeyguardManager.class); + FingerprintManager fm = App.self.getSystemService(FingerprintManager.class); return km.isKeyguardSecure() && fm != null && fm.isHardwareDetected() && fm.hasEnrolledFingerprints(); } @@ -106,7 +104,7 @@ public abstract class FingerprintHelper { protected FingerprintHelper() throws Exception { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); - manager = Data.MM().getSystemService(FingerprintManager.class); + manager = App.self.getSystemService(FingerprintManager.class); cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7); diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/PatchAPK.java b/app/src/full/java/com/topjohnwu/magisk/utils/PatchAPK.java similarity index 89% rename from app/src/full/java/com/topjohnwu/magisk/asyncs/PatchAPK.java rename to app/src/full/java/com/topjohnwu/magisk/utils/PatchAPK.java index 31feb5652..8cb43bda9 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/PatchAPK.java +++ b/app/src/full/java/com/topjohnwu/magisk/utils/PatchAPK.java @@ -1,16 +1,16 @@ -package com.topjohnwu.magisk.asyncs; +package com.topjohnwu.magisk.utils; import android.os.AsyncTask; import android.widget.Toast; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.RootUtils; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.BuildConfig; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.components.Notifications; -import com.topjohnwu.magisk.utils.RootUtils; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.ShellUtils; import com.topjohnwu.utils.JarMap; import com.topjohnwu.utils.SignAPK; @@ -95,14 +95,14 @@ public class PatchAPK { } private static boolean patchAndHide() { - MagiskManager mm = Data.MM(); + App app = App.self; // Generate a new app with random package name - File repack = new File(mm.getFilesDir(), "patched.apk"); + File repack = new File(app.getFilesDir(), "patched.apk"); String pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length()); try { - JarMap apk = new JarMap(mm.getPackageCodePath()); + JarMap apk = new JarMap(app.getPackageCodePath()); if (!patch(apk, pkg)) return false; SignAPK.sign(apk, new BufferedOutputStream(new FileOutputStream(repack))); @@ -115,7 +115,7 @@ public class PatchAPK { if (!ShellUtils.fastCmdResult("pm install " + repack)) return false;; - mm.mDB.setStrings(Const.Key.SU_MANAGER, pkg); + app.mDB.setStrings(Const.Key.SU_MANAGER, pkg); Data.exportPrefs(); RootUtils.rmAndLaunch(BuildConfig.APPLICATION_ID, pkg); @@ -143,10 +143,10 @@ public class PatchAPK { public static void hideManager() { AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { - MagiskManager mm = Data.MM(); + App app = App.self; NotificationCompat.Builder progress = - Notifications.progress(mm.getString(R.string.hide_manager_title)); - NotificationManagerCompat mgr = NotificationManagerCompat.from(mm); + Notifications.progress(app.getString(R.string.hide_manager_title)); + NotificationManagerCompat mgr = NotificationManagerCompat.from(app); mgr.notify(Const.ID.HIDE_MANAGER_NOTIFICATION_ID, progress.build()); boolean b = patchAndHide(); mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID); diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/SuConnector.java b/app/src/full/java/com/topjohnwu/magisk/utils/SuConnector.java index 6dac1b811..9133a5c6c 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/SuConnector.java +++ b/app/src/full/java/com/topjohnwu/magisk/utils/SuConnector.java @@ -9,12 +9,13 @@ import android.os.Process; import android.text.TextUtils; import android.widget.Toast; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.container.Policy; +import com.topjohnwu.core.container.SuLogEntry; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.container.Policy; -import com.topjohnwu.magisk.container.SuLogEntry; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -76,8 +77,8 @@ public abstract class SuConnector { if (fromUid < 0) return; if (fromUid == Process.myUid()) return; - MagiskManager mm = Data.MM(); - PackageManager pm = mm.getPackageManager(); + App app = App.self; + PackageManager pm = app.getPackageManager(); Policy policy; boolean notify; @@ -91,7 +92,7 @@ public abstract class SuConnector { } } else { // Doesn't report whether notify or not, check database ourselves - policy = mm.mDB.getPolicy(fromUid); + policy = app.mDB.getPolicy(fromUid); if (policy == null) return; notify = policy.notification; @@ -116,24 +117,22 @@ public abstract class SuConnector { log.fromPid = pid; log.command = command; log.date = new Date(); - mm.mDB.addLog(log); + app.mDB.addLog(log); } private static void handleNotify(Policy policy) { - MagiskManager mm = Data.MM(); - String message = mm.getString(policy.policy == Policy.ALLOW ? + String message = App.self.getString(policy.policy == Policy.ALLOW ? R.string.su_allow_toast : R.string.su_deny_toast, policy.appName); if (policy.notification && Data.suNotificationType == Const.Value.NOTIFICATION_TOAST) Utils.toast(message, Toast.LENGTH_SHORT); } public static void handleNotify(Intent intent) { - MagiskManager mm = Data.MM(); int fromUid = intent.getIntExtra("from.uid", -1); if (fromUid < 0) return; if (fromUid == Process.myUid()) return; try { - Policy policy = new Policy(fromUid, mm.getPackageManager()); + Policy policy = new Policy(fromUid, App.self.getPackageManager()); policy.policy = intent.getIntExtra("policy", -1); if (policy.policy >= 0) handleNotify(policy); diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Download.java b/app/src/main/java/com/topjohnwu/magisk/utils/Download.java index b917918cd..91002ad8c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Download.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Download.java @@ -6,12 +6,6 @@ import android.net.NetworkInfo; public class Download { - public static String getLegalFilename(CharSequence filename) { - return filename.toString().replace(" ", "_").replace("'", "").replace("\"", "") - .replace("$", "").replace("`", "").replace("*", "").replace("/", "_") - .replace("#", "").replace("@", "").replace("\\", "_"); - } - public static boolean checkNetworkStatus(Context context) { ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); diff --git a/build.py b/build.py index 131291f1f..b49be3409 100755 --- a/build.py +++ b/build.py @@ -242,7 +242,7 @@ def build_apk(args, flavor): def build_app(args): source = os.path.join('scripts', 'util_functions.sh') - target = os.path.join('app', 'src', 'full', 'res', 'raw', 'util_functions.sh') + target = os.path.join('core', 'src', 'main', 'res', 'raw', 'util_functions.sh') cp(source, target) build_apk(args, 'Full') diff --git a/core/.gitignore b/core/.gitignore new file mode 100644 index 000000000..512bf037e --- /dev/null +++ b/core/.gitignore @@ -0,0 +1,2 @@ +/build +src/main/res/raw/util_functions.sh diff --git a/core/build.gradle b/core/build.gradle new file mode 100644 index 000000000..cc266479a --- /dev/null +++ b/core/build.gradle @@ -0,0 +1,33 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + + defaultConfig { + minSdkVersion 16 + targetSdkVersion rootProject.ext.compileSdkVersion + versionCode 1 + versionName "1.0" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':net') + implementation project(':utils') + implementation 'com.github.topjohnwu:libsu:2.1.2' + implementation 'org.kamranzafar:jtar:2.3' +} diff --git a/core/proguard-rules.pro b/core/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/core/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml new file mode 100644 index 000000000..54ffe8311 --- /dev/null +++ b/core/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/app/src/full/java/com/topjohnwu/magisk/MagiskManager.java b/core/src/main/java/com/topjohnwu/core/App.java similarity index 67% rename from app/src/full/java/com/topjohnwu/magisk/MagiskManager.java rename to core/src/main/java/com/topjohnwu/core/App.java index 6cf8c9d6c..35751db8d 100644 --- a/app/src/full/java/com/topjohnwu/magisk/MagiskManager.java +++ b/core/src/main/java/com/topjohnwu/core/App.java @@ -1,30 +1,31 @@ -package com.topjohnwu.magisk; +package com.topjohnwu.core; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.os.Handler; +import android.os.Looper; import android.preference.PreferenceManager; -import com.topjohnwu.magisk.database.MagiskDB; -import com.topjohnwu.magisk.database.RepoDatabaseHelper; -import com.topjohnwu.magisk.utils.LocaleManager; -import com.topjohnwu.magisk.utils.RootUtils; +import com.topjohnwu.core.database.MagiskDB; +import com.topjohnwu.core.database.RepoDatabaseHelper; +import com.topjohnwu.core.utils.LocaleManager; +import com.topjohnwu.core.utils.RootUtils; import com.topjohnwu.superuser.ContainerApp; import com.topjohnwu.superuser.Shell; -import java.lang.ref.WeakReference; +public class App extends ContainerApp { -public class MagiskManager extends ContainerApp { - - // Info - public boolean hasInit = false; + public static App self; + public static Handler mainHandler = new Handler(Looper.getMainLooper()); + public boolean init = false; // Global resources public SharedPreferences prefs; - public RepoDatabaseHelper repoDB; public MagiskDB mDB; + public RepoDatabaseHelper repoDB; - public MagiskManager() { - Data.weakApp = new WeakReference<>(this); + public App() { + self = this; } @Override @@ -37,8 +38,8 @@ public class MagiskManager extends ContainerApp { Shell.Config.setTimeout(2); prefs = PreferenceManager.getDefaultSharedPreferences(this); - repoDB = new RepoDatabaseHelper(this); mDB = new MagiskDB(this); + repoDB = new RepoDatabaseHelper(this); LocaleManager.setLocale(this); Data.loadConfig(); diff --git a/app/src/full/java/com/topjohnwu/magisk/Const.java b/core/src/main/java/com/topjohnwu/core/Const.java similarity index 99% rename from app/src/full/java/com/topjohnwu/magisk/Const.java rename to core/src/main/java/com/topjohnwu/core/Const.java index cf31dd1c5..16544a635 100644 --- a/app/src/full/java/com/topjohnwu/magisk/Const.java +++ b/core/src/main/java/com/topjohnwu/core/Const.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk; +package com.topjohnwu.core; import android.os.Environment; import android.os.Process; @@ -39,7 +39,7 @@ public class Const { /* A list of apps that should not be shown as hide-able */ public static final List HIDE_BLACKLIST = Arrays.asList( - Data.MM().getPackageName(), + App.self.getPackageName(), "com.google.android.gms" ); diff --git a/app/src/full/java/com/topjohnwu/magisk/Data.java b/core/src/main/java/com/topjohnwu/core/Data.java similarity index 70% rename from app/src/full/java/com/topjohnwu/magisk/Data.java rename to core/src/main/java/com/topjohnwu/core/Data.java index ecdb47c4f..04778ad72 100644 --- a/app/src/full/java/com/topjohnwu/magisk/Data.java +++ b/core/src/main/java/com/topjohnwu/core/Data.java @@ -1,16 +1,9 @@ -package com.topjohnwu.magisk; +package com.topjohnwu.core; import android.content.SharedPreferences; -import android.os.Handler; -import android.os.Looper; import android.util.Xml; -import com.topjohnwu.magisk.components.AboutCardRow; -import com.topjohnwu.magisk.receivers.GeneralReceiver; -import com.topjohnwu.magisk.receivers.ShortcutReceiver; -import com.topjohnwu.magisk.services.OnBootService; -import com.topjohnwu.magisk.services.UpdateCheckService; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; import com.topjohnwu.superuser.io.SuFile; @@ -21,15 +14,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.IOException; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Map; public class Data { - // Global app instance - public static WeakReference weakApp; - public static Handler mainHandler = new Handler(Looper.getMainLooper()); - public static Map classMap = new HashMap<>(); // Current status public static String magiskVersionString; @@ -55,29 +41,12 @@ public class Data { // Configs public static boolean isDarkTheme; public static int suRequestTimeout; - public static int suLogTimeout = 14; public static int multiuserState = -1; public static int suResponseType; public static int suNotificationType; public static int updateChannel; public static int repoOrder; - - static { - classMap.put(MagiskManager.class, a.q.class); - classMap.put(MainActivity.class, a.b.class); - classMap.put(SplashActivity.class, a.c.class); - classMap.put(AboutActivity.class, a.d.class); - classMap.put(DonationActivity.class, a.e.class); - classMap.put(FlashActivity.class, a.f.class); - classMap.put(NoUIActivity.class, a.g.class); - classMap.put(GeneralReceiver.class, a.h.class); - classMap.put(ShortcutReceiver.class, a.i.class); - classMap.put(OnBootService.class, a.j.class); - classMap.put(UpdateCheckService.class, a.k.class); - classMap.put(AboutCardRow.class, a.l.class); - classMap.put(SuRequestActivity.class, a.m.class); - - } + public static int suLogTimeout = 14; public static void loadMagiskInfo() { try { @@ -87,24 +56,19 @@ public class Data { } catch (NumberFormatException ignored) {} } - public static MagiskManager MM() { - return weakApp.get(); - } - public static void exportPrefs() { // Flush prefs to disk - MagiskManager mm = MM(); - mm.prefs.edit().commit(); - File xml = new File(mm.getFilesDir().getParent() + "/shared_prefs", - mm.getPackageName() + "_preferences.xml"); + App app = App.self; + app.prefs.edit().commit(); + File xml = new File(app.getFilesDir().getParent() + "/shared_prefs", + app.getPackageName() + "_preferences.xml"); Shell.su(Utils.fmt("cat %s > /data/user/0/%s", xml, Const.MANAGER_CONFIGS)).exec(); } public static void importPrefs() { - MagiskManager mm = MM(); SuFile config = new SuFile("/data/user/0/" + Const.MANAGER_CONFIGS); if (config.exists()) { - SharedPreferences.Editor editor = mm.prefs.edit(); + SharedPreferences.Editor editor = App.self.prefs.edit(); try { SuFileInputStream is = new SuFileInputStream(config); XmlPullParser parser = Xml.newPullParser(); @@ -162,20 +126,20 @@ public class Data { } public static void loadConfig() { - MagiskManager mm = MM(); + App app = App.self; // su - suRequestTimeout = Utils.getPrefsInt(mm.prefs, Const.Key.SU_REQUEST_TIMEOUT, Const.Value.timeoutList[2]); - suResponseType = Utils.getPrefsInt(mm.prefs, Const.Key.SU_AUTO_RESPONSE, Const.Value.SU_PROMPT); - suNotificationType = Utils.getPrefsInt(mm.prefs, Const.Key.SU_NOTIFICATION, Const.Value.NOTIFICATION_TOAST); + suRequestTimeout = Utils.getPrefsInt(app.prefs, Const.Key.SU_REQUEST_TIMEOUT, Const.Value.timeoutList[2]); + suResponseType = Utils.getPrefsInt(app.prefs, Const.Key.SU_AUTO_RESPONSE, Const.Value.SU_PROMPT); + suNotificationType = Utils.getPrefsInt(app.prefs, Const.Key.SU_NOTIFICATION, Const.Value.NOTIFICATION_TOAST); // config - isDarkTheme = mm.prefs.getBoolean(Const.Key.DARK_THEME, false); - updateChannel = Utils.getPrefsInt(mm.prefs, Const.Key.UPDATE_CHANNEL, Const.Value.STABLE_CHANNEL); - repoOrder = mm.prefs.getInt(Const.Key.REPO_ORDER, Const.Value.ORDER_DATE); + isDarkTheme = app.prefs.getBoolean(Const.Key.DARK_THEME, false); + updateChannel = Utils.getPrefsInt(app.prefs, Const.Key.UPDATE_CHANNEL, Const.Value.STABLE_CHANNEL); + repoOrder = app.prefs.getInt(Const.Key.REPO_ORDER, Const.Value.ORDER_DATE); } public static void writeConfig() { - MM().prefs.edit() + App.self.prefs.edit() .putBoolean(Const.Key.DARK_THEME, isDarkTheme) .putBoolean(Const.Key.MAGISKHIDE, magiskHide) .putBoolean(Const.Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists()) diff --git a/app/src/full/java/com/topjohnwu/magisk/container/BaseModule.java b/core/src/main/java/com/topjohnwu/core/container/BaseModule.java similarity index 98% rename from app/src/full/java/com/topjohnwu/magisk/container/BaseModule.java rename to core/src/main/java/com/topjohnwu/core/container/BaseModule.java index aa2576b5c..167f84447 100644 --- a/app/src/full/java/com/topjohnwu/magisk/container/BaseModule.java +++ b/core/src/main/java/com/topjohnwu/core/container/BaseModule.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.container; +package com.topjohnwu.core.container; import android.content.ContentValues; import android.database.Cursor; diff --git a/app/src/full/java/com/topjohnwu/magisk/container/Module.java b/core/src/main/java/com/topjohnwu/core/container/Module.java similarity index 97% rename from app/src/full/java/com/topjohnwu/magisk/container/Module.java rename to core/src/main/java/com/topjohnwu/core/container/Module.java index 04b040b45..48ff50ab4 100644 --- a/app/src/full/java/com/topjohnwu/magisk/container/Module.java +++ b/core/src/main/java/com/topjohnwu/core/container/Module.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.container; +package com.topjohnwu.core.container; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.io.SuFile; diff --git a/app/src/full/java/com/topjohnwu/magisk/container/Policy.java b/core/src/main/java/com/topjohnwu/core/container/Policy.java similarity index 96% rename from app/src/full/java/com/topjohnwu/magisk/container/Policy.java rename to core/src/main/java/com/topjohnwu/core/container/Policy.java index 3897ab5dc..76fc32f2d 100644 --- a/app/src/full/java/com/topjohnwu/magisk/container/Policy.java +++ b/core/src/main/java/com/topjohnwu/core/container/Policy.java @@ -1,10 +1,10 @@ -package com.topjohnwu.magisk.container; +package com.topjohnwu.core.container; import android.content.ContentValues; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.core.utils.Utils; import androidx.annotation.NonNull; diff --git a/app/src/full/java/com/topjohnwu/magisk/container/Repo.java b/core/src/main/java/com/topjohnwu/core/container/Repo.java similarity index 87% rename from app/src/full/java/com/topjohnwu/magisk/container/Repo.java rename to core/src/main/java/com/topjohnwu/core/container/Repo.java index 18fc26e3d..8db237a28 100644 --- a/app/src/full/java/com/topjohnwu/magisk/container/Repo.java +++ b/core/src/main/java/com/topjohnwu/core/container/Repo.java @@ -1,12 +1,11 @@ -package com.topjohnwu.magisk.container; +package com.topjohnwu.core.container; import android.content.ContentValues; import android.database.Cursor; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.utils.Download; -import com.topjohnwu.magisk.utils.Logger; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.utils.Logger; +import com.topjohnwu.core.utils.Utils; import java.text.DateFormat; import java.util.Date; @@ -73,7 +72,7 @@ public class Repo extends BaseModule { } public String getDownloadFilename() { - return Download.getLegalFilename(getName() + "-" + getVersion() + ".zip"); + return Utils.getLegalFilename(getName() + "-" + getVersion() + ".zip"); } public class IllegalRepoException extends Exception { diff --git a/app/src/full/java/com/topjohnwu/magisk/container/SuLogEntry.java b/core/src/main/java/com/topjohnwu/core/container/SuLogEntry.java similarity index 95% rename from app/src/full/java/com/topjohnwu/magisk/container/SuLogEntry.java rename to core/src/main/java/com/topjohnwu/core/container/SuLogEntry.java index 2638105f4..04cfc56e9 100644 --- a/app/src/full/java/com/topjohnwu/magisk/container/SuLogEntry.java +++ b/core/src/main/java/com/topjohnwu/core/container/SuLogEntry.java @@ -1,8 +1,8 @@ -package com.topjohnwu.magisk.container; +package com.topjohnwu.core.container; import android.content.ContentValues; -import com.topjohnwu.magisk.utils.LocaleManager; +import com.topjohnwu.core.utils.LocaleManager; import java.text.DateFormat; import java.text.SimpleDateFormat; diff --git a/app/src/full/java/com/topjohnwu/magisk/container/TarEntry.java b/core/src/main/java/com/topjohnwu/core/container/TarEntry.java similarity index 98% rename from app/src/full/java/com/topjohnwu/magisk/container/TarEntry.java rename to core/src/main/java/com/topjohnwu/core/container/TarEntry.java index 2a09ddd39..4813444f3 100644 --- a/app/src/full/java/com/topjohnwu/magisk/container/TarEntry.java +++ b/core/src/main/java/com/topjohnwu/core/container/TarEntry.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.container; +package com.topjohnwu.core.container; import org.kamranzafar.jtar.TarHeader; diff --git a/app/src/full/java/com/topjohnwu/magisk/container/ValueSortedMap.java b/core/src/main/java/com/topjohnwu/core/container/ValueSortedMap.java similarity index 95% rename from app/src/full/java/com/topjohnwu/magisk/container/ValueSortedMap.java rename to core/src/main/java/com/topjohnwu/core/container/ValueSortedMap.java index 23be3c4d0..cca2717d0 100644 --- a/app/src/full/java/com/topjohnwu/magisk/container/ValueSortedMap.java +++ b/core/src/main/java/com/topjohnwu/core/container/ValueSortedMap.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.container; +package com.topjohnwu.core.container; import java.util.ArrayList; import java.util.Collection; diff --git a/app/src/full/java/com/topjohnwu/magisk/database/MagiskDB.java b/core/src/main/java/com/topjohnwu/core/database/MagiskDB.java similarity index 94% rename from app/src/full/java/com/topjohnwu/magisk/database/MagiskDB.java rename to core/src/main/java/com/topjohnwu/core/database/MagiskDB.java index 871e8769f..263d01cd9 100644 --- a/app/src/full/java/com/topjohnwu/magisk/database/MagiskDB.java +++ b/core/src/main/java/com/topjohnwu/core/database/MagiskDB.java @@ -1,16 +1,16 @@ -package com.topjohnwu.magisk.database; +package com.topjohnwu.core.database; import android.content.ContentValues; import android.content.Context; import android.content.pm.PackageManager; import android.text.TextUtils; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.container.Policy; -import com.topjohnwu.magisk.container.SuLogEntry; -import com.topjohnwu.magisk.utils.LocaleManager; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.container.Policy; +import com.topjohnwu.core.container.SuLogEntry; +import com.topjohnwu.core.utils.LocaleManager; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.superuser.Shell; import java.text.DateFormat; @@ -23,7 +23,7 @@ import java.util.Map; public class MagiskDB { private static final String POLICY_TABLE = "policies"; - private static final String LOG_TABLE = "logs"; + private static final String LOG_TABLE = "err"; private static final String SETTINGS_TABLE = "settings"; private static final String STRINGS_TABLE = "strings"; diff --git a/app/src/full/java/com/topjohnwu/magisk/database/RepoDatabaseHelper.java b/core/src/main/java/com/topjohnwu/core/database/RepoDatabaseHelper.java similarity index 84% rename from app/src/full/java/com/topjohnwu/magisk/database/RepoDatabaseHelper.java rename to core/src/main/java/com/topjohnwu/core/database/RepoDatabaseHelper.java index d50375f6a..f29c285c7 100644 --- a/app/src/full/java/com/topjohnwu/magisk/database/RepoDatabaseHelper.java +++ b/core/src/main/java/com/topjohnwu/core/database/RepoDatabaseHelper.java @@ -1,15 +1,14 @@ -package com.topjohnwu.magisk.database; +package com.topjohnwu.core.database; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.adapters.ReposAdapter; -import com.topjohnwu.magisk.container.Repo; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.container.Repo; import java.util.HashSet; import java.util.Set; @@ -20,12 +19,10 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper { private static final String TABLE_NAME = "repos"; private SQLiteDatabase mDb; - private MagiskManager mm; - private ReposAdapter adapter; + private Runnable adapterCb; public RepoDatabaseHelper(Context context) { super(context, "repo.db", null, DATABASE_VER); - mm = Data.MM(); mDb = getWritableDatabase(); // Remove outdated repos @@ -46,7 +43,7 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper { "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " + "(id TEXT, name TEXT, version TEXT, versionCode INT, minMagisk INT, " + "author TEXT, description TEXT, last_update INT, PRIMARY KEY(id))"); - mm.prefs.edit().remove(Const.Key.ETAG_KEY).apply(); + App.self.prefs.edit().remove(Const.Key.ETAG_KEY).apply(); } } @@ -120,17 +117,17 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper { return set; } - public void registerAdapter(ReposAdapter a) { - adapter = a; + public void registerAdapterCallback(Runnable cb) { + adapterCb = cb; } - public void unregisterAdapter() { - adapter = null; + public void unregisterAdapterCallback() { + adapterCb = null; } private void notifyAdapter() { - if (adapter != null) { - Data.mainHandler.post(adapter::notifyDBChanged); + if (adapterCb != null) { + App.mainHandler.post(adapterCb); } } } diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java b/core/src/main/java/com/topjohnwu/core/tasks/CheckUpdates.java similarity index 81% rename from app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java rename to core/src/main/java/com/topjohnwu/core/tasks/CheckUpdates.java index 5971df0c3..8d43c836f 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java +++ b/core/src/main/java/com/topjohnwu/core/tasks/CheckUpdates.java @@ -1,10 +1,9 @@ -package com.topjohnwu.magisk.asyncs; +package com.topjohnwu.core.tasks; -import com.topjohnwu.magisk.BuildConfig; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.components.Notifications; -import com.topjohnwu.magisk.utils.Topic; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.utils.Topic; import com.topjohnwu.net.Networking; import com.topjohnwu.net.ResponseListener; @@ -51,7 +50,7 @@ public class CheckUpdates { url = Const.Url.BETA_URL; break; case Const.Value.CUSTOM_CHANNEL: - url = Data.MM().prefs.getString(Const.Key.CUSTOM_CHANNEL, ""); + url = App.self.prefs.getString(Const.Key.CUSTOM_CHANNEL, ""); break; default: return; @@ -89,15 +88,10 @@ public class CheckUpdates { JSONObject uninstaller = getJson(json, "uninstaller"); Data.uninstallerLink = getString(uninstaller, "link", null); - if (cb != null) { - if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) { - Notifications.managerUpdate(); - } else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) { - Notifications.magiskUpdate(); - } - cb.run(); - } Topic.publish(Topic.UPDATE_CHECK_DONE); + + if (cb != null) + cb.run(); } } } diff --git a/core/src/main/java/com/topjohnwu/core/tasks/FlashZip.java b/core/src/main/java/com/topjohnwu/core/tasks/FlashZip.java new file mode 100644 index 000000000..577960a7f --- /dev/null +++ b/core/src/main/java/com/topjohnwu/core/tasks/FlashZip.java @@ -0,0 +1,83 @@ +package com.topjohnwu.core.tasks; + +import android.net.Uri; +import android.os.AsyncTask; + +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.utils.Utils; +import com.topjohnwu.core.utils.ZipUtils; +import com.topjohnwu.superuser.Shell; +import com.topjohnwu.superuser.ShellUtils; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; + +public abstract class FlashZip { + + private Uri mUri; + private File tmpFile; + private List console, logs; + + public FlashZip(Uri uri, List out, List err) { + mUri = uri; + console = out; + logs = err; + tmpFile = new File(App.self.getCacheDir(), "install.zip"); + } + + private boolean unzipAndCheck() throws IOException { + ZipUtils.unzip(tmpFile, tmpFile.getParentFile(), "META-INF/com/google/android", true); + return ShellUtils.fastCmdResult("grep -q '#MAGISK' " + new File(tmpFile.getParentFile(), "updater-script")); + } + + private boolean flash() throws IOException { + console.add("- Copying zip to temp directory"); + try (InputStream in = App.self.getContentResolver().openInputStream(mUri); + OutputStream out = new BufferedOutputStream(new FileOutputStream(tmpFile))) { + if (in == null) throw new FileNotFoundException(); + InputStream buf= new BufferedInputStream(in); + ShellUtils.pump(buf, out); + } catch (FileNotFoundException e) { + console.add("! Invalid Uri"); + throw e; + } catch (IOException e) { + console.add("! Cannot copy to cache"); + throw e; + } + try { + if (!unzipAndCheck()) { + console.add("! This zip is not a Magisk Module!"); + return false; + } + } catch (IOException e) { + console.add("! Unzip error"); + throw e; + } + console.add("- Installing " + Utils.getNameFromUri(App.self, mUri)); + return Shell.su("cd " + tmpFile.getParent(), + "BOOTMODE=true sh update-binary dummy 1 " + tmpFile) + .to(console, logs) + .exec().isSuccess(); + } + + public void exec() { + AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { + boolean success = false; + try { + success = flash(); + } catch (IOException ignored) {} + Shell.su("cd /", "rm -rf " + tmpFile.getParent() + " " + Const.TMP_FOLDER_PATH).submit(); + onResult(success); + }); + } + + protected abstract void onResult(boolean success); +} diff --git a/core/src/main/java/com/topjohnwu/core/tasks/MagiskInstaller.java b/core/src/main/java/com/topjohnwu/core/tasks/MagiskInstaller.java new file mode 100644 index 000000000..256efed34 --- /dev/null +++ b/core/src/main/java/com/topjohnwu/core/tasks/MagiskInstaller.java @@ -0,0 +1,288 @@ +package com.topjohnwu.core.tasks; + +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.text.TextUtils; + +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.R; +import com.topjohnwu.core.container.TarEntry; +import com.topjohnwu.core.utils.Utils; +import com.topjohnwu.net.DownloadProgressListener; +import com.topjohnwu.net.Networking; +import com.topjohnwu.superuser.Shell; +import com.topjohnwu.superuser.ShellUtils; +import com.topjohnwu.superuser.internal.NOPList; +import com.topjohnwu.superuser.io.SuFile; +import com.topjohnwu.superuser.io.SuFileInputStream; +import com.topjohnwu.superuser.io.SuFileOutputStream; +import com.topjohnwu.utils.SignBoot; + +import org.kamranzafar.jtar.TarInputStream; +import org.kamranzafar.jtar.TarOutputStream; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import androidx.annotation.MainThread; +import androidx.annotation.WorkerThread; + +public abstract class MagiskInstaller { + + private List console, logs; + protected String srcBoot; + protected File installDir; + + private class ProgressLog implements DownloadProgressListener { + + private int prev = -1; + private int location; + + @Override + public void onProgress(long bytesDownloaded, long totalBytes) { + if (prev < 0) { + location = console.size(); + console.add("... 0%"); + } + int curr = (int) (100 * bytesDownloaded / totalBytes); + if (prev != curr) { + prev = curr; + console.set(location, "... " + prev + "%"); + } + } + } + + protected MagiskInstaller() { + console = NOPList.getInstance(); + logs = NOPList.getInstance(); + } + + public MagiskInstaller(List out, List err) { + console = out; + logs = err; + installDir = new File(Utils.getDEContext().getFilesDir().getParent(), "install"); + Shell.sh("rm -rf " + installDir).exec(); + installDir.mkdirs(); + } + + protected boolean extractZip() { + String arch; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + List abis = Arrays.asList(Build.SUPPORTED_ABIS); + arch = abis.contains("x86") ? "x86" : "arm"; + } else { + arch = TextUtils.equals(Build.CPU_ABI, "x86") ? "x86" : "arm"; + } + + console.add("- Device platform: " + Build.CPU_ABI); + + File zip = new File(App.self.getFilesDir(), "magisk.zip"); + + if (!ShellUtils.checkSum("MD5", zip, Data.magiskMD5)) { + console.add("- Downloading zip"); + Networking.get(Data.magiskLink) + .setDownloadProgressListener(new ProgressLog()) + .execForFile(zip); + } else { + console.add("- Existing zip found"); + } + + try { + ZipInputStream zi = new ZipInputStream(new BufferedInputStream( + new FileInputStream(zip), (int) zip.length())); + ZipEntry ze; + while ((ze = zi.getNextEntry()) != null) { + if (ze.isDirectory()) + continue; + String name = null; + String[] names = { arch + "/", "common/", "META-INF/com/google/android/update-binary" }; + for (String n : names) { + if (ze.getName().startsWith(n)) { + name = ze.getName().substring(ze.getName().lastIndexOf('/') + 1); + break; + } + } + if (name == null && ze.getName().startsWith("chromeos/")) + name = ze.getName(); + if (name == null) + continue; + File dest; + if (installDir instanceof SuFile) { + dest = new SuFile(installDir, name); + } else { + dest = new File(installDir, name); + } + dest.getParentFile().mkdirs(); + try (OutputStream out = new SuFileOutputStream(dest)) { + ShellUtils.pump(zi, out); + } + } + } catch (IOException e) { + console.add("! Cannot unzip zip"); + return false; + } + Shell.sh(Utils.fmt("chmod -R 755 %s/*; %s/magiskinit -x magisk %s/magisk", + installDir, installDir, installDir)).exec(); + return true; + } + + protected boolean copyBoot(Uri bootUri) { + srcBoot = new File(installDir, "boot.img").getPath(); + console.add("- Copying image to cache"); + // Copy boot image to local + try (InputStream in = App.self.getContentResolver().openInputStream(bootUri); + OutputStream out = new FileOutputStream(srcBoot)) { + if (in == null) + throw new FileNotFoundException(); + + InputStream src; + if (Utils.getNameFromUri(App.self, bootUri).endsWith(".tar")) { + // Extract boot.img from tar + TarInputStream tar = new TarInputStream(new BufferedInputStream(in)); + org.kamranzafar.jtar.TarEntry entry; + while ((entry = tar.getNextEntry()) != null) { + if (entry.getName().equals("boot.img")) + break; + } + src = tar; + } else { + // Direct copy raw image + src = new BufferedInputStream(in); + } + ShellUtils.pump(src, out); + } catch (FileNotFoundException e) { + console.add("! Invalid Uri"); + return false; + } catch (IOException e) { + console.add("! Copy failed"); + return false; + } + return true; + } + + protected boolean patchBoot() { + boolean isSigned; + try (InputStream in = new SuFileInputStream(srcBoot)) { + isSigned = SignBoot.verifySignature(in, null); + if (isSigned) { + console.add("- Boot image is signed with AVB 1.0"); + } + } catch (IOException e) { + console.add("! Unable to check signature"); + return false; + } + + // Patch boot image + if (!Shell.sh(Utils.fmt("cd %s; KEEPFORCEENCRYPT=%b KEEPVERITY=%b " + + "sh update-binary indep boot_patch.sh %s", + installDir, Data.keepEnc, Data.keepVerity, srcBoot)) + .to(console, logs).exec().isSuccess()) + return false; + + Shell.Job job = Shell.sh("mv bin/busybox busybox", + "rm -rf magisk.apk bin boot.img update-binary", + "cd /"); + + File patched = new File(installDir, "new-boot.img"); + if (isSigned) { + console.add("- Signing boot image with test keys"); + File signed = new File(installDir, "signed.img"); + try (InputStream in = new SuFileInputStream(patched); + OutputStream out = new BufferedOutputStream(new FileOutputStream(signed))) { + SignBoot.doSignature("/boot", in, out, null, null); + } catch (IOException e) { + return false; + } + job.add("mv -f " + signed + " " + patched); + } + job.exec(); + return true; + } + + protected boolean flashBoot() { + if (!Shell.su(Utils.fmt("direct_install %s %s", installDir, srcBoot)) + .to(console, logs).exec().isSuccess()) + return false; + if (!Data.keepVerity) + Shell.su("find_dtbo_image", "patch_dtbo_image").to(console, logs).exec(); + return true; + } + + protected boolean storeBoot() { + File patched = new File(installDir, "new-boot.img"); + String fmt = App.self.prefs.getString(Const.Key.BOOT_FORMAT, ".img"); + File dest = new File(Const.EXTERNAL_PATH, "patched_boot" + fmt); + dest.getParentFile().mkdirs(); + OutputStream os; + try { + switch (fmt) { + case ".img.tar": + os = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest))); + ((TarOutputStream) os).putNextEntry(new TarEntry(patched, "boot.img")); + break; + default: + case ".img": + os = new BufferedOutputStream(new FileOutputStream(dest)); + break; + } + try (InputStream in = new SuFileInputStream(patched)) { + ShellUtils.pump(in, os); + os.close(); + } + } catch (IOException e) { + console.add("! Failed to store boot to " + dest); + return false; + } + Shell.sh("rm -f " + patched).exec(); + console.add(""); + console.add("****************************"); + console.add(" Patched image is placed in "); + console.add(" " + dest + " "); + console.add("****************************"); + return true; + } + + protected boolean postOTA() { + SuFile bootctl = new SuFile(Const.MAGISK_PATH + "/.core/bootctl"); + try (InputStream in = App.self.getResources().openRawResource(R.raw.bootctl); + OutputStream out = new SuFileOutputStream(bootctl)) { + ShellUtils.pump(in, out); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + Shell.su("post_ota " + bootctl.getParent()).exec(); + console.add("***************************************"); + console.add(" Next reboot will boot to second slot!"); + console.add("***************************************"); + return true; + } + + @WorkerThread + protected abstract boolean operations(); + + @MainThread + protected abstract void onResult(boolean success); + + public void exec() { + AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { + boolean b = operations(); + App.mainHandler.post(() -> onResult(b)); + }); + } + +} diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/ParallelTask.java b/core/src/main/java/com/topjohnwu/core/tasks/ParallelTask.java similarity index 94% rename from app/src/full/java/com/topjohnwu/magisk/asyncs/ParallelTask.java rename to core/src/main/java/com/topjohnwu/core/tasks/ParallelTask.java index e7049c848..a230ce136 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/ParallelTask.java +++ b/core/src/main/java/com/topjohnwu/core/tasks/ParallelTask.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.asyncs; +package com.topjohnwu.core.tasks; import android.app.Activity; import android.os.AsyncTask; diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/SafetyNet.java b/core/src/main/java/com/topjohnwu/core/tasks/SafetyNet.java similarity index 85% rename from app/src/full/java/com/topjohnwu/magisk/asyncs/SafetyNet.java rename to core/src/main/java/com/topjohnwu/core/tasks/SafetyNet.java index c1477e1b2..1ddb28c4d 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/SafetyNet.java +++ b/core/src/main/java/com/topjohnwu/core/tasks/SafetyNet.java @@ -1,11 +1,11 @@ -package com.topjohnwu.magisk.asyncs; +package com.topjohnwu.core.tasks; import android.app.Activity; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.utils.ISafetyNetHelper; -import com.topjohnwu.magisk.utils.Topic; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.utils.ISafetyNetHelper; +import com.topjohnwu.core.utils.Topic; import com.topjohnwu.net.Networking; import com.topjohnwu.superuser.Shell; @@ -16,7 +16,7 @@ import dalvik.system.DexClassLoader; public class SafetyNet { public static final File EXT_APK = - new File(Data.MM().getFilesDir().getParent() + "/snet", "snet.apk"); + new File(App.self.getFilesDir().getParent() + "/snet", "snet.apk"); private static void dyRun(Activity activity) throws Exception { DexClassLoader loader = new DexClassLoader(EXT_APK.getPath(), EXT_APK.getParent(), diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/UpdateRepos.java b/core/src/main/java/com/topjohnwu/core/tasks/UpdateRepos.java similarity index 82% rename from app/src/full/java/com/topjohnwu/magisk/asyncs/UpdateRepos.java rename to core/src/main/java/com/topjohnwu/core/tasks/UpdateRepos.java index be860219b..1eab8919f 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/UpdateRepos.java +++ b/core/src/main/java/com/topjohnwu/core/tasks/UpdateRepos.java @@ -1,15 +1,14 @@ -package com.topjohnwu.magisk.asyncs; +package com.topjohnwu.core.tasks; import android.database.Cursor; import android.os.AsyncTask; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.container.Repo; -import com.topjohnwu.magisk.utils.Logger; -import com.topjohnwu.magisk.utils.Topic; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.container.Repo; +import com.topjohnwu.core.utils.Logger; +import com.topjohnwu.core.utils.Topic; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.net.Networking; import com.topjohnwu.net.Request; @@ -35,7 +34,7 @@ public class UpdateRepos { private static final int CORE_POOL_SIZE = Math.max(2, CPU_COUNT - 1); private static final DateFormat dateFormat; - private MagiskManager mm; + private App app = App.self; private Set cached; private ExecutorService threadPool; @@ -44,10 +43,6 @@ public class UpdateRepos { dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); } - public UpdateRepos() { - mm = Data.MM(); - } - private void waitTasks() { threadPool.shutdown(); while (true) { @@ -64,17 +59,17 @@ public class UpdateRepos { String id = rawRepo.getString("name"); Date date = dateFormat.parse(rawRepo.getString("pushed_at")); threadPool.execute(() -> { - Repo repo = mm.repoDB.getRepo(id); + Repo repo = app.repoDB.getRepo(id); try { if (repo == null) repo = new Repo(id); else cached.remove(id); repo.update(date); - mm.repoDB.addRepo(repo); + app.repoDB.addRepo(repo); } catch (Repo.IllegalRepoException e) { Logger.debug(e.getMessage()); - mm.repoDB.removeRepo(id); + app.repoDB.removeRepo(id); } }); } @@ -86,7 +81,7 @@ public class UpdateRepos { private boolean loadPage(int page) { Request req = Networking.get(Utils.fmt(Const.Url.REPO_URL, page + 1)); if (page == 0) { - String etag = mm.prefs.getString(Const.Key.ETAG_KEY, null); + String etag = app.prefs.getString(Const.Key.ETAG_KEY, null); if (etag != null) req.addHeaders(Const.Key.IF_NONE_MATCH, etag); } @@ -115,7 +110,7 @@ public class UpdateRepos { String etag = res.getConnection().getHeaderField(Const.Key.ETAG_KEY); if (etag != null) { etag = etag.substring(etag.indexOf('\"'), etag.lastIndexOf('\"') + 1); - mm.prefs.edit().putString(Const.Key.ETAG_KEY, etag).apply(); + app.prefs.edit().putString(Const.Key.ETAG_KEY, etag).apply(); } } @@ -128,16 +123,16 @@ public class UpdateRepos { } private void fullReload() { - Cursor c = mm.repoDB.getRawCursor(); + Cursor c = app.repoDB.getRawCursor(); while (c.moveToNext()) { Repo repo = new Repo(c); threadPool.execute(() -> { try { repo.update(); - mm.repoDB.addRepo(repo); + app.repoDB.addRepo(repo); } catch (Repo.IllegalRepoException e) { Logger.debug(e.getMessage()); - mm.repoDB.removeRepo(repo); + app.repoDB.removeRepo(repo); } }); } @@ -147,13 +142,13 @@ public class UpdateRepos { public void exec(boolean force) { Topic.reset(Topic.REPO_LOAD_DONE); AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { - cached = Collections.synchronizedSet(mm.repoDB.getRepoIDSet()); + cached = Collections.synchronizedSet(app.repoDB.getRepoIDSet()); threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE); if (loadPages()) { waitTasks(); // The leftover cached means they are removed from online repo - mm.repoDB.removeRepo(cached); + app.repoDB.removeRepo(cached); } else if (force) { fullReload(); } diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/BootSigner.java b/core/src/main/java/com/topjohnwu/core/utils/BootSigner.java similarity index 97% rename from app/src/full/java/com/topjohnwu/magisk/utils/BootSigner.java rename to core/src/main/java/com/topjohnwu/core/utils/BootSigner.java index 63567599c..107e7c87b 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/BootSigner.java +++ b/core/src/main/java/com/topjohnwu/core/utils/BootSigner.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.core.utils; import com.topjohnwu.utils.SignBoot; diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/ISafetyNetHelper.java b/core/src/main/java/com/topjohnwu/core/utils/ISafetyNetHelper.java similarity index 88% rename from app/src/full/java/com/topjohnwu/magisk/utils/ISafetyNetHelper.java rename to core/src/main/java/com/topjohnwu/core/utils/ISafetyNetHelper.java index 52b6f06c7..f4d89be8e 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/ISafetyNetHelper.java +++ b/core/src/main/java/com/topjohnwu/core/utils/ISafetyNetHelper.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.core.utils; public interface ISafetyNetHelper { diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/LocaleManager.java b/core/src/main/java/com/topjohnwu/core/utils/LocaleManager.java similarity index 77% rename from app/src/full/java/com/topjohnwu/magisk/utils/LocaleManager.java rename to core/src/main/java/com/topjohnwu/core/utils/LocaleManager.java index d4d03daa4..37d3332d8 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/LocaleManager.java +++ b/core/src/main/java/com/topjohnwu/core/utils/LocaleManager.java @@ -1,13 +1,11 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.core.utils; import android.content.res.Configuration; import android.content.res.Resources; import android.os.AsyncTask; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.R; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; import java.util.ArrayList; import java.util.Collections; @@ -22,15 +20,15 @@ public class LocaleManager { public final static Locale defaultLocale = Locale.getDefault(); public static List locales; - public static void setLocale(MagiskManager mm) { - String localeConfig = mm.prefs.getString(Const.Key.LOCALE, ""); + public static void setLocale(App app) { + String localeConfig = app.prefs.getString(Const.Key.LOCALE, ""); if (localeConfig.isEmpty()) { locale = defaultLocale; } else { locale = Locale.forLanguageTag(localeConfig); } Locale.setDefault(locale); - Resources res = mm.getResources(); + Resources res = app.getResources(); Configuration config = res.getConfiguration(); config.setLocale(locale); res.updateConfiguration(config, res.getDisplayMetrics()); @@ -39,18 +37,16 @@ public class LocaleManager { public static String getString(Locale locale, @StringRes int id) { Configuration config = new Configuration(); config.setLocale(locale); - return Data.MM().createConfigurationContext(config).getString(id); + return App.self.createConfigurationContext(config).getString(id); } - public static void loadAvailableLocales() { + public static void loadAvailableLocales(@StringRes int compareId) { AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { locales = new ArrayList<>(); HashSet set = new HashSet<>(); - Resources res = Data.MM().getResources(); + Resources res = App.self.getResources(); Locale locale; - @StringRes int compareId = R.string.download_file_error; - // Add default locale locales.add(Locale.ENGLISH); set.add(getString(Locale.ENGLISH, compareId)); diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/Logger.java b/core/src/main/java/com/topjohnwu/core/utils/Logger.java similarity index 81% rename from app/src/full/java/com/topjohnwu/magisk/utils/Logger.java rename to core/src/main/java/com/topjohnwu/core/utils/Logger.java index 68756e91a..23a53e0fa 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/Logger.java +++ b/core/src/main/java/com/topjohnwu/core/utils/Logger.java @@ -1,9 +1,9 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.core.utils; import android.util.Log; -import com.topjohnwu.magisk.BuildConfig; -import com.topjohnwu.magisk.Const; +import com.topjohnwu.core.BuildConfig; +import com.topjohnwu.core.Const; public class Logger { diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/RootUtils.java b/core/src/main/java/com/topjohnwu/core/utils/RootUtils.java similarity index 91% rename from app/src/full/java/com/topjohnwu/magisk/utils/RootUtils.java rename to core/src/main/java/com/topjohnwu/core/utils/RootUtils.java index ac3e52b02..1fce861ea 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/RootUtils.java +++ b/core/src/main/java/com/topjohnwu/core/utils/RootUtils.java @@ -1,10 +1,10 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.core.utils; import android.content.Context; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.R; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.R; import com.topjohnwu.superuser.BusyBox; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/Topic.java b/core/src/main/java/com/topjohnwu/core/utils/Topic.java similarity index 95% rename from app/src/full/java/com/topjohnwu/magisk/utils/Topic.java rename to core/src/main/java/com/topjohnwu/core/utils/Topic.java index ee22a5913..3ddd7fd4b 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/Topic.java +++ b/core/src/main/java/com/topjohnwu/core/utils/Topic.java @@ -1,6 +1,6 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.core.utils; -import com.topjohnwu.magisk.Data; +import com.topjohnwu.core.App; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -67,7 +67,7 @@ public class Topic { topicList[topic].published = true; } for (Subscriber sub : topicList[topic].subscribers) { - Data.mainHandler.post(() -> sub.onPublish(topic, results)); + App.mainHandler.post(() -> sub.onPublish(topic, results)); } } diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/Utils.java b/core/src/main/java/com/topjohnwu/core/utils/Utils.java similarity index 59% rename from app/src/full/java/com/topjohnwu/magisk/utils/Utils.java rename to core/src/main/java/com/topjohnwu/core/utils/Utils.java index 6dbb72321..b25aadcf3 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/Utils.java +++ b/core/src/main/java/com/topjohnwu/core/utils/Utils.java @@ -1,10 +1,6 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.core.utils; -import android.app.job.JobInfo; -import android.app.job.JobScheduler; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -13,16 +9,15 @@ import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.provider.OpenableColumns; import android.widget.Toast; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Data; -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.container.Module; -import com.topjohnwu.magisk.container.ValueSortedMap; -import com.topjohnwu.magisk.services.UpdateCheckService; +import com.topjohnwu.core.App; +import com.topjohnwu.core.Const; +import com.topjohnwu.core.Data; +import com.topjohnwu.core.container.Module; +import com.topjohnwu.core.container.ValueSortedMap; import com.topjohnwu.net.Networking; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.io.SuFile; @@ -32,6 +27,19 @@ import java.util.Map; public class Utils { + public static void toast(CharSequence msg, int duration) { + App.mainHandler.post(() -> Toast.makeText(App.self, msg, duration).show()); + } + + public static void toast(int resId, int duration) { + App.mainHandler.post(() -> 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))); } @@ -59,7 +67,7 @@ public class Utils { } public static int dpInPx(int dp) { - float scale = Data.MM().getResources().getDisplayMetrics().density; + float scale = App.self.getResources().getDisplayMetrics().density; return (int) (dp * scale + 0.5); } @@ -67,51 +75,23 @@ public class Utils { return String.format(Locale.US, fmt, args); } - public static String dos2unix(String s) { - String newString = s.replace("\r\n", "\n"); - if(!newString.endsWith("\n")) { - return newString + "\n"; - } else { - return newString; - } - } - - public static void setupUpdateCheck() { - MagiskManager mm = Data.MM(); - JobScheduler scheduler = (JobScheduler) mm.getSystemService(Context.JOB_SCHEDULER_SERVICE); - - if (mm.prefs.getBoolean(Const.Key.CHECK_UPDATES, true)) { - if (scheduler.getAllPendingJobs().isEmpty() || - Const.UPDATE_SERVICE_VER > mm.prefs.getInt(Const.Key.UPDATE_SERVICE_VER, -1)) { - ComponentName service = new ComponentName(mm, Data.classMap.get(UpdateCheckService.class)); - JobInfo info = new JobInfo.Builder(Const.ID.UPDATE_SERVICE_ID, service) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) - .setPersisted(true) - .setPeriodic(8 * 60 * 60 * 1000) - .build(); - scheduler.schedule(info); + 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.locale); + res.updateConfiguration(config, res.getDisplayMetrics()); + return res.getString(info.labelRes); } - } else { - scheduler.cancel(Const.UPDATE_SERVICE_VER); - } + } catch (Exception ignored) {} + return info.loadLabel(pm).toString(); } - 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); - } - } - - public static void toast(CharSequence msg, int duration) { - Data.mainHandler.post(() -> Toast.makeText(Data.MM(), msg, duration).show()); - } - - public static void toast(int resId, int duration) { - Data.mainHandler.post(() -> Toast.makeText(Data.MM(), resId, duration).show()); + public static String getLegalFilename(CharSequence filename) { + return filename.toString().replace(" ", "_").replace("'", "").replace("\"", "") + .replace("$", "").replace("`", "").replace("*", "").replace("/", "_") + .replace("#", "").replace("@", "").replace("\\", "_"); } public static void loadModules() { @@ -130,29 +110,16 @@ public class Utils { }); } - 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.locale); - res.updateConfiguration(config, res.getDisplayMetrics()); - return res.getString(info.labelRes); - } - } catch (Exception ignored) {} - return info.loadLabel(pm).toString(); - } - public static boolean showSuperUser() { if (Data.multiuserState < 0) - Data.multiuserState = Data.MM().mDB.getSettings(Const.Key.SU_MULTIUSER_MODE, + Data.multiuserState = App.self.mDB.getSettings(Const.Key.SU_MULTIUSER_MODE, Const.Value.MULTIUSER_MODE_OWNER_ONLY); return Shell.rootAccess() && (Const.USER_ID == 0 || Data.multiuserState != Const.Value.MULTIUSER_MODE_OWNER_MANAGED); } - public static String dlString(String url) { - String s = Networking.get(url).execForString().getResult(); - return s == null ? "" : s; + public static Context getDEContext() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? + App.self.createDeviceProtectedStorageContext() : App.self; } -} \ No newline at end of file +} diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/ZipUtils.java b/core/src/main/java/com/topjohnwu/core/utils/ZipUtils.java similarity index 98% rename from app/src/full/java/com/topjohnwu/magisk/utils/ZipUtils.java rename to core/src/main/java/com/topjohnwu/core/utils/ZipUtils.java index 7203f8d01..733d9ca63 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/ZipUtils.java +++ b/core/src/main/java/com/topjohnwu/core/utils/ZipUtils.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.core.utils; import com.topjohnwu.superuser.ShellUtils; import com.topjohnwu.superuser.io.SuFile; diff --git a/app/src/full/res/raw/bootctl b/core/src/main/res/raw/bootctl similarity index 100% rename from app/src/full/res/raw/bootctl rename to core/src/main/res/raw/bootctl diff --git a/app/src/full/res/raw/nonroot_utils.sh b/core/src/main/res/raw/nonroot_utils.sh similarity index 100% rename from app/src/full/res/raw/nonroot_utils.sh rename to core/src/main/res/raw/nonroot_utils.sh diff --git a/app/src/full/res/raw/utils.sh b/core/src/main/res/raw/utils.sh similarity index 90% rename from app/src/full/res/raw/utils.sh rename to core/src/main/res/raw/utils.sh index 8251208d1..3780dd785 100644 --- a/app/src/full/res/raw/utils.sh +++ b/core/src/main/res/raw/utils.sh @@ -63,9 +63,9 @@ restore_imgs() { post_ota() { cd $1 chmod 755 bootctl - ./bootctl hal-info || return - [ `./bootctl get-current-slot` -eq 0 ] && SLOT_NUM=1 || SLOT_NUM=0 - ./bootctl set-active-boot-slot $SLOT_NUM + ../../../../../app/src/full/res/raw/bootctl hal-info || return + [ `../../../../../app/src/full/res/raw/bootctl get-current-slot` -eq 0 ] && SLOT_NUM=1 || SLOT_NUM=0 + ../../../../../app/src/full/res/raw/bootctl set-active-boot-slot $SLOT_NUM echo '${0%/*}/../bootctl mark-boot-successful;rm -f ${0%/*}/../bootctl $0' > post-fs-data.d/post_ota.sh chmod 755 post-fs-data.d/post_ota.sh cd / diff --git a/settings.gradle b/settings.gradle index 3c9ca144d..f7aace374 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':native', ':utils', ':snet', ':net' +include ':app', ':native', ':utils', ':snet', ':net', ':core'