mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-25 11:05:34 +00:00
Separate backend logic from frontend UI
This commit is contained in:
parent
006d28abd5
commit
ff3d66a661
1
app/.gitignore
vendored
1
app/.gitignore
vendored
@ -6,7 +6,6 @@
|
|||||||
app/release
|
app/release
|
||||||
*.hprof
|
*.hprof
|
||||||
.externalNativeBuild/
|
.externalNativeBuild/
|
||||||
src/full/res/raw/util_functions.sh
|
|
||||||
public.certificate.x509.pem
|
public.certificate.x509.pem
|
||||||
private.key.pk8
|
private.key.pk8
|
||||||
*.apk
|
*.apk
|
||||||
|
@ -73,6 +73,7 @@ dependencies {
|
|||||||
implementation 'androidx.core:core:1.0.1'
|
implementation 'androidx.core:core:1.0.1'
|
||||||
implementation project(':net')
|
implementation project(':net')
|
||||||
fullImplementation project(':utils')
|
fullImplementation project(':utils')
|
||||||
|
fullImplementation project(':core')
|
||||||
fullImplementation 'androidx.appcompat:appcompat:1.0.2'
|
fullImplementation 'androidx.appcompat:appcompat:1.0.2'
|
||||||
fullImplementation "androidx.preference:preference:${rootProject.ext.androidXVersion}"
|
fullImplementation "androidx.preference:preference:${rootProject.ext.androidXVersion}"
|
||||||
fullImplementation "androidx.recyclerview:recyclerview:${rootProject.ext.androidXVersion}"
|
fullImplementation "androidx.recyclerview:recyclerview:${rootProject.ext.androidXVersion}"
|
||||||
|
9
app/proguard-rules.pro
vendored
9
app/proguard-rules.pro
vendored
@ -23,14 +23,11 @@
|
|||||||
-dontwarn javax.naming.**
|
-dontwarn javax.naming.**
|
||||||
|
|
||||||
# Snet extention
|
# Snet extention
|
||||||
-keepclassmembers class com.topjohnwu.magisk.utils.ISafetyNetHelper { *; }
|
-keepclassmembers class com.topjohnwu.core.utils.ISafetyNetHelper { *; }
|
||||||
-keepclassmembers class com.topjohnwu.magisk.utils.BootSigner { *; }
|
-keepclassmembers class com.topjohnwu.core.utils.BootSigner { *; }
|
||||||
|
|
||||||
# Fast Android Networking Library
|
|
||||||
-dontwarn okhttp3.**
|
|
||||||
|
|
||||||
# Strip logging
|
# Strip logging
|
||||||
-assumenosideeffects class com.topjohnwu.magisk.utils.Logger {
|
-assumenosideeffects class com.topjohnwu.core.utils.Logger {
|
||||||
public *** debug(...);
|
public *** debug(...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,9 +40,6 @@
|
|||||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||||
android:screenOrientation="nosensor"
|
android:screenOrientation="nosensor"
|
||||||
android:theme="@style/AppTheme.StatusBar" />
|
android:theme="@style/AppTheme.StatusBar" />
|
||||||
<activity
|
|
||||||
android:name="a.g"
|
|
||||||
android:theme="@style/AppTheme.Translucent" />
|
|
||||||
|
|
||||||
<!-- Superuser -->
|
<!-- Superuser -->
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package a;
|
package a;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.BootSigner;
|
import com.topjohnwu.core.utils.BootSigner;
|
||||||
|
|
||||||
import androidx.annotation.Keep;
|
import androidx.annotation.Keep;
|
||||||
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
package a;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.NoUIActivity;
|
|
||||||
|
|
||||||
public class g extends NoUIActivity {
|
|
||||||
/* stub */
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
package a;
|
package a;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.App;
|
||||||
|
|
||||||
public class q extends MagiskManager {
|
public class q extends App {
|
||||||
/* stub */
|
/* stub */
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,11 @@ import android.os.Bundle;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
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.AboutCardRow;
|
||||||
import com.topjohnwu.magisk.components.BaseActivity;
|
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;
|
import java.util.Locale;
|
||||||
|
|
||||||
@ -62,9 +63,9 @@ public class AboutActivity extends BaseActivity {
|
|||||||
appTranslators.setSummary(translators);
|
appTranslators.setSummary(translators);
|
||||||
}
|
}
|
||||||
|
|
||||||
appSourceCode.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.SOURCE_CODE_URL)));
|
appSourceCode.setOnClickListener(v -> AppUtils.openLink(this, Uri.parse(Const.Url.SOURCE_CODE_URL)));
|
||||||
supportThread.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.XDA_THREAD)));
|
supportThread.setOnClickListener(v -> AppUtils.openLink(this, Uri.parse(Const.Url.XDA_THREAD)));
|
||||||
twitter.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.TWITTER_URL)));
|
twitter.setOnClickListener(v -> AppUtils.openLink(this, Uri.parse(Const.Url.TWITTER_URL)));
|
||||||
|
|
||||||
setFloating();
|
setFloating();
|
||||||
}
|
}
|
||||||
|
34
app/src/full/java/com/topjohnwu/magisk/ClassMap.java
Normal file
34
app/src/full/java/com/topjohnwu/magisk/ClassMap.java
Normal file
@ -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<Class, Class> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,10 @@ package com.topjohnwu.magisk;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.components.AboutCardRow;
|
import com.topjohnwu.magisk.components.AboutCardRow;
|
||||||
import com.topjohnwu.magisk.components.BaseActivity;
|
import com.topjohnwu.magisk.components.BaseActivity;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.AppUtils;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
@ -38,7 +39,7 @@ public class DonationActivity extends BaseActivity {
|
|||||||
ab.setDisplayHomeAsUpEnabled(true);
|
ab.setDisplayHomeAsUpEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
paypal.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.PAYPAL_URL)));
|
paypal.setOnClickListener(v -> AppUtils.openLink(this, Uri.parse(Const.Url.PAYPAL_URL)));
|
||||||
patreon.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.PATREON_URL)));
|
patreon.setOnClickListener(v -> AppUtils.openLink(this, Uri.parse(Const.Url.PATREON_URL)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -12,18 +11,22 @@ import android.widget.ScrollView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.FlashZip;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.asyncs.InstallMagisk;
|
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.components.BaseActivity;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.CallbackList;
|
import com.topjohnwu.superuser.CallbackList;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@ -40,7 +43,7 @@ public class FlashActivity extends BaseActivity {
|
|||||||
@BindView(R.id.reboot) public Button reboot;
|
@BindView(R.id.reboot) public Button reboot;
|
||||||
@BindView(R.id.scrollView) ScrollView sv;
|
@BindView(R.id.scrollView) ScrollView sv;
|
||||||
|
|
||||||
private List<String> logs;
|
private List<String> console, logs;
|
||||||
|
|
||||||
@OnClick(R.id.reboot)
|
@OnClick(R.id.reboot)
|
||||||
void reboot() {
|
void reboot() {
|
||||||
@ -49,7 +52,7 @@ public class FlashActivity extends BaseActivity {
|
|||||||
|
|
||||||
@OnClick(R.id.save_logs)
|
@OnClick(R.id.save_logs)
|
||||||
void saveLogs() {
|
void saveLogs() {
|
||||||
runWithPermission(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, () -> {
|
runWithExternalRW(() -> {
|
||||||
Calendar now = Calendar.getInstance();
|
Calendar now = Calendar.getInstance();
|
||||||
String filename = String.format(Locale.US,
|
String filename = String.format(Locale.US,
|
||||||
"magisk_install_log_%04d%02d%02d_%02d%02d%02d.log",
|
"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
|
@Override
|
||||||
public int getDarkTheme() {
|
public int getDarkTheme() {
|
||||||
return R.style.AppTheme_StatusBar_Dark;
|
return R.style.AppTheme_StatusBar_Dark;
|
||||||
@ -92,8 +106,36 @@ public class FlashActivity extends BaseActivity {
|
|||||||
if (!Shell.rootAccess())
|
if (!Shell.rootAccess())
|
||||||
reboot.setVisibility(View.GONE);
|
reboot.setVisibility(View.GONE);
|
||||||
|
|
||||||
logs = new ArrayList<>();
|
logs = Collections.synchronizedList(new ArrayList<>());
|
||||||
CallbackList<String> console = new CallbackList<String>(new ArrayList<>()) {
|
console = new ConsoleList();
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
Uri uri = intent.getData();
|
||||||
|
|
||||||
|
switch (intent.getStringExtra(Const.Key.FLASH_ACTION)) {
|
||||||
|
case Const.Value.FLASH_ZIP:
|
||||||
|
new FlashModule(uri).exec();
|
||||||
|
break;
|
||||||
|
case Const.Value.UNINSTALL:
|
||||||
|
new Uninstall(uri).exec();
|
||||||
|
break;
|
||||||
|
case Const.Value.FLASH_MAGISK:
|
||||||
|
new DirectInstall().exec();
|
||||||
|
break;
|
||||||
|
case Const.Value.FLASH_INACTIVE_SLOT:
|
||||||
|
new SecondSlot().exec();
|
||||||
|
break;
|
||||||
|
case Const.Value.PATCH_BOOT:
|
||||||
|
new PatchBoot(uri).exec();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ConsoleList extends CallbackList<String> {
|
||||||
|
|
||||||
|
ConsoleList() {
|
||||||
|
super(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
flashLogs.setText(TextUtils.join("\n", this));
|
flashLogs.setText(TextUtils.join("\n", this));
|
||||||
@ -109,60 +151,110 @@ public class FlashActivity extends BaseActivity {
|
|||||||
@Override
|
@Override
|
||||||
public String set(int i, String s) {
|
public String set(int i, String s) {
|
||||||
String ret = super.set(i, s);
|
String ret = super.set(i, s);
|
||||||
Data.mainHandler.post(this::updateUI);
|
App.mainHandler.post(this::updateUI);
|
||||||
return ret;
|
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();
|
|
||||||
break;
|
|
||||||
case Const.Value.UNINSTALL:
|
|
||||||
new UninstallMagisk(this, uri, console, logs).exec();
|
|
||||||
break;
|
|
||||||
case Const.Value.FLASH_MAGISK:
|
|
||||||
new InstallMagisk(this, console, logs, InstallMagisk.DIRECT_MODE).exec();
|
|
||||||
break;
|
|
||||||
case Const.Value.FLASH_INACTIVE_SLOT:
|
|
||||||
new InstallMagisk(this, console, logs, InstallMagisk.SECOND_SLOT_MODE).exec();
|
|
||||||
break;
|
|
||||||
case Const.Value.PATCH_BOOT:
|
|
||||||
new InstallMagisk(this, console, logs,
|
|
||||||
intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT)).exec();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.close)
|
private class FlashModule extends FlashZip {
|
||||||
@Override
|
|
||||||
public void finish() {
|
FlashModule(Uri uri) {
|
||||||
super.finish();
|
super(uri, console, logs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
protected void onResult(boolean success) {
|
||||||
// Prevent user accidentally press back button
|
if (success) {
|
||||||
}
|
Utils.loadModules();
|
||||||
|
|
||||||
private static class UninstallMagisk extends FlashZip {
|
|
||||||
|
|
||||||
private UninstallMagisk(BaseActivity context, Uri uri, List<String> console, List<String> logs) {
|
|
||||||
super(context, uri, console, logs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Integer result) {
|
|
||||||
if (result == 1) {
|
|
||||||
Data.mainHandler.postDelayed(() ->
|
|
||||||
Shell.su("pm uninstall " + getActivity().getPackageName()).exec(), 3000);
|
|
||||||
} else {
|
} else {
|
||||||
super.onPostExecute(result);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -8,6 +8,10 @@ import android.view.MenuItem;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.google.android.material.navigation.NavigationView;
|
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.components.BaseActivity;
|
||||||
import com.topjohnwu.magisk.fragments.LogFragment;
|
import com.topjohnwu.magisk.fragments.LogFragment;
|
||||||
import com.topjohnwu.magisk.fragments.MagiskFragment;
|
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.SettingsFragment;
|
||||||
import com.topjohnwu.magisk.fragments.SuperuserFragment;
|
import com.topjohnwu.magisk.fragments.SuperuserFragment;
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@ -49,8 +51,8 @@ public class MainActivity extends BaseActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
if (!mm.hasInit) {
|
if (!app.init) {
|
||||||
startActivity(new Intent(this, Data.classMap.get(SplashActivity.class)));
|
startActivity(new Intent(this, ClassMap.get(SplashActivity.class)));
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +122,7 @@ public class MainActivity extends BaseActivity
|
|||||||
public void checkHideSection() {
|
public void checkHideSection() {
|
||||||
Menu menu = navigationView.getMenu();
|
Menu menu = navigationView.getMenu();
|
||||||
menu.findItem(R.id.magiskhide).setVisible(Shell.rootAccess() &&
|
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.modules).setVisible(Shell.rootAccess() && Data.magiskVersionCode >= 0);
|
||||||
menu.findItem(R.id.downloads).setVisible(Download.checkNetworkStatus(this)
|
menu.findItem(R.id.downloads).setVisible(Download.checkNetworkStatus(this)
|
||||||
&& Shell.rootAccess() && Data.magiskVersionCode >= 0);
|
&& Shell.rootAccess() && Data.magiskVersionCode >= 0);
|
||||||
@ -189,11 +191,11 @@ public class MainActivity extends BaseActivity
|
|||||||
displayFragment(new SettingsFragment(), true);
|
displayFragment(new SettingsFragment(), true);
|
||||||
break;
|
break;
|
||||||
case R.id.app_about:
|
case R.id.app_about:
|
||||||
startActivity(new Intent(this, Data.classMap.get(AboutActivity.class)));
|
startActivity(new Intent(this, ClassMap.get(AboutActivity.class)));
|
||||||
mDrawerItem = bak;
|
mDrawerItem = bak;
|
||||||
break;
|
break;
|
||||||
case R.id.donation:
|
case R.id.donation:
|
||||||
startActivity(new Intent(this, Data.classMap.get(DonationActivity.class)));
|
startActivity(new Intent(this, ClassMap.get(DonationActivity.class)));
|
||||||
mDrawerItem = bak;
|
mDrawerItem = bak;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,14 +5,17 @@ import android.content.pm.PackageManager;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
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.BaseActivity;
|
||||||
import com.topjohnwu.magisk.components.Notifications;
|
import com.topjohnwu.magisk.components.Notifications;
|
||||||
import com.topjohnwu.magisk.receivers.ShortcutReceiver;
|
import com.topjohnwu.magisk.receivers.ShortcutReceiver;
|
||||||
|
import com.topjohnwu.magisk.utils.AppUtils;
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
public class SplashActivity extends BaseActivity {
|
public class SplashActivity extends BaseActivity {
|
||||||
@ -21,9 +24,9 @@ public class SplashActivity extends BaseActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(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)) {
|
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();
|
Shell.su("pm uninstall " + pkg).exec();
|
||||||
}
|
}
|
||||||
if (TextUtils.equals(pkg, getPackageName())) {
|
if (TextUtils.equals(pkg, getPackageName())) {
|
||||||
@ -37,7 +40,7 @@ public class SplashActivity extends BaseActivity {
|
|||||||
// Magisk working as expected
|
// Magisk working as expected
|
||||||
if (Shell.rootAccess() && Data.magiskVersionCode > 0) {
|
if (Shell.rootAccess() && Data.magiskVersionCode > 0) {
|
||||||
// Update check service
|
// Update check service
|
||||||
Utils.setupUpdateCheck();
|
AppUtils.setupUpdateCheck();
|
||||||
// Load modules
|
// Load modules
|
||||||
Utils.loadModules();
|
Utils.loadModules();
|
||||||
}
|
}
|
||||||
@ -45,13 +48,13 @@ public class SplashActivity extends BaseActivity {
|
|||||||
Data.importPrefs();
|
Data.importPrefs();
|
||||||
|
|
||||||
// Dynamic detect all locales
|
// Dynamic detect all locales
|
||||||
LocaleManager.loadAvailableLocales();
|
LocaleManager.loadAvailableLocales(R.string.download_file_error);
|
||||||
|
|
||||||
// Create notification channel on Android O
|
// Create notification channel on Android O
|
||||||
Notifications.setup(this);
|
Notifications.setup(this);
|
||||||
|
|
||||||
// Setup shortcuts
|
// Setup shortcuts
|
||||||
sendBroadcast(new Intent(this, Data.classMap.get(ShortcutReceiver.class)));
|
sendBroadcast(new Intent(this, ClassMap.get(ShortcutReceiver.class)));
|
||||||
|
|
||||||
if (Download.checkNetworkStatus(this)) {
|
if (Download.checkNetworkStatus(this)) {
|
||||||
// Fire update check
|
// Fire update check
|
||||||
@ -63,9 +66,9 @@ public class SplashActivity extends BaseActivity {
|
|||||||
// Write back default values
|
// Write back default values
|
||||||
Data.writeConfig();
|
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(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION));
|
||||||
intent.putExtra(BaseActivity.INTENT_PERM, getIntent().getStringExtra(BaseActivity.INTENT_PERM));
|
intent.putExtra(BaseActivity.INTENT_PERM, getIntent().getStringExtra(BaseActivity.INTENT_PERM));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
|
@ -15,8 +15,10 @@ import android.widget.LinearLayout;
|
|||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
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.components.BaseActivity;
|
||||||
import com.topjohnwu.magisk.container.Policy;
|
|
||||||
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
||||||
import com.topjohnwu.magisk.utils.SuConnector;
|
import com.topjohnwu.magisk.utils.SuConnector;
|
||||||
|
|
||||||
@ -70,7 +72,7 @@ public class SuRequestActivity extends BaseActivity {
|
|||||||
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
|
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
|
||||||
PackageManager pm = getPackageManager();
|
PackageManager pm = getPackageManager();
|
||||||
mm.mDB.clearOutdated();
|
app.mDB.clearOutdated();
|
||||||
|
|
||||||
// Get policy
|
// Get policy
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
@ -84,7 +86,7 @@ public class SuRequestActivity extends BaseActivity {
|
|||||||
};
|
};
|
||||||
Bundle bundle = connector.readSocketInput();
|
Bundle bundle = connector.readSocketInput();
|
||||||
int uid = Integer.parseInt(bundle.getString("uid"));
|
int uid = Integer.parseInt(bundle.getString("uid"));
|
||||||
policy = mm.mDB.getPolicy(uid);
|
policy = app.mDB.getPolicy(uid);
|
||||||
if (policy == null) {
|
if (policy == null) {
|
||||||
policy = new Policy(uid, pm);
|
policy = new Policy(uid, pm);
|
||||||
}
|
}
|
||||||
@ -212,7 +214,7 @@ public class SuRequestActivity extends BaseActivity {
|
|||||||
policy.policy = action;
|
policy.policy = action;
|
||||||
if (time >= 0) {
|
if (time >= 0) {
|
||||||
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
|
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
|
||||||
mm.mDB.updatePolicy(policy);
|
app.mDB.updatePolicy(policy);
|
||||||
}
|
}
|
||||||
handleAction();
|
handleAction();
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,10 @@ import android.widget.Filter;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
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.R;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -10,9 +10,9 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
import com.topjohnwu.core.container.Module;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.container.Module;
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -10,12 +10,12 @@ import android.widget.Switch;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
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.R;
|
||||||
import com.topjohnwu.magisk.components.CustomAlertDialog;
|
import com.topjohnwu.magisk.components.CustomAlertDialog;
|
||||||
import com.topjohnwu.magisk.components.ExpandableView;
|
import com.topjohnwu.magisk.components.ExpandableView;
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
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 com.topjohnwu.magisk.utils.FingerprintHelper;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -11,14 +11,14 @@ import android.widget.ImageView;
|
|||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
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.R;
|
||||||
import com.topjohnwu.magisk.asyncs.DownloadModule;
|
|
||||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
|
||||||
import com.topjohnwu.magisk.components.BaseActivity;
|
import com.topjohnwu.magisk.components.BaseActivity;
|
||||||
import com.topjohnwu.magisk.components.CustomAlertDialog;
|
import com.topjohnwu.magisk.components.CustomAlertDialog;
|
||||||
import com.topjohnwu.magisk.container.Module;
|
import com.topjohnwu.magisk.components.MarkDownWindow;
|
||||||
import com.topjohnwu.magisk.container.Repo;
|
import com.topjohnwu.magisk.utils.DownloadModule;
|
||||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -8,10 +8,10 @@ import android.view.animation.RotateAnimation;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
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.R;
|
||||||
import com.topjohnwu.magisk.components.ExpandableView;
|
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.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -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<Void, Void, Integer> {
|
|
||||||
|
|
||||||
private Uri mUri;
|
|
||||||
private File mCachedFile;
|
|
||||||
private List<String> console, logs;
|
|
||||||
|
|
||||||
public FlashZip(Activity context, Uri uri, List<String> console, List<String> 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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<Void, Void, Boolean> {
|
|
||||||
|
|
||||||
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<String> 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<String> console, List<String> logs, int mode) {
|
|
||||||
this(context);
|
|
||||||
this.console = console;
|
|
||||||
this.logs = logs;
|
|
||||||
this.mode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InstallMagisk(FlashActivity context, List<String> console, List<String> 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<String> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
package com.topjohnwu.magisk.components;
|
package com.topjohnwu.magisk.components;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@ -8,13 +9,12 @@ import android.os.Bundle;
|
|||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.Data;
|
||||||
import com.topjohnwu.magisk.NoUIActivity;
|
import com.topjohnwu.core.utils.LocaleManager;
|
||||||
|
import com.topjohnwu.core.utils.Topic;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -26,12 +26,12 @@ import androidx.core.content.ContextCompat;
|
|||||||
public abstract class BaseActivity extends AppCompatActivity implements Topic.AutoSubscriber {
|
public abstract class BaseActivity extends AppCompatActivity implements Topic.AutoSubscriber {
|
||||||
|
|
||||||
public static final String INTENT_PERM = "perm_dialog";
|
public static final String INTENT_PERM = "perm_dialog";
|
||||||
|
private static Runnable grantCallback;
|
||||||
|
|
||||||
protected static Runnable permissionGrantCallback;
|
|
||||||
static int[] EMPTY_INT_ARRAY = new int[0];
|
static int[] EMPTY_INT_ARRAY = new int[0];
|
||||||
|
|
||||||
private ActivityResultListener activityResultListener;
|
private ActivityResultListener activityResultListener;
|
||||||
public MagiskManager mm;
|
public App app;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] getSubscribedTopics() {
|
public int[] getSubscribedTopics() {
|
||||||
@ -49,7 +49,7 @@ public abstract class BaseActivity extends AppCompatActivity implements Topic.Au
|
|||||||
Configuration config = base.getResources().getConfiguration();
|
Configuration config = base.getResources().getConfiguration();
|
||||||
config.setLocale(LocaleManager.locale);
|
config.setLocale(LocaleManager.locale);
|
||||||
applyOverrideConfiguration(config);
|
applyOverrideConfiguration(config);
|
||||||
mm = Data.MM();
|
app = App.self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
public static void runWithPermission(Context context, String[] permissions, Runnable callback) {
|
||||||
boolean granted = true;
|
boolean granted = true;
|
||||||
for (String perm : permissions) {
|
for (String perm : permissions) {
|
||||||
@ -95,23 +103,13 @@ public abstract class BaseActivity extends AppCompatActivity implements Topic.Au
|
|||||||
callback.run();
|
callback.run();
|
||||||
} else {
|
} else {
|
||||||
// Passed in context should be an activity if not granted, need to show dialog!
|
// Passed in context should be an activity if not granted, need to show dialog!
|
||||||
permissionGrantCallback = callback;
|
if (context instanceof BaseActivity) {
|
||||||
if (!(context instanceof BaseActivity)) {
|
grantCallback = callback;
|
||||||
// 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 {
|
|
||||||
ActivityCompat.requestPermissions((BaseActivity) context, permissions, 0);
|
ActivityCompat.requestPermissions((BaseActivity) context, permissions, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void runWithPermission(String[] permissions, Runnable callback) {
|
|
||||||
runWithPermission(this, permissions, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
if (activityResultListener != null)
|
if (activityResultListener != null)
|
||||||
@ -132,13 +130,13 @@ public abstract class BaseActivity extends AppCompatActivity implements Topic.Au
|
|||||||
grant = false;
|
grant = false;
|
||||||
}
|
}
|
||||||
if (grant) {
|
if (grant) {
|
||||||
if (permissionGrantCallback != null) {
|
if (grantCallback != null) {
|
||||||
permissionGrantCallback.run();
|
grantCallback.run();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, R.string.no_rw_storage, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.no_rw_storage, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
permissionGrantCallback = null;
|
grantCallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ActivityResultListener {
|
public interface ActivityResultListener {
|
||||||
|
@ -2,20 +2,19 @@ package com.topjohnwu.magisk.components;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import butterknife.Unbinder;
|
import butterknife.Unbinder;
|
||||||
|
|
||||||
public class BaseFragment extends Fragment implements Topic.AutoSubscriber {
|
public class BaseFragment extends Fragment implements Topic.AutoSubscriber {
|
||||||
|
|
||||||
public MagiskManager mm;
|
public App app;
|
||||||
protected Unbinder unbinder = null;
|
protected Unbinder unbinder = null;
|
||||||
|
|
||||||
public BaseFragment() {
|
public BaseFragment() {
|
||||||
mm = Data.MM();
|
app = App.self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
package com.topjohnwu.magisk.components;
|
package com.topjohnwu.magisk.components;
|
||||||
|
|
||||||
import android.app.Activity;
|
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.R;
|
||||||
import com.topjohnwu.magisk.asyncs.InstallMagisk;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
import com.topjohnwu.superuser.io.SuFile;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
@ -14,7 +19,25 @@ public class EnvFixDialog extends CustomAlertDialog {
|
|||||||
setTitle(R.string.env_fix_title);
|
setTitle(R.string.env_fix_title);
|
||||||
setMessage(R.string.env_fix_msg);
|
setMessage(R.string.env_fix_msg);
|
||||||
setCancelable(true);
|
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);
|
setNegativeButton(R.string.no_thanks, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package com.topjohnwu.magisk.components;
|
package com.topjohnwu.magisk.components;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
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.FlashActivity;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.net.Networking;
|
import com.topjohnwu.net.Networking;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -33,7 +33,7 @@ class InstallMethodDialog extends AlertDialog.Builder {
|
|||||||
downloadOnly(activity);
|
downloadOnly(activity);
|
||||||
break;
|
break;
|
||||||
case 2:
|
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);
|
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_MAGISK);
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
break;
|
break;
|
||||||
@ -48,13 +48,13 @@ class InstallMethodDialog extends AlertDialog.Builder {
|
|||||||
private void patchBoot(BaseActivity a) {
|
private void patchBoot(BaseActivity a) {
|
||||||
Utils.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG);
|
Utils.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG);
|
||||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT).setType("*/*");
|
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,
|
a.startActivityForResult(intent, Const.ID.SELECT_BOOT,
|
||||||
(requestCode, resultCode, data) -> {
|
(requestCode, resultCode, data) -> {
|
||||||
if (requestCode == Const.ID.SELECT_BOOT &&
|
if (requestCode == Const.ID.SELECT_BOOT &&
|
||||||
resultCode == Activity.RESULT_OK && data != null) {
|
resultCode == Activity.RESULT_OK && data != null) {
|
||||||
Intent i = new Intent(a, Data.classMap.get(FlashActivity.class))
|
Intent i = new Intent(a, ClassMap.get(FlashActivity.class))
|
||||||
.putExtra(Const.Key.FLASH_SET_BOOT, data.getData())
|
.setData(data.getData())
|
||||||
.putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_BOOT);
|
.putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_BOOT);
|
||||||
a.startActivity(i);
|
a.startActivity(i);
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ class InstallMethodDialog extends AlertDialog.Builder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void downloadOnly(BaseActivity a) {
|
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",
|
String filename = Utils.fmt("Magisk-v%s(%d).zip",
|
||||||
Data.remoteMagiskVersionString, Data.remoteMagiskVersionCode);
|
Data.remoteMagiskVersionString, Data.remoteMagiskVersionCode);
|
||||||
File zip = new File(Const.EXTERNAL_PATH, filename);
|
File zip = new File(Const.EXTERNAL_PATH, filename);
|
||||||
@ -86,7 +86,7 @@ class InstallMethodDialog extends AlertDialog.Builder {
|
|||||||
.setMessage(R.string.install_inactive_slot_msg)
|
.setMessage(R.string.install_inactive_slot_msg)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setPositiveButton(R.string.yes, (d, i) -> {
|
.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);
|
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_INACTIVE_SLOT);
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
})
|
})
|
||||||
|
@ -3,11 +3,10 @@ package com.topjohnwu.magisk.components;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Data;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.utils.Utils;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
import com.topjohnwu.magisk.utils.AppUtils;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
|
|
||||||
@ -15,35 +14,34 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MagiskInstallDialog extends CustomAlertDialog {
|
public class MagiskInstallDialog extends CustomAlertDialog {
|
||||||
public MagiskInstallDialog(BaseActivity activity) {
|
public MagiskInstallDialog(BaseActivity a) {
|
||||||
super(activity);
|
super(a);
|
||||||
MagiskManager mm = Data.MM();
|
|
||||||
String filename = Utils.fmt("Magisk-v%s(%d).zip",
|
String filename = Utils.fmt("Magisk-v%s(%d).zip",
|
||||||
Data.remoteMagiskVersionString, Data.remoteMagiskVersionCode);
|
Data.remoteMagiskVersionString, Data.remoteMagiskVersionCode);
|
||||||
setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.magisk)));
|
setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.magisk)));
|
||||||
setMessage(mm.getString(R.string.repo_install_msg, filename));
|
setMessage(a.getString(R.string.repo_install_msg, filename));
|
||||||
setCancelable(true);
|
setCancelable(true);
|
||||||
setPositiveButton(R.string.install, (d, i) -> {
|
setPositiveButton(R.string.install, (d, i) -> {
|
||||||
List<String> options = new ArrayList<>();
|
List<String> options = new ArrayList<>();
|
||||||
options.add(mm.getString(R.string.download_zip_only));
|
options.add(a.getString(R.string.download_zip_only));
|
||||||
options.add(mm.getString(R.string.patch_boot_file));
|
options.add(a.getString(R.string.patch_boot_file));
|
||||||
if (Shell.rootAccess()) {
|
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");
|
String s = ShellUtils.fastCmd("grep_prop ro.build.ab_update");
|
||||||
if (!s.isEmpty() && Boolean.parseBoolean(s)) {
|
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);
|
setNegativeButton(R.string.no_thanks, null);
|
||||||
if (!TextUtils.isEmpty(Data.magiskNoteLink)) {
|
if (!TextUtils.isEmpty(Data.magiskNoteLink)) {
|
||||||
setNeutralButton(R.string.release_notes, (d, i) -> {
|
setNeutralButton(R.string.release_notes, (d, i) -> {
|
||||||
if (Data.magiskNoteLink.contains("forum.xda-developers")) {
|
if (Data.magiskNoteLink.contains("forum.xda-developers")) {
|
||||||
// Open forum links in browser
|
// Open forum links in browser
|
||||||
Utils.openLink(activity, Uri.parse(Data.magiskNoteLink));
|
AppUtils.openLink(a, Uri.parse(Data.magiskNoteLink));
|
||||||
} else {
|
} else {
|
||||||
new MarkDownWindow(activity, null, Data.magiskNoteLink).exec();
|
new MarkDownWindow(a, null, Data.magiskNoteLink).exec();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,30 +2,27 @@ package com.topjohnwu.magisk.components;
|
|||||||
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Data;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.utils.Utils;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
import com.topjohnwu.magisk.utils.DownloadApp;
|
||||||
import com.topjohnwu.magisk.utils.DlInstallManager;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
public class ManagerInstallDialog extends CustomAlertDialog {
|
public class ManagerInstallDialog extends CustomAlertDialog {
|
||||||
|
|
||||||
public ManagerInstallDialog(@NonNull BaseActivity activity) {
|
public ManagerInstallDialog(@NonNull BaseActivity a) {
|
||||||
super(activity);
|
super(a);
|
||||||
MagiskManager mm = Data.MM();
|
|
||||||
String name = Utils.fmt("MagiskManager v%s(%d)",
|
String name = Utils.fmt("MagiskManager v%s(%d)",
|
||||||
Data.remoteManagerVersionString, Data.remoteManagerVersionCode);
|
Data.remoteManagerVersionString, Data.remoteManagerVersionCode);
|
||||||
setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.app_name)));
|
setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.app_name)));
|
||||||
setMessage(mm.getString(R.string.repo_install_msg, name));
|
setMessage(a.getString(R.string.repo_install_msg, name));
|
||||||
setCancelable(true);
|
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);
|
setNegativeButton(R.string.no_thanks, null);
|
||||||
if (!TextUtils.isEmpty(Data.managerNoteLink)) {
|
if (!TextUtils.isEmpty(Data.managerNoteLink)) {
|
||||||
setNeutralButton(R.string.app_changelog, (d, i) ->
|
setNeutralButton(R.string.app_changelog, (d, i) ->
|
||||||
new MarkDownWindow(activity, null, Data.managerNoteLink).exec());
|
new MarkDownWindow(a, null, Data.managerNoteLink).exec());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.magisk.components;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
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.R;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
|
|
||||||
import org.commonmark.node.Node;
|
import org.commonmark.node.Node;
|
||||||
@ -40,7 +41,7 @@ public class MarkDownWindow extends ParallelTask<Void, Void, String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String doInBackground(Void... voids) {
|
protected String doInBackground(Void... voids) {
|
||||||
MagiskManager mm = Data.MM();
|
App app = App.self;
|
||||||
String md;
|
String md;
|
||||||
if (mUrl != null) {
|
if (mUrl != null) {
|
||||||
md = Utils.dlString(mUrl);
|
md = Utils.dlString(mUrl);
|
||||||
@ -55,14 +56,11 @@ public class MarkDownWindow extends ParallelTask<Void, Void, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
String css;
|
String css;
|
||||||
try (
|
try (InputStream in = app.getResources()
|
||||||
InputStream in = mm.getResources().openRawResource(
|
.openRawResource(Data.isDarkTheme ? R.raw.dark : R.raw.light);
|
||||||
Data.isDarkTheme ? R.raw.dark : R.raw.light);
|
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream()
|
|
||||||
) {
|
|
||||||
ShellUtils.pump(in, out);
|
ShellUtils.pump(in, out);
|
||||||
css = out.toString();
|
css = out.toString();
|
||||||
in.close();
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return "";
|
return "";
|
@ -7,13 +7,14 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
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.R;
|
||||||
import com.topjohnwu.magisk.SplashActivity;
|
import com.topjohnwu.magisk.SplashActivity;
|
||||||
import com.topjohnwu.magisk.receivers.GeneralReceiver;
|
import com.topjohnwu.magisk.receivers.GeneralReceiver;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
@ -36,74 +37,74 @@ public class Notifications {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void magiskUpdate() {
|
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");
|
intent.putExtra(Const.Key.OPEN_SECTION, "magisk");
|
||||||
TaskStackBuilder stackBuilder = TaskStackBuilder.create(mm);
|
TaskStackBuilder stackBuilder = TaskStackBuilder.create(app);
|
||||||
stackBuilder.addParentStack(Data.classMap.get(SplashActivity.class));
|
stackBuilder.addParentStack(ClassMap.get(SplashActivity.class));
|
||||||
stackBuilder.addNextIntent(intent);
|
stackBuilder.addNextIntent(intent);
|
||||||
PendingIntent pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
|
PendingIntent pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
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)
|
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||||
.setContentTitle(mm.getString(R.string.magisk_update_title))
|
.setContentTitle(app.getString(R.string.magisk_update_title))
|
||||||
.setContentText(mm.getString(R.string.magisk_update_available, Data.remoteMagiskVersionString))
|
.setContentText(app.getString(R.string.magisk_update_available, Data.remoteMagiskVersionString))
|
||||||
.setVibrate(new long[]{0, 100, 100, 100})
|
.setVibrate(new long[]{0, 100, 100, 100})
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setContentIntent(pendingIntent);
|
.setContentIntent(pendingIntent);
|
||||||
|
|
||||||
NotificationManagerCompat mgr = NotificationManagerCompat.from(mm);
|
NotificationManagerCompat mgr = NotificationManagerCompat.from(app);
|
||||||
mgr.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build());
|
mgr.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void managerUpdate() {
|
public static void managerUpdate() {
|
||||||
MagiskManager mm = Data.MM();
|
App app = App.self;
|
||||||
String name = Utils.fmt("MagiskManager v%s(%d)",
|
String name = Utils.fmt("MagiskManager v%s(%d)",
|
||||||
Data.remoteManagerVersionString, Data.remoteManagerVersionCode);
|
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.setAction(Const.Key.BROADCAST_MANAGER_UPDATE);
|
||||||
intent.putExtra(Const.Key.INTENT_SET_LINK, Data.managerLink);
|
intent.putExtra(Const.Key.INTENT_SET_LINK, Data.managerLink);
|
||||||
intent.putExtra(Const.Key.INTENT_SET_NAME, name);
|
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);
|
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)
|
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||||
.setContentTitle(mm.getString(R.string.manager_update_title))
|
.setContentTitle(app.getString(R.string.manager_update_title))
|
||||||
.setContentText(mm.getString(R.string.manager_download_install))
|
.setContentText(app.getString(R.string.manager_download_install))
|
||||||
.setVibrate(new long[]{0, 100, 100, 100})
|
.setVibrate(new long[]{0, 100, 100, 100})
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setContentIntent(pendingIntent);
|
.setContentIntent(pendingIntent);
|
||||||
|
|
||||||
NotificationManagerCompat mgr = NotificationManagerCompat.from(mm);
|
NotificationManagerCompat mgr = NotificationManagerCompat.from(app);
|
||||||
mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build());
|
mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void dtboPatched() {
|
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);
|
.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);
|
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)
|
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||||
.setContentTitle(mm.getString(R.string.dtbo_patched_title))
|
.setContentTitle(app.getString(R.string.dtbo_patched_title))
|
||||||
.setContentText(mm.getString(R.string.dtbo_patched_reboot))
|
.setContentText(app.getString(R.string.dtbo_patched_reboot))
|
||||||
.setVibrate(new long[]{0, 100, 100, 100})
|
.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());
|
mgr.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NotificationCompat.Builder progress(String title) {
|
public static NotificationCompat.Builder progress(String title) {
|
||||||
MagiskManager mm = Data.MM();
|
App app = App.self;
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.PROGRESS_NOTIFICATION_CHANNEL);
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.PROGRESS_NOTIFICATION_CHANNEL);
|
||||||
builder.setPriority(NotificationCompat.PRIORITY_LOW)
|
builder.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||||
.setContentTitle(title)
|
.setContentTitle(title)
|
||||||
|
@ -2,10 +2,9 @@ package com.topjohnwu.magisk.components;
|
|||||||
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.utils.Utils;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.net.DownloadProgressListener;
|
import com.topjohnwu.net.DownloadProgressListener;
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
@ -17,12 +16,11 @@ public class ProgressNotification implements DownloadProgressListener {
|
|||||||
private long prevTime;
|
private long prevTime;
|
||||||
|
|
||||||
public ProgressNotification(String title) {
|
public ProgressNotification(String title) {
|
||||||
MagiskManager mm = Data.MM();
|
mgr = NotificationManagerCompat.from(App.self);
|
||||||
mgr = NotificationManagerCompat.from(mm);
|
|
||||||
builder = Notifications.progress(title);
|
builder = Notifications.progress(title);
|
||||||
prevTime = System.currentTimeMillis();
|
prevTime = System.currentTimeMillis();
|
||||||
update();
|
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
|
@Override
|
||||||
@ -47,7 +45,7 @@ public class ProgressNotification implements DownloadProgressListener {
|
|||||||
|
|
||||||
public void dlDone() {
|
public void dlDone() {
|
||||||
builder.setProgress(0, 0, false)
|
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)
|
.setSmallIcon(R.drawable.ic_check_circle)
|
||||||
.setOngoing(false);
|
.setOngoing(false);
|
||||||
update();
|
update();
|
||||||
@ -55,7 +53,7 @@ public class ProgressNotification implements DownloadProgressListener {
|
|||||||
|
|
||||||
public void dlFail() {
|
public void dlFail() {
|
||||||
builder.setProgress(0, 0, false)
|
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)
|
.setSmallIcon(R.drawable.ic_cancel)
|
||||||
.setOngoing(false);
|
.setOngoing(false);
|
||||||
update();
|
update();
|
||||||
|
@ -6,8 +6,8 @@ import android.view.View;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
import com.topjohnwu.core.utils.Utils;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
|
@ -7,11 +7,12 @@ import android.net.Uri;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
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.FlashActivity;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.net.Networking;
|
import com.topjohnwu.net.Networking;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ public class UninstallDialog extends CustomAlertDialog {
|
|||||||
.setErrorHandler(((conn, e) -> progress.dlFail()))
|
.setErrorHandler(((conn, e) -> progress.dlFail()))
|
||||||
.getAsFile(f -> {
|
.getAsFile(f -> {
|
||||||
progress.dismiss();
|
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)
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
.setData(Uri.fromFile(f))
|
.setData(Uri.fromFile(f))
|
||||||
.putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL);
|
.putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL);
|
||||||
|
@ -15,13 +15,15 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
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.BuildConfig;
|
||||||
import com.topjohnwu.magisk.Const;
|
|
||||||
import com.topjohnwu.magisk.Data;
|
|
||||||
import com.topjohnwu.magisk.MainActivity;
|
import com.topjohnwu.magisk.MainActivity;
|
||||||
import com.topjohnwu.magisk.R;
|
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.BaseActivity;
|
||||||
import com.topjohnwu.magisk.components.BaseFragment;
|
import com.topjohnwu.magisk.components.BaseFragment;
|
||||||
import com.topjohnwu.magisk.components.CustomAlertDialog;
|
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.ManagerInstallDialog;
|
||||||
import com.topjohnwu.magisk.components.UninstallDialog;
|
import com.topjohnwu.magisk.components.UninstallDialog;
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
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.Shell;
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ public class MagiskFragment extends BaseFragment
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
((NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll();
|
((NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll();
|
||||||
new MagiskInstallDialog((BaseActivity) getActivity()).show();
|
new MagiskInstallDialog((BaseActivity) getActivity()).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ public class MagiskFragment extends BaseFragment
|
|||||||
shownDialog = false;
|
shownDialog = false;
|
||||||
|
|
||||||
// Trigger state check
|
// Trigger state check
|
||||||
if (Download.checkNetworkStatus(mm)) {
|
if (Download.checkNetworkStatus(app)) {
|
||||||
CheckUpdates.check();
|
CheckUpdates.check();
|
||||||
} else {
|
} else {
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
@ -199,7 +199,7 @@ public class MagiskFragment extends BaseFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasGms() {
|
private boolean hasGms() {
|
||||||
PackageManager pm = mm.getPackageManager();
|
PackageManager pm = app.getPackageManager();
|
||||||
PackageInfo info;
|
PackageInfo info;
|
||||||
try {
|
try {
|
||||||
info = pm.getPackageInfo("com.google.android.gms", 0);
|
info = pm.getPackageInfo("com.google.android.gms", 0);
|
||||||
@ -212,13 +212,13 @@ public class MagiskFragment extends BaseFragment
|
|||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
((MainActivity) requireActivity()).checkHideSection();
|
((MainActivity) requireActivity()).checkHideSection();
|
||||||
|
|
||||||
boolean hasNetwork = Download.checkNetworkStatus(mm);
|
boolean hasNetwork = Download.checkNetworkStatus(app);
|
||||||
boolean hasRoot = Shell.rootAccess();
|
boolean hasRoot = Shell.rootAccess();
|
||||||
|
|
||||||
magiskUpdate.setVisibility(hasNetwork ? View.VISIBLE : View.GONE);
|
magiskUpdate.setVisibility(hasNetwork ? View.VISIBLE : View.GONE);
|
||||||
installOptionCard.setVisibility(hasNetwork ? View.VISIBLE : View.GONE);
|
installOptionCard.setVisibility(hasNetwork ? View.VISIBLE : View.GONE);
|
||||||
uninstallButton.setVisibility(hasRoot ? 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;
|
int image, color;
|
||||||
|
|
||||||
|
@ -8,10 +8,10 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.SearchView;
|
import android.widget.SearchView;
|
||||||
|
|
||||||
|
import com.topjohnwu.core.utils.Topic;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
|
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
|
||||||
import com.topjohnwu.magisk.components.BaseFragment;
|
import com.topjohnwu.magisk.components.BaseFragment;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -15,11 +15,11 @@ import android.widget.ScrollView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
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.R;
|
||||||
import com.topjohnwu.magisk.components.BaseFragment;
|
import com.topjohnwu.magisk.components.BaseFragment;
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -12,15 +12,15 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
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.FlashActivity;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
||||||
import com.topjohnwu.magisk.components.BaseFragment;
|
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 com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
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) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) {
|
if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) {
|
||||||
// Get the URI of the selected file
|
// 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);
|
intent.setData(data.getData()).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,14 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.SearchView;
|
import android.widget.SearchView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
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.R;
|
||||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
||||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
|
||||||
import com.topjohnwu.magisk.components.BaseFragment;
|
import com.topjohnwu.magisk.components.BaseFragment;
|
||||||
import com.topjohnwu.magisk.container.Module;
|
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -70,8 +70,8 @@ public class ReposFragment extends BaseFragment implements Topic.Subscriber {
|
|||||||
@Override
|
@Override
|
||||||
public void onPublish(int topic, Object[] result) {
|
public void onPublish(int topic, Object[] result) {
|
||||||
if (topic == Topic.MODULE_LOAD_DONE) {
|
if (topic == Topic.MODULE_LOAD_DONE) {
|
||||||
adapter = new ReposAdapter(mm.repoDB, (Map<String, Module>) result[0]);
|
adapter = new ReposAdapter(app.repoDB, (Map<String, Module>) result[0]);
|
||||||
mm.repoDB.registerAdapter(adapter);
|
app.repoDB.registerAdapterCallback(adapter::notifyDBChanged);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
emptyRv.setVisibility(View.GONE);
|
emptyRv.setVisibility(View.GONE);
|
||||||
@ -108,7 +108,7 @@ public class ReposFragment extends BaseFragment implements Topic.Subscriber {
|
|||||||
.setTitle(R.string.sorting_order)
|
.setTitle(R.string.sorting_order)
|
||||||
.setSingleChoiceItems(R.array.sorting_orders, Data.repoOrder, (d, which) -> {
|
.setSingleChoiceItems(R.array.sorting_orders, Data.repoOrder, (d, which) -> {
|
||||||
Data.repoOrder = 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();
|
adapter.notifyDBChanged();
|
||||||
d.dismiss();
|
d.dismiss();
|
||||||
}).show();
|
}).show();
|
||||||
@ -119,6 +119,6 @@ public class ReposFragment extends BaseFragment implements Topic.Subscriber {
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
mm.repoDB.unregisterAdapter();
|
app.repoDB.unregisterAdapterCallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,19 +10,20 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.Toast;
|
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.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.R;
|
||||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
import com.topjohnwu.magisk.utils.AppUtils;
|
||||||
import com.topjohnwu.magisk.asyncs.PatchAPK;
|
|
||||||
import com.topjohnwu.magisk.utils.DlInstallManager;
|
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
|
import com.topjohnwu.magisk.utils.DownloadApp;
|
||||||
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
import com.topjohnwu.magisk.utils.PatchAPK;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -43,7 +44,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
implements SharedPreferences.OnSharedPreferenceChangeListener,
|
implements SharedPreferences.OnSharedPreferenceChangeListener,
|
||||||
Topic.Subscriber, Topic.AutoSubscriber {
|
Topic.Subscriber, Topic.AutoSubscriber {
|
||||||
|
|
||||||
private MagiskManager mm;
|
private App app = App.self;
|
||||||
|
|
||||||
private ListPreference updateChannel, autoRes, suNotification,
|
private ListPreference updateChannel, autoRes, suNotification,
|
||||||
requestTimeout, rootConfig, multiuserConfig, nsConfig;
|
requestTimeout, rootConfig, multiuserConfig, nsConfig;
|
||||||
@ -52,10 +53,10 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
private boolean showSuperuser;
|
private boolean showSuperuser;
|
||||||
|
|
||||||
private void prefsSync() {
|
private void prefsSync() {
|
||||||
rootState = mm.mDB.getSettings(Const.Key.ROOT_ACCESS, Const.Value.ROOT_ACCESS_APPS_AND_ADB);
|
rootState = app.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);
|
namespaceState = app.mDB.getSettings(Const.Key.SU_MNT_NS, Const.Value.NAMESPACE_MODE_REQUESTER);
|
||||||
showSuperuser = Utils.showSuperUser();
|
showSuperuser = Utils.showSuperUser();
|
||||||
mm.prefs.edit()
|
app.prefs.edit()
|
||||||
.putString(Const.Key.ROOT_ACCESS, String.valueOf(rootState))
|
.putString(Const.Key.ROOT_ACCESS, String.valueOf(rootState))
|
||||||
.putString(Const.Key.SU_MNT_NS, String.valueOf(namespaceState))
|
.putString(Const.Key.SU_MNT_NS, String.valueOf(namespaceState))
|
||||||
.putString(Const.Key.SU_MULTIUSER_MODE, String.valueOf(Data.multiuserState))
|
.putString(Const.Key.SU_MULTIUSER_MODE, String.valueOf(Data.multiuserState))
|
||||||
@ -65,7 +66,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
mm = Data.MM();
|
|
||||||
prefsSync();
|
prefsSync();
|
||||||
|
|
||||||
setPreferencesFromResource(R.xml.app_settings, rootKey);
|
setPreferencesFromResource(R.xml.app_settings, rootKey);
|
||||||
@ -82,12 +82,12 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
});
|
});
|
||||||
Preference restoreManager = findPreference("restore");
|
Preference restoreManager = findPreference("restore");
|
||||||
restoreManager.setOnPreferenceClickListener(pref -> {
|
restoreManager.setOnPreferenceClickListener(pref -> {
|
||||||
DlInstallManager.restore();
|
DownloadApp.restore();
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
findPreference("clear").setOnPreferenceClickListener(pref -> {
|
findPreference("clear").setOnPreferenceClickListener(pref -> {
|
||||||
mm.prefs.edit().remove(Const.Key.ETAG_KEY).apply();
|
app.prefs.edit().remove(Const.Key.ETAG_KEY).apply();
|
||||||
mm.repoDB.clearRepo();
|
app.repoDB.clearRepo();
|
||||||
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT);
|
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@ -114,17 +114,17 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
if (channel == Const.Value.CUSTOM_CHANNEL) {
|
if (channel == Const.Value.CUSTOM_CHANNEL) {
|
||||||
View v = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_channel_dialog, null);
|
View v = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_channel_dialog, null);
|
||||||
EditText url = v.findViewById(R.id.custom_url);
|
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())
|
new AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.settings_update_custom)
|
.setTitle(R.string.settings_update_custom)
|
||||||
.setView(v)
|
.setView(v)
|
||||||
.setPositiveButton(R.string.ok, (d, i) ->
|
.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())
|
url.getText().toString()).apply())
|
||||||
.setNegativeButton(R.string.close, (d, i) ->
|
.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 ->
|
.setOnCancelListener(d ->
|
||||||
mm.prefs.edit().putString(Const.Key.UPDATE_CHANNEL, prev).apply())
|
app.prefs.edit().putString(Const.Key.UPDATE_CHANNEL, prev).apply())
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -152,10 +152,10 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Shell.rootAccess() && Const.USER_ID == 0) {
|
if (Shell.rootAccess() && Const.USER_ID == 0) {
|
||||||
if (mm.getPackageName().equals(BuildConfig.APPLICATION_ID)) {
|
if (app.getPackageName().equals(BuildConfig.APPLICATION_ID)) {
|
||||||
generalCatagory.removePreference(restoreManager);
|
generalCatagory.removePreference(restoreManager);
|
||||||
} else {
|
} else {
|
||||||
if (!Download.checkNetworkStatus(mm))
|
if (!Download.checkNetworkStatus(app))
|
||||||
generalCatagory.removePreference(restoreManager);
|
generalCatagory.removePreference(restoreManager);
|
||||||
generalCatagory.removePreference(hideManager);
|
generalCatagory.removePreference(hideManager);
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
mm.prefs.registerOnSharedPreferenceChangeListener(this);
|
app.prefs.registerOnSharedPreferenceChangeListener(this);
|
||||||
Topic.subscribe(this);
|
Topic.subscribe(this);
|
||||||
requireActivity().setTitle(R.string.settings);
|
requireActivity().setTitle(R.string.settings);
|
||||||
return super.onCreateView(inflater, container, savedInstanceState);
|
return super.onCreateView(inflater, container, savedInstanceState);
|
||||||
@ -199,7 +199,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
mm.prefs.unregisterOnSharedPreferenceChangeListener(this);
|
app.prefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
Topic.unsubscribe(this);
|
Topic.unsubscribe(this);
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
}
|
}
|
||||||
@ -210,7 +210,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
case Const.Key.ROOT_ACCESS:
|
case Const.Key.ROOT_ACCESS:
|
||||||
case Const.Key.SU_MULTIUSER_MODE:
|
case Const.Key.SU_MULTIUSER_MODE:
|
||||||
case Const.Key.SU_MNT_NS:
|
case Const.Key.SU_MNT_NS:
|
||||||
mm.mDB.setSettings(key, Utils.getPrefsInt(prefs, key));
|
app.mDB.setSettings(key, Utils.getPrefsInt(prefs, key));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (key) {
|
switch (key) {
|
||||||
@ -244,7 +244,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Const.Key.LOCALE:
|
case Const.Key.LOCALE:
|
||||||
LocaleManager.setLocale(mm);
|
LocaleManager.setLocale(app);
|
||||||
requireActivity().recreate();
|
requireActivity().recreate();
|
||||||
break;
|
break;
|
||||||
case Const.Key.UPDATE_CHANNEL:
|
case Const.Key.UPDATE_CHANNEL:
|
||||||
@ -252,7 +252,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
CheckUpdates.check();
|
CheckUpdates.check();
|
||||||
break;
|
break;
|
||||||
case Const.Key.CHECK_UPDATES:
|
case Const.Key.CHECK_UPDATES:
|
||||||
Utils.setupUpdateCheck();
|
AppUtils.setupUpdateCheck();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Data.loadConfig();
|
Data.loadConfig();
|
||||||
@ -268,7 +268,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
((SwitchPreference) preference).setChecked(!checked);
|
((SwitchPreference) preference).setChecked(!checked);
|
||||||
FingerprintHelper.showAuthDialog(requireActivity(), () -> {
|
FingerprintHelper.showAuthDialog(requireActivity(), () -> {
|
||||||
((SwitchPreference) preference).setChecked(checked);
|
((SwitchPreference) preference).setChecked(checked);
|
||||||
mm.mDB.setSettings(key, checked ? 1 : 0);
|
app.mDB.setSettings(key, checked ? 1 : 0);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -286,7 +286,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
.getStringArray(R.array.su_notification)[Data.suNotificationType]);
|
.getStringArray(R.array.su_notification)[Data.suNotificationType]);
|
||||||
requestTimeout.setSummary(
|
requestTimeout.setSummary(
|
||||||
getString(R.string.request_timeout_summary,
|
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()
|
multiuserConfig.setSummary(getResources()
|
||||||
.getStringArray(R.array.multiuser_summary)[Data.multiuserState]);
|
.getStringArray(R.array.multiuser_summary)[Data.multiuserState]);
|
||||||
nsConfig.setSummary(getResources()
|
nsConfig.setSummary(getResources()
|
||||||
|
@ -42,7 +42,7 @@ public class SuLogFragment extends BaseFragment {
|
|||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
|
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
|
||||||
unbinder = new SuLogFragment_ViewBinding(this, v);
|
unbinder = new SuLogFragment_ViewBinding(this, v);
|
||||||
adapter = new SuLogAdapter(mm.mDB);
|
adapter = new SuLogAdapter(app.mDB);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
updateList();
|
updateList();
|
||||||
@ -69,7 +69,7 @@ public class SuLogFragment extends BaseFragment {
|
|||||||
updateList();
|
updateList();
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_clear:
|
case R.id.menu_clear:
|
||||||
mm.mDB.clearLogs();
|
app.mDB.clearLogs();
|
||||||
updateList();
|
updateList();
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
@ -7,10 +7,10 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.topjohnwu.core.container.Policy;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
||||||
import com.topjohnwu.magisk.components.BaseFragment;
|
import com.topjohnwu.magisk.components.BaseFragment;
|
||||||
import com.topjohnwu.magisk.container.Policy;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -48,13 +48,13 @@ public class SuperuserFragment extends BaseFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void displayPolicyList() {
|
private void displayPolicyList() {
|
||||||
List<Policy> policyList = mm.mDB.getPolicyList();
|
List<Policy> policyList = app.mDB.getPolicyList();
|
||||||
|
|
||||||
if (policyList.size() == 0) {
|
if (policyList.size() == 0) {
|
||||||
emptyRv.setVisibility(View.VISIBLE);
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
recyclerView.setAdapter(new PolicyAdapter(policyList, mm.mDB, pm));
|
recyclerView.setAdapter(new PolicyAdapter(policyList, app.mDB, pm));
|
||||||
emptyRv.setVisibility(View.GONE);
|
emptyRv.setVisibility(View.GONE);
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,13 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.Data;
|
||||||
|
import com.topjohnwu.magisk.ClassMap;
|
||||||
import com.topjohnwu.magisk.SuRequestActivity;
|
import com.topjohnwu.magisk.SuRequestActivity;
|
||||||
import com.topjohnwu.magisk.services.OnBootService;
|
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.magisk.utils.SuConnector;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ public class GeneralReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
MagiskManager mm = Data.MM();
|
App app = App.self;
|
||||||
if (intent == null)
|
if (intent == null)
|
||||||
return;
|
return;
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
@ -34,10 +35,10 @@ public class GeneralReceiver extends BroadcastReceiver {
|
|||||||
bootAction = "boot";
|
bootAction = "boot";
|
||||||
switch (bootAction) {
|
switch (bootAction) {
|
||||||
case "request":
|
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"))
|
.putExtra("socket", intent.getStringExtra("socket"))
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
mm.startActivity(i);
|
app.startActivity(i);
|
||||||
break;
|
break;
|
||||||
case "log":
|
case "log":
|
||||||
SuConnector.handleLogs(intent);
|
SuConnector.handleLogs(intent);
|
||||||
@ -48,24 +49,24 @@ public class GeneralReceiver extends BroadcastReceiver {
|
|||||||
case "boot":
|
case "boot":
|
||||||
default:
|
default:
|
||||||
/* The actual on-boot trigger */
|
/* The actual on-boot trigger */
|
||||||
OnBootService.enqueueWork(mm);
|
OnBootService.enqueueWork(app);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Intent.ACTION_PACKAGE_REPLACED:
|
case Intent.ACTION_PACKAGE_REPLACED:
|
||||||
// This will only work pre-O
|
// This will only work pre-O
|
||||||
if (mm.prefs.getBoolean(Const.Key.SU_REAUTH, false)) {
|
if (app.prefs.getBoolean(Const.Key.SU_REAUTH, false)) {
|
||||||
mm.mDB.deletePolicy(getPkg(intent));
|
app.mDB.deletePolicy(getPkg(intent));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
|
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
|
||||||
String pkg = getPkg(intent);
|
String pkg = getPkg(intent);
|
||||||
mm.mDB.deletePolicy(pkg);
|
app.mDB.deletePolicy(pkg);
|
||||||
Shell.su("magiskhide --rm " + pkg).submit();
|
Shell.su("magiskhide --rm " + pkg).submit();
|
||||||
break;
|
break;
|
||||||
case Const.Key.BROADCAST_MANAGER_UPDATE:
|
case Const.Key.BROADCAST_MANAGER_UPDATE:
|
||||||
Data.managerLink = intent.getStringExtra(Const.Key.INTENT_SET_LINK);
|
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;
|
break;
|
||||||
case Const.Key.BROADCAST_REBOOT:
|
case Const.Key.BROADCAST_REBOOT:
|
||||||
Shell.su("/system/bin/reboot").submit();
|
Shell.su("/system/bin/reboot").submit();
|
||||||
|
@ -8,12 +8,13 @@ import android.content.pm.ShortcutManager;
|
|||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
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.R;
|
||||||
import com.topjohnwu.magisk.SplashActivity;
|
import com.topjohnwu.magisk.SplashActivity;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -24,55 +25,54 @@ public class ShortcutReceiver extends BroadcastReceiver {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||||
MagiskManager mm = Data.MM();
|
|
||||||
ShortcutManager manager = context.getSystemService(ShortcutManager.class);
|
ShortcutManager manager = context.getSystemService(ShortcutManager.class);
|
||||||
manager.setDynamicShortcuts(getShortCuts(mm));
|
manager.setDynamicShortcuts(getShortCuts(App.self));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
|
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
|
||||||
private ArrayList<ShortcutInfo> getShortCuts(MagiskManager mm) {
|
private ArrayList<ShortcutInfo> getShortCuts(App app) {
|
||||||
ArrayList<ShortcutInfo> shortCuts = new ArrayList<>();
|
ArrayList<ShortcutInfo> shortCuts = new ArrayList<>();
|
||||||
boolean root = Shell.rootAccess();
|
boolean root = Shell.rootAccess();
|
||||||
if (Utils.showSuperUser()) {
|
if (Utils.showSuperUser()) {
|
||||||
shortCuts.add(new ShortcutInfo.Builder(mm, "superuser")
|
shortCuts.add(new ShortcutInfo.Builder(app, "superuser")
|
||||||
.setShortLabel(mm.getString(R.string.superuser))
|
.setShortLabel(app.getString(R.string.superuser))
|
||||||
.setIntent(new Intent(mm, Data.classMap.get(SplashActivity.class))
|
.setIntent(new Intent(app, ClassMap.get(SplashActivity.class))
|
||||||
.putExtra(Const.Key.OPEN_SECTION, "superuser")
|
.putExtra(Const.Key.OPEN_SECTION, "superuser")
|
||||||
.setAction(Intent.ACTION_VIEW)
|
.setAction(Intent.ACTION_VIEW)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
||||||
.setIcon(Icon.createWithResource(mm, R.drawable.sc_superuser))
|
.setIcon(Icon.createWithResource(app, R.drawable.sc_superuser))
|
||||||
.setRank(0)
|
.setRank(0)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
if (root && mm.prefs.getBoolean(Const.Key.MAGISKHIDE, false)) {
|
if (root && app.prefs.getBoolean(Const.Key.MAGISKHIDE, false)) {
|
||||||
shortCuts.add(new ShortcutInfo.Builder(mm, "magiskhide")
|
shortCuts.add(new ShortcutInfo.Builder(app, "magiskhide")
|
||||||
.setShortLabel(mm.getString(R.string.magiskhide))
|
.setShortLabel(app.getString(R.string.magiskhide))
|
||||||
.setIntent(new Intent(mm, Data.classMap.get(SplashActivity.class))
|
.setIntent(new Intent(app, ClassMap.get(SplashActivity.class))
|
||||||
.putExtra(Const.Key.OPEN_SECTION, "magiskhide")
|
.putExtra(Const.Key.OPEN_SECTION, "magiskhide")
|
||||||
.setAction(Intent.ACTION_VIEW)
|
.setAction(Intent.ACTION_VIEW)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
||||||
.setIcon(Icon.createWithResource(mm, R.drawable.sc_magiskhide))
|
.setIcon(Icon.createWithResource(app, R.drawable.sc_magiskhide))
|
||||||
.setRank(1)
|
.setRank(1)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
if (!mm.prefs.getBoolean(Const.Key.COREONLY, false) && root && Data.magiskVersionCode >= 0) {
|
if (!app.prefs.getBoolean(Const.Key.COREONLY, false) && root && Data.magiskVersionCode >= 0) {
|
||||||
shortCuts.add(new ShortcutInfo.Builder(mm, "modules")
|
shortCuts.add(new ShortcutInfo.Builder(app, "modules")
|
||||||
.setShortLabel(mm.getString(R.string.modules))
|
.setShortLabel(app.getString(R.string.modules))
|
||||||
.setIntent(new Intent(mm, Data.classMap.get(SplashActivity.class))
|
.setIntent(new Intent(app, ClassMap.get(SplashActivity.class))
|
||||||
.putExtra(Const.Key.OPEN_SECTION, "modules")
|
.putExtra(Const.Key.OPEN_SECTION, "modules")
|
||||||
.setAction(Intent.ACTION_VIEW)
|
.setAction(Intent.ACTION_VIEW)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
||||||
.setIcon(Icon.createWithResource(mm, R.drawable.sc_extension))
|
.setIcon(Icon.createWithResource(app, R.drawable.sc_extension))
|
||||||
.setRank(3)
|
.setRank(3)
|
||||||
.build());
|
.build());
|
||||||
shortCuts.add(new ShortcutInfo.Builder(mm, "downloads")
|
shortCuts.add(new ShortcutInfo.Builder(app, "downloads")
|
||||||
.setShortLabel(mm.getString(R.string.downloads))
|
.setShortLabel(app.getString(R.string.downloads))
|
||||||
.setIntent(new Intent(mm, Data.classMap.get(SplashActivity.class))
|
.setIntent(new Intent(app, ClassMap.get(SplashActivity.class))
|
||||||
.putExtra(Const.Key.OPEN_SECTION, "downloads")
|
.putExtra(Const.Key.OPEN_SECTION, "downloads")
|
||||||
.setAction(Intent.ACTION_VIEW)
|
.setAction(Intent.ACTION_VIEW)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
.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)
|
.setRank(2)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ package com.topjohnwu.magisk.services;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.ClassMap;
|
||||||
import com.topjohnwu.magisk.components.Notifications;
|
import com.topjohnwu.magisk.components.Notifications;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
@ -15,7 +15,7 @@ import androidx.core.app.JobIntentService;
|
|||||||
public class OnBootService extends JobIntentService {
|
public class OnBootService extends JobIntentService {
|
||||||
|
|
||||||
public static void enqueueWork(Context context) {
|
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
|
@Override
|
||||||
|
@ -3,7 +3,10 @@ package com.topjohnwu.magisk.services;
|
|||||||
import android.app.job.JobParameters;
|
import android.app.job.JobParameters;
|
||||||
import android.app.job.JobService;
|
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;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
public class UpdateCheckService extends JobService {
|
public class UpdateCheckService extends JobService {
|
||||||
@ -11,7 +14,14 @@ public class UpdateCheckService extends JobService {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onStartJob(JobParameters params) {
|
public boolean onStartJob(JobParameters params) {
|
||||||
Shell.getShell();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
50
app/src/full/java/com/topjohnwu/magisk/utils/AppUtils.java
Normal file
50
app/src/full/java/com/topjohnwu/magisk/utils/AppUtils.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,11 +2,12 @@ package com.topjohnwu.magisk.utils;
|
|||||||
|
|
||||||
import android.os.AsyncTask;
|
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.BuildConfig;
|
||||||
import com.topjohnwu.magisk.Data;
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.PatchAPK;
|
|
||||||
import com.topjohnwu.magisk.components.ProgressNotification;
|
import com.topjohnwu.magisk.components.ProgressNotification;
|
||||||
import com.topjohnwu.net.Networking;
|
import com.topjohnwu.net.Networking;
|
||||||
import com.topjohnwu.net.ResponseListener;
|
import com.topjohnwu.net.ResponseListener;
|
||||||
@ -18,7 +19,7 @@ import java.io.BufferedOutputStream;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
public class DlInstallManager {
|
public class DownloadApp {
|
||||||
|
|
||||||
public static void upgrade(String name) {
|
public static void upgrade(String name) {
|
||||||
dlInstall(name, new PatchPackageName());
|
dlInstall(name, new PatchPackageName());
|
||||||
@ -31,8 +32,7 @@ public class DlInstallManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void dlInstall(String name, ManagerDownloadListener listener) {
|
private static void dlInstall(String name, ManagerDownloadListener listener) {
|
||||||
MagiskManager mm = Data.MM();
|
File apk = new File(App.self.getFilesDir(), "manager.apk");
|
||||||
File apk = new File(mm.getFilesDir(), "manager.apk");
|
|
||||||
ProgressNotification progress = new ProgressNotification(name);
|
ProgressNotification progress = new ProgressNotification(name);
|
||||||
listener.setProgressNotification(progress);
|
listener.setProgressNotification(progress);
|
||||||
Networking.get(Data.managerLink)
|
Networking.get(Data.managerLink)
|
||||||
@ -63,23 +63,23 @@ public class DlInstallManager {
|
|||||||
@Override
|
@Override
|
||||||
public void onDownloadComplete(File apk, ProgressNotification progress) {
|
public void onDownloadComplete(File apk, ProgressNotification progress) {
|
||||||
File patched = apk;
|
File patched = apk;
|
||||||
MagiskManager mm = Data.MM();
|
App app = App.self;
|
||||||
if (!mm.getPackageName().equals(BuildConfig.APPLICATION_ID)) {
|
if (!App.self.getPackageName().equals(BuildConfig.APPLICATION_ID)) {
|
||||||
progress.getNotification()
|
progress.getNotification()
|
||||||
.setProgress(0, 0, true)
|
.setProgress(0, 0, true)
|
||||||
.setContentTitle(mm.getString(R.string.hide_manager_title))
|
.setContentTitle(app.getString(R.string.hide_manager_title))
|
||||||
.setContentText("");
|
.setContentText("");
|
||||||
progress.update();
|
progress.update();
|
||||||
patched = new File(apk.getParent(), "patched.apk");
|
patched = new File(apk.getParent(), "patched.apk");
|
||||||
try {
|
try {
|
||||||
JarMap jarMap = new JarMap(apk);
|
JarMap jarMap = new JarMap(apk);
|
||||||
PatchAPK.patch(jarMap, mm.getPackageName());
|
PatchAPK.patch(jarMap, app.getPackageName());
|
||||||
SignAPK.sign(jarMap, new BufferedOutputStream(new FileOutputStream(patched)));
|
SignAPK.sign(jarMap, new BufferedOutputStream(new FileOutputStream(patched)));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
APKInstall.install(mm, patched);
|
APKInstall.install(app, patched);
|
||||||
progress.dismiss();
|
progress.dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,17 +88,17 @@ public class DlInstallManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDownloadComplete(File apk, ProgressNotification progress) {
|
public void onDownloadComplete(File apk, ProgressNotification progress) {
|
||||||
MagiskManager mm = Data.MM();
|
App app = App.self;
|
||||||
progress.getNotification()
|
progress.getNotification()
|
||||||
.setProgress(0, 0, true)
|
.setProgress(0, 0, true)
|
||||||
.setContentTitle(mm.getString(R.string.restore_img_msg))
|
.setContentTitle(app.getString(R.string.restore_img_msg))
|
||||||
.setContentText("");
|
.setContentText("");
|
||||||
progress.update();
|
progress.update();
|
||||||
Data.exportPrefs();
|
Data.exportPrefs();
|
||||||
// Make it world readable
|
// Make it world readable
|
||||||
apk.setReadable(true, false);
|
apk.setReadable(true, false);
|
||||||
if (ShellUtils.fastCmdResult("pm install " + apk))
|
if (ShellUtils.fastCmdResult("pm install " + apk))
|
||||||
RootUtils.rmAndLaunch(mm.getPackageName(), BuildConfig.APPLICATION_ID);
|
RootUtils.rmAndLaunch(app.getPackageName(), BuildConfig.APPLICATION_ID);
|
||||||
progress.dismiss();
|
progress.dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,17 +1,16 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.magisk.utils;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
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.FlashActivity;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
|
||||||
import com.topjohnwu.magisk.components.BaseActivity;
|
import com.topjohnwu.magisk.components.BaseActivity;
|
||||||
import com.topjohnwu.magisk.components.ProgressNotification;
|
import com.topjohnwu.magisk.components.ProgressNotification;
|
||||||
import com.topjohnwu.magisk.container.Repo;
|
|
||||||
import com.topjohnwu.net.Networking;
|
import com.topjohnwu.net.Networking;
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
|
|
||||||
@ -28,26 +27,25 @@ import java.util.zip.ZipOutputStream;
|
|||||||
public class DownloadModule {
|
public class DownloadModule {
|
||||||
|
|
||||||
public static void exec(BaseActivity activity, Repo repo, boolean install) {
|
public static void exec(BaseActivity activity, Repo repo, boolean install) {
|
||||||
activity.runWithPermission(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
|
activity.runWithExternalRW(() -> AsyncTask.THREAD_POOL_EXECUTOR.execute(
|
||||||
() -> AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> dlProcessInstall(repo, install)));
|
() -> dlProcessInstall(repo, install)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void dlProcessInstall(Repo repo, boolean install) {
|
private static void dlProcessInstall(Repo repo, boolean install) {
|
||||||
File output = new File(Const.EXTERNAL_PATH, repo.getDownloadFilename());
|
File output = new File(Const.EXTERNAL_PATH, repo.getDownloadFilename());
|
||||||
ProgressNotification progress = new ProgressNotification(output.getName());
|
ProgressNotification progress = new ProgressNotification(output.getName());
|
||||||
try {
|
try {
|
||||||
MagiskManager mm = Data.MM();
|
|
||||||
InputStream in = Networking.get(repo.getZipUrl())
|
InputStream in = Networking.get(repo.getZipUrl())
|
||||||
.setDownloadProgressListener(progress)
|
.setDownloadProgressListener(progress)
|
||||||
.execForInputStream().getResult();
|
.execForInputStream().getResult();
|
||||||
removeTopFolder(in, new BufferedOutputStream(new FileOutputStream(output)));
|
removeTopFolder(in, new BufferedOutputStream(new FileOutputStream(output)));
|
||||||
if (install) {
|
if (install) {
|
||||||
progress.dismiss();
|
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))
|
intent.setData(Uri.fromFile(output))
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
|
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
|
||||||
mm.startActivity(intent);
|
App.self.startActivity(intent);
|
||||||
} else {
|
} else {
|
||||||
progress.getNotification().setContentTitle(output.getName());
|
progress.getNotification().setContentTitle(output.getName());
|
||||||
progress.dlDone();
|
progress.dlDone();
|
@ -16,9 +16,9 @@ import android.security.keystore.KeyProperties;
|
|||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.utils.Utils;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.components.CustomAlertDialog;
|
import com.topjohnwu.magisk.components.CustomAlertDialog;
|
||||||
|
|
||||||
@ -36,10 +36,9 @@ public abstract class FingerprintHelper {
|
|||||||
private CancellationSignal cancel;
|
private CancellationSignal cancel;
|
||||||
|
|
||||||
public static boolean useFingerPrint() {
|
public static boolean useFingerPrint() {
|
||||||
MagiskManager mm = Data.MM();
|
boolean fp = App.self.mDB.getSettings(Const.Key.SU_FINGERPRINT, 0) != 0;
|
||||||
boolean fp = mm.mDB.getSettings(Const.Key.SU_FINGERPRINT, 0) != 0;
|
|
||||||
if (fp && !canUseFingerprint()) {
|
if (fp && !canUseFingerprint()) {
|
||||||
mm.mDB.setSettings(Const.Key.SU_FINGERPRINT, 0);
|
App.self.mDB.setSettings(Const.Key.SU_FINGERPRINT, 0);
|
||||||
fp = false;
|
fp = false;
|
||||||
}
|
}
|
||||||
return fp;
|
return fp;
|
||||||
@ -48,9 +47,8 @@ public abstract class FingerprintHelper {
|
|||||||
public static boolean canUseFingerprint() {
|
public static boolean canUseFingerprint() {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||||
return false;
|
return false;
|
||||||
MagiskManager mm = Data.MM();
|
KeyguardManager km = App.self.getSystemService(KeyguardManager.class);
|
||||||
KeyguardManager km = mm.getSystemService(KeyguardManager.class);
|
FingerprintManager fm = App.self.getSystemService(FingerprintManager.class);
|
||||||
FingerprintManager fm = mm.getSystemService(FingerprintManager.class);
|
|
||||||
return km.isKeyguardSecure() && fm != null && fm.isHardwareDetected() && fm.hasEnrolledFingerprints();
|
return km.isKeyguardSecure() && fm != null && fm.isHardwareDetected() && fm.hasEnrolledFingerprints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +104,7 @@ public abstract class FingerprintHelper {
|
|||||||
|
|
||||||
protected FingerprintHelper() throws Exception {
|
protected FingerprintHelper() throws Exception {
|
||||||
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
|
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||||
manager = Data.MM().getSystemService(FingerprintManager.class);
|
manager = App.self.getSystemService(FingerprintManager.class);
|
||||||
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
|
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
|
||||||
+ KeyProperties.BLOCK_MODE_CBC + "/"
|
+ KeyProperties.BLOCK_MODE_CBC + "/"
|
||||||
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.magisk.utils;
|
||||||
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.widget.Toast;
|
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.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.R;
|
||||||
import com.topjohnwu.magisk.components.Notifications;
|
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.superuser.ShellUtils;
|
||||||
import com.topjohnwu.utils.JarMap;
|
import com.topjohnwu.utils.JarMap;
|
||||||
import com.topjohnwu.utils.SignAPK;
|
import com.topjohnwu.utils.SignAPK;
|
||||||
@ -95,14 +95,14 @@ public class PatchAPK {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean patchAndHide() {
|
private static boolean patchAndHide() {
|
||||||
MagiskManager mm = Data.MM();
|
App app = App.self;
|
||||||
|
|
||||||
// Generate a new app with random package name
|
// 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());
|
String pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
JarMap apk = new JarMap(mm.getPackageCodePath());
|
JarMap apk = new JarMap(app.getPackageCodePath());
|
||||||
if (!patch(apk, pkg))
|
if (!patch(apk, pkg))
|
||||||
return false;
|
return false;
|
||||||
SignAPK.sign(apk, new BufferedOutputStream(new FileOutputStream(repack)));
|
SignAPK.sign(apk, new BufferedOutputStream(new FileOutputStream(repack)));
|
||||||
@ -115,7 +115,7 @@ public class PatchAPK {
|
|||||||
if (!ShellUtils.fastCmdResult("pm install " + repack))
|
if (!ShellUtils.fastCmdResult("pm install " + repack))
|
||||||
return false;;
|
return false;;
|
||||||
|
|
||||||
mm.mDB.setStrings(Const.Key.SU_MANAGER, pkg);
|
app.mDB.setStrings(Const.Key.SU_MANAGER, pkg);
|
||||||
Data.exportPrefs();
|
Data.exportPrefs();
|
||||||
RootUtils.rmAndLaunch(BuildConfig.APPLICATION_ID, pkg);
|
RootUtils.rmAndLaunch(BuildConfig.APPLICATION_ID, pkg);
|
||||||
|
|
||||||
@ -143,10 +143,10 @@ public class PatchAPK {
|
|||||||
|
|
||||||
public static void hideManager() {
|
public static void hideManager() {
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
MagiskManager mm = Data.MM();
|
App app = App.self;
|
||||||
NotificationCompat.Builder progress =
|
NotificationCompat.Builder progress =
|
||||||
Notifications.progress(mm.getString(R.string.hide_manager_title));
|
Notifications.progress(app.getString(R.string.hide_manager_title));
|
||||||
NotificationManagerCompat mgr = NotificationManagerCompat.from(mm);
|
NotificationManagerCompat mgr = NotificationManagerCompat.from(app);
|
||||||
mgr.notify(Const.ID.HIDE_MANAGER_NOTIFICATION_ID, progress.build());
|
mgr.notify(Const.ID.HIDE_MANAGER_NOTIFICATION_ID, progress.build());
|
||||||
boolean b = patchAndHide();
|
boolean b = patchAndHide();
|
||||||
mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID);
|
mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID);
|
@ -9,12 +9,13 @@ import android.os.Process;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
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.R;
|
||||||
import com.topjohnwu.magisk.container.Policy;
|
|
||||||
import com.topjohnwu.magisk.container.SuLogEntry;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
@ -76,8 +77,8 @@ public abstract class SuConnector {
|
|||||||
if (fromUid < 0) return;
|
if (fromUid < 0) return;
|
||||||
if (fromUid == Process.myUid()) return;
|
if (fromUid == Process.myUid()) return;
|
||||||
|
|
||||||
MagiskManager mm = Data.MM();
|
App app = App.self;
|
||||||
PackageManager pm = mm.getPackageManager();
|
PackageManager pm = app.getPackageManager();
|
||||||
Policy policy;
|
Policy policy;
|
||||||
|
|
||||||
boolean notify;
|
boolean notify;
|
||||||
@ -91,7 +92,7 @@ public abstract class SuConnector {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Doesn't report whether notify or not, check database ourselves
|
// Doesn't report whether notify or not, check database ourselves
|
||||||
policy = mm.mDB.getPolicy(fromUid);
|
policy = app.mDB.getPolicy(fromUid);
|
||||||
if (policy == null)
|
if (policy == null)
|
||||||
return;
|
return;
|
||||||
notify = policy.notification;
|
notify = policy.notification;
|
||||||
@ -116,24 +117,22 @@ public abstract class SuConnector {
|
|||||||
log.fromPid = pid;
|
log.fromPid = pid;
|
||||||
log.command = command;
|
log.command = command;
|
||||||
log.date = new Date();
|
log.date = new Date();
|
||||||
mm.mDB.addLog(log);
|
app.mDB.addLog(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handleNotify(Policy policy) {
|
private static void handleNotify(Policy policy) {
|
||||||
MagiskManager mm = Data.MM();
|
String message = App.self.getString(policy.policy == Policy.ALLOW ?
|
||||||
String message = mm.getString(policy.policy == Policy.ALLOW ?
|
|
||||||
R.string.su_allow_toast : R.string.su_deny_toast, policy.appName);
|
R.string.su_allow_toast : R.string.su_deny_toast, policy.appName);
|
||||||
if (policy.notification && Data.suNotificationType == Const.Value.NOTIFICATION_TOAST)
|
if (policy.notification && Data.suNotificationType == Const.Value.NOTIFICATION_TOAST)
|
||||||
Utils.toast(message, Toast.LENGTH_SHORT);
|
Utils.toast(message, Toast.LENGTH_SHORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void handleNotify(Intent intent) {
|
public static void handleNotify(Intent intent) {
|
||||||
MagiskManager mm = Data.MM();
|
|
||||||
int fromUid = intent.getIntExtra("from.uid", -1);
|
int fromUid = intent.getIntExtra("from.uid", -1);
|
||||||
if (fromUid < 0) return;
|
if (fromUid < 0) return;
|
||||||
if (fromUid == Process.myUid()) return;
|
if (fromUid == Process.myUid()) return;
|
||||||
try {
|
try {
|
||||||
Policy policy = new Policy(fromUid, mm.getPackageManager());
|
Policy policy = new Policy(fromUid, App.self.getPackageManager());
|
||||||
policy.policy = intent.getIntExtra("policy", -1);
|
policy.policy = intent.getIntExtra("policy", -1);
|
||||||
if (policy.policy >= 0)
|
if (policy.policy >= 0)
|
||||||
handleNotify(policy);
|
handleNotify(policy);
|
||||||
|
@ -6,12 +6,6 @@ import android.net.NetworkInfo;
|
|||||||
|
|
||||||
public class Download {
|
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) {
|
public static boolean checkNetworkStatus(Context context) {
|
||||||
ConnectivityManager manager = (ConnectivityManager)
|
ConnectivityManager manager = (ConnectivityManager)
|
||||||
context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
2
build.py
2
build.py
@ -242,7 +242,7 @@ def build_apk(args, flavor):
|
|||||||
|
|
||||||
def build_app(args):
|
def build_app(args):
|
||||||
source = os.path.join('scripts', 'util_functions.sh')
|
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)
|
cp(source, target)
|
||||||
build_apk(args, 'Full')
|
build_apk(args, 'Full')
|
||||||
|
|
||||||
|
2
core/.gitignore
vendored
Normal file
2
core/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/build
|
||||||
|
src/main/res/raw/util_functions.sh
|
33
core/build.gradle
Normal file
33
core/build.gradle
Normal file
@ -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'
|
||||||
|
}
|
21
core/proguard-rules.pro
vendored
Normal file
21
core/proguard-rules.pro
vendored
Normal file
@ -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
|
2
core/src/main/AndroidManifest.xml
Normal file
2
core/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.topjohnwu.core" />
|
@ -1,30 +1,31 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.core;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.database.MagiskDB;
|
import com.topjohnwu.core.database.MagiskDB;
|
||||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
import com.topjohnwu.core.database.RepoDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
import com.topjohnwu.core.utils.LocaleManager;
|
||||||
import com.topjohnwu.magisk.utils.RootUtils;
|
import com.topjohnwu.core.utils.RootUtils;
|
||||||
import com.topjohnwu.superuser.ContainerApp;
|
import com.topjohnwu.superuser.ContainerApp;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
public class App extends ContainerApp {
|
||||||
|
|
||||||
public class MagiskManager extends ContainerApp {
|
public static App self;
|
||||||
|
public static Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||||
// Info
|
public boolean init = false;
|
||||||
public boolean hasInit = false;
|
|
||||||
|
|
||||||
// Global resources
|
// Global resources
|
||||||
public SharedPreferences prefs;
|
public SharedPreferences prefs;
|
||||||
public RepoDatabaseHelper repoDB;
|
|
||||||
public MagiskDB mDB;
|
public MagiskDB mDB;
|
||||||
|
public RepoDatabaseHelper repoDB;
|
||||||
|
|
||||||
public MagiskManager() {
|
public App() {
|
||||||
Data.weakApp = new WeakReference<>(this);
|
self = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -37,8 +38,8 @@ public class MagiskManager extends ContainerApp {
|
|||||||
Shell.Config.setTimeout(2);
|
Shell.Config.setTimeout(2);
|
||||||
|
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
repoDB = new RepoDatabaseHelper(this);
|
|
||||||
mDB = new MagiskDB(this);
|
mDB = new MagiskDB(this);
|
||||||
|
repoDB = new RepoDatabaseHelper(this);
|
||||||
|
|
||||||
LocaleManager.setLocale(this);
|
LocaleManager.setLocale(this);
|
||||||
Data.loadConfig();
|
Data.loadConfig();
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.core;
|
||||||
|
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
@ -39,7 +39,7 @@ public class Const {
|
|||||||
|
|
||||||
/* A list of apps that should not be shown as hide-able */
|
/* A list of apps that should not be shown as hide-able */
|
||||||
public static final List<String> HIDE_BLACKLIST = Arrays.asList(
|
public static final List<String> HIDE_BLACKLIST = Arrays.asList(
|
||||||
Data.MM().getPackageName(),
|
App.self.getPackageName(),
|
||||||
"com.google.android.gms"
|
"com.google.android.gms"
|
||||||
);
|
);
|
||||||
|
|
@ -1,16 +1,9 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.core;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.util.Xml;
|
import android.util.Xml;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.components.AboutCardRow;
|
import com.topjohnwu.core.utils.Utils;
|
||||||
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.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
import com.topjohnwu.superuser.io.SuFile;
|
import com.topjohnwu.superuser.io.SuFile;
|
||||||
@ -21,15 +14,8 @@ import org.xmlpull.v1.XmlPullParserException;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class Data {
|
public class Data {
|
||||||
// Global app instance
|
|
||||||
public static WeakReference<MagiskManager> weakApp;
|
|
||||||
public static Handler mainHandler = new Handler(Looper.getMainLooper());
|
|
||||||
public static Map<Class, Class> classMap = new HashMap<>();
|
|
||||||
|
|
||||||
// Current status
|
// Current status
|
||||||
public static String magiskVersionString;
|
public static String magiskVersionString;
|
||||||
@ -55,29 +41,12 @@ public class Data {
|
|||||||
// Configs
|
// Configs
|
||||||
public static boolean isDarkTheme;
|
public static boolean isDarkTheme;
|
||||||
public static int suRequestTimeout;
|
public static int suRequestTimeout;
|
||||||
public static int suLogTimeout = 14;
|
|
||||||
public static int multiuserState = -1;
|
public static int multiuserState = -1;
|
||||||
public static int suResponseType;
|
public static int suResponseType;
|
||||||
public static int suNotificationType;
|
public static int suNotificationType;
|
||||||
public static int updateChannel;
|
public static int updateChannel;
|
||||||
public static int repoOrder;
|
public static int repoOrder;
|
||||||
|
public static int suLogTimeout = 14;
|
||||||
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 void loadMagiskInfo() {
|
public static void loadMagiskInfo() {
|
||||||
try {
|
try {
|
||||||
@ -87,24 +56,19 @@ public class Data {
|
|||||||
} catch (NumberFormatException ignored) {}
|
} catch (NumberFormatException ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MagiskManager MM() {
|
|
||||||
return weakApp.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void exportPrefs() {
|
public static void exportPrefs() {
|
||||||
// Flush prefs to disk
|
// Flush prefs to disk
|
||||||
MagiskManager mm = MM();
|
App app = App.self;
|
||||||
mm.prefs.edit().commit();
|
app.prefs.edit().commit();
|
||||||
File xml = new File(mm.getFilesDir().getParent() + "/shared_prefs",
|
File xml = new File(app.getFilesDir().getParent() + "/shared_prefs",
|
||||||
mm.getPackageName() + "_preferences.xml");
|
app.getPackageName() + "_preferences.xml");
|
||||||
Shell.su(Utils.fmt("cat %s > /data/user/0/%s", xml, Const.MANAGER_CONFIGS)).exec();
|
Shell.su(Utils.fmt("cat %s > /data/user/0/%s", xml, Const.MANAGER_CONFIGS)).exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void importPrefs() {
|
public static void importPrefs() {
|
||||||
MagiskManager mm = MM();
|
|
||||||
SuFile config = new SuFile("/data/user/0/" + Const.MANAGER_CONFIGS);
|
SuFile config = new SuFile("/data/user/0/" + Const.MANAGER_CONFIGS);
|
||||||
if (config.exists()) {
|
if (config.exists()) {
|
||||||
SharedPreferences.Editor editor = mm.prefs.edit();
|
SharedPreferences.Editor editor = App.self.prefs.edit();
|
||||||
try {
|
try {
|
||||||
SuFileInputStream is = new SuFileInputStream(config);
|
SuFileInputStream is = new SuFileInputStream(config);
|
||||||
XmlPullParser parser = Xml.newPullParser();
|
XmlPullParser parser = Xml.newPullParser();
|
||||||
@ -162,20 +126,20 @@ public class Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void loadConfig() {
|
public static void loadConfig() {
|
||||||
MagiskManager mm = MM();
|
App app = App.self;
|
||||||
// su
|
// su
|
||||||
suRequestTimeout = Utils.getPrefsInt(mm.prefs, Const.Key.SU_REQUEST_TIMEOUT, Const.Value.timeoutList[2]);
|
suRequestTimeout = Utils.getPrefsInt(app.prefs, Const.Key.SU_REQUEST_TIMEOUT, Const.Value.timeoutList[2]);
|
||||||
suResponseType = Utils.getPrefsInt(mm.prefs, Const.Key.SU_AUTO_RESPONSE, Const.Value.SU_PROMPT);
|
suResponseType = Utils.getPrefsInt(app.prefs, Const.Key.SU_AUTO_RESPONSE, Const.Value.SU_PROMPT);
|
||||||
suNotificationType = Utils.getPrefsInt(mm.prefs, Const.Key.SU_NOTIFICATION, Const.Value.NOTIFICATION_TOAST);
|
suNotificationType = Utils.getPrefsInt(app.prefs, Const.Key.SU_NOTIFICATION, Const.Value.NOTIFICATION_TOAST);
|
||||||
|
|
||||||
// config
|
// config
|
||||||
isDarkTheme = mm.prefs.getBoolean(Const.Key.DARK_THEME, false);
|
isDarkTheme = app.prefs.getBoolean(Const.Key.DARK_THEME, false);
|
||||||
updateChannel = Utils.getPrefsInt(mm.prefs, Const.Key.UPDATE_CHANNEL, Const.Value.STABLE_CHANNEL);
|
updateChannel = Utils.getPrefsInt(app.prefs, Const.Key.UPDATE_CHANNEL, Const.Value.STABLE_CHANNEL);
|
||||||
repoOrder = mm.prefs.getInt(Const.Key.REPO_ORDER, Const.Value.ORDER_DATE);
|
repoOrder = app.prefs.getInt(Const.Key.REPO_ORDER, Const.Value.ORDER_DATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeConfig() {
|
public static void writeConfig() {
|
||||||
MM().prefs.edit()
|
App.self.prefs.edit()
|
||||||
.putBoolean(Const.Key.DARK_THEME, isDarkTheme)
|
.putBoolean(Const.Key.DARK_THEME, isDarkTheme)
|
||||||
.putBoolean(Const.Key.MAGISKHIDE, magiskHide)
|
.putBoolean(Const.Key.MAGISKHIDE, magiskHide)
|
||||||
.putBoolean(Const.Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists())
|
.putBoolean(Const.Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists())
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk.container;
|
package com.topjohnwu.core.container;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk.container;
|
package com.topjohnwu.core.container;
|
||||||
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
import com.topjohnwu.superuser.io.SuFile;
|
import com.topjohnwu.superuser.io.SuFile;
|
@ -1,10 +1,10 @@
|
|||||||
package com.topjohnwu.magisk.container;
|
package com.topjohnwu.core.container;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.core.utils.Utils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
@ -1,12 +1,11 @@
|
|||||||
package com.topjohnwu.magisk.container;
|
package com.topjohnwu.core.container;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.core.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.core.utils.Utils;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -73,7 +72,7 @@ public class Repo extends BaseModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getDownloadFilename() {
|
public String getDownloadFilename() {
|
||||||
return Download.getLegalFilename(getName() + "-" + getVersion() + ".zip");
|
return Utils.getLegalFilename(getName() + "-" + getVersion() + ".zip");
|
||||||
}
|
}
|
||||||
|
|
||||||
public class IllegalRepoException extends Exception {
|
public class IllegalRepoException extends Exception {
|
@ -1,8 +1,8 @@
|
|||||||
package com.topjohnwu.magisk.container;
|
package com.topjohnwu.core.container;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
import com.topjohnwu.core.utils.LocaleManager;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk.container;
|
package com.topjohnwu.core.container;
|
||||||
|
|
||||||
import org.kamranzafar.jtar.TarHeader;
|
import org.kamranzafar.jtar.TarHeader;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk.container;
|
package com.topjohnwu.core.container;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
@ -1,16 +1,16 @@
|
|||||||
package com.topjohnwu.magisk.database;
|
package com.topjohnwu.core.database;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Data;
|
||||||
import com.topjohnwu.magisk.container.Policy;
|
import com.topjohnwu.core.container.Policy;
|
||||||
import com.topjohnwu.magisk.container.SuLogEntry;
|
import com.topjohnwu.core.container.SuLogEntry;
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
import com.topjohnwu.core.utils.LocaleManager;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.core.utils.Utils;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
@ -23,7 +23,7 @@ import java.util.Map;
|
|||||||
public class MagiskDB {
|
public class MagiskDB {
|
||||||
|
|
||||||
private static final String POLICY_TABLE = "policies";
|
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 SETTINGS_TABLE = "settings";
|
||||||
private static final String STRINGS_TABLE = "strings";
|
private static final String STRINGS_TABLE = "strings";
|
||||||
|
|
@ -1,15 +1,14 @@
|
|||||||
package com.topjohnwu.magisk.database;
|
package com.topjohnwu.core.database;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.Data;
|
||||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
import com.topjohnwu.core.container.Repo;
|
||||||
import com.topjohnwu.magisk.container.Repo;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -20,12 +19,10 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
private static final String TABLE_NAME = "repos";
|
private static final String TABLE_NAME = "repos";
|
||||||
|
|
||||||
private SQLiteDatabase mDb;
|
private SQLiteDatabase mDb;
|
||||||
private MagiskManager mm;
|
private Runnable adapterCb;
|
||||||
private ReposAdapter adapter;
|
|
||||||
|
|
||||||
public RepoDatabaseHelper(Context context) {
|
public RepoDatabaseHelper(Context context) {
|
||||||
super(context, "repo.db", null, DATABASE_VER);
|
super(context, "repo.db", null, DATABASE_VER);
|
||||||
mm = Data.MM();
|
|
||||||
mDb = getWritableDatabase();
|
mDb = getWritableDatabase();
|
||||||
|
|
||||||
// Remove outdated repos
|
// Remove outdated repos
|
||||||
@ -46,7 +43,7 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " +
|
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " +
|
||||||
"(id TEXT, name TEXT, version TEXT, versionCode INT, minMagisk INT, " +
|
"(id TEXT, name TEXT, version TEXT, versionCode INT, minMagisk INT, " +
|
||||||
"author TEXT, description TEXT, last_update INT, PRIMARY KEY(id))");
|
"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;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerAdapter(ReposAdapter a) {
|
public void registerAdapterCallback(Runnable cb) {
|
||||||
adapter = a;
|
adapterCb = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterAdapter() {
|
public void unregisterAdapterCallback() {
|
||||||
adapter = null;
|
adapterCb = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyAdapter() {
|
private void notifyAdapter() {
|
||||||
if (adapter != null) {
|
if (adapterCb != null) {
|
||||||
Data.mainHandler.post(adapter::notifyDBChanged);
|
App.mainHandler.post(adapterCb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,9 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.core.tasks;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.BuildConfig;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Data;
|
||||||
import com.topjohnwu.magisk.components.Notifications;
|
import com.topjohnwu.core.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
|
||||||
import com.topjohnwu.net.Networking;
|
import com.topjohnwu.net.Networking;
|
||||||
import com.topjohnwu.net.ResponseListener;
|
import com.topjohnwu.net.ResponseListener;
|
||||||
|
|
||||||
@ -51,7 +50,7 @@ public class CheckUpdates {
|
|||||||
url = Const.Url.BETA_URL;
|
url = Const.Url.BETA_URL;
|
||||||
break;
|
break;
|
||||||
case Const.Value.CUSTOM_CHANNEL:
|
case Const.Value.CUSTOM_CHANNEL:
|
||||||
url = Data.MM().prefs.getString(Const.Key.CUSTOM_CHANNEL, "");
|
url = App.self.prefs.getString(Const.Key.CUSTOM_CHANNEL, "");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
@ -89,15 +88,10 @@ public class CheckUpdates {
|
|||||||
JSONObject uninstaller = getJson(json, "uninstaller");
|
JSONObject uninstaller = getJson(json, "uninstaller");
|
||||||
Data.uninstallerLink = getString(uninstaller, "link", null);
|
Data.uninstallerLink = getString(uninstaller, "link", null);
|
||||||
|
|
||||||
if (cb != null) {
|
Topic.publish(Topic.UPDATE_CHECK_DONE);
|
||||||
if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) {
|
|
||||||
Notifications.managerUpdate();
|
if (cb != null)
|
||||||
} else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) {
|
|
||||||
Notifications.magiskUpdate();
|
|
||||||
}
|
|
||||||
cb.run();
|
cb.run();
|
||||||
}
|
}
|
||||||
Topic.publish(Topic.UPDATE_CHECK_DONE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
83
core/src/main/java/com/topjohnwu/core/tasks/FlashZip.java
Normal file
83
core/src/main/java/com/topjohnwu/core/tasks/FlashZip.java
Normal file
@ -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<String> console, logs;
|
||||||
|
|
||||||
|
public FlashZip(Uri uri, List<String> out, List<String> 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);
|
||||||
|
}
|
288
core/src/main/java/com/topjohnwu/core/tasks/MagiskInstaller.java
Normal file
288
core/src/main/java/com/topjohnwu/core/tasks/MagiskInstaller.java
Normal file
@ -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<String> 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<String> out, List<String> 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<String> 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));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.core.tasks;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
@ -1,11 +1,11 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.core.tasks;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.utils.ISafetyNetHelper;
|
import com.topjohnwu.core.utils.ISafetyNetHelper;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.core.utils.Topic;
|
||||||
import com.topjohnwu.net.Networking;
|
import com.topjohnwu.net.Networking;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ import dalvik.system.DexClassLoader;
|
|||||||
public class SafetyNet {
|
public class SafetyNet {
|
||||||
|
|
||||||
public static final File EXT_APK =
|
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 {
|
private static void dyRun(Activity activity) throws Exception {
|
||||||
DexClassLoader loader = new DexClassLoader(EXT_APK.getPath(), EXT_APK.getParent(),
|
DexClassLoader loader = new DexClassLoader(EXT_APK.getPath(), EXT_APK.getParent(),
|
@ -1,15 +1,14 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.core.tasks;
|
||||||
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.container.Repo;
|
||||||
import com.topjohnwu.magisk.container.Repo;
|
import com.topjohnwu.core.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.core.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.core.utils.Utils;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.net.Networking;
|
import com.topjohnwu.net.Networking;
|
||||||
import com.topjohnwu.net.Request;
|
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 int CORE_POOL_SIZE = Math.max(2, CPU_COUNT - 1);
|
||||||
private static final DateFormat dateFormat;
|
private static final DateFormat dateFormat;
|
||||||
|
|
||||||
private MagiskManager mm;
|
private App app = App.self;
|
||||||
private Set<String> cached;
|
private Set<String> cached;
|
||||||
private ExecutorService threadPool;
|
private ExecutorService threadPool;
|
||||||
|
|
||||||
@ -44,10 +43,6 @@ public class UpdateRepos {
|
|||||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateRepos() {
|
|
||||||
mm = Data.MM();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void waitTasks() {
|
private void waitTasks() {
|
||||||
threadPool.shutdown();
|
threadPool.shutdown();
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -64,17 +59,17 @@ public class UpdateRepos {
|
|||||||
String id = rawRepo.getString("name");
|
String id = rawRepo.getString("name");
|
||||||
Date date = dateFormat.parse(rawRepo.getString("pushed_at"));
|
Date date = dateFormat.parse(rawRepo.getString("pushed_at"));
|
||||||
threadPool.execute(() -> {
|
threadPool.execute(() -> {
|
||||||
Repo repo = mm.repoDB.getRepo(id);
|
Repo repo = app.repoDB.getRepo(id);
|
||||||
try {
|
try {
|
||||||
if (repo == null)
|
if (repo == null)
|
||||||
repo = new Repo(id);
|
repo = new Repo(id);
|
||||||
else
|
else
|
||||||
cached.remove(id);
|
cached.remove(id);
|
||||||
repo.update(date);
|
repo.update(date);
|
||||||
mm.repoDB.addRepo(repo);
|
app.repoDB.addRepo(repo);
|
||||||
} catch (Repo.IllegalRepoException e) {
|
} catch (Repo.IllegalRepoException e) {
|
||||||
Logger.debug(e.getMessage());
|
Logger.debug(e.getMessage());
|
||||||
mm.repoDB.removeRepo(id);
|
app.repoDB.removeRepo(id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -86,7 +81,7 @@ public class UpdateRepos {
|
|||||||
private boolean loadPage(int page) {
|
private boolean loadPage(int page) {
|
||||||
Request req = Networking.get(Utils.fmt(Const.Url.REPO_URL, page + 1));
|
Request req = Networking.get(Utils.fmt(Const.Url.REPO_URL, page + 1));
|
||||||
if (page == 0) {
|
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)
|
if (etag != null)
|
||||||
req.addHeaders(Const.Key.IF_NONE_MATCH, etag);
|
req.addHeaders(Const.Key.IF_NONE_MATCH, etag);
|
||||||
}
|
}
|
||||||
@ -115,7 +110,7 @@ public class UpdateRepos {
|
|||||||
String etag = res.getConnection().getHeaderField(Const.Key.ETAG_KEY);
|
String etag = res.getConnection().getHeaderField(Const.Key.ETAG_KEY);
|
||||||
if (etag != null) {
|
if (etag != null) {
|
||||||
etag = etag.substring(etag.indexOf('\"'), etag.lastIndexOf('\"') + 1);
|
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() {
|
private void fullReload() {
|
||||||
Cursor c = mm.repoDB.getRawCursor();
|
Cursor c = app.repoDB.getRawCursor();
|
||||||
while (c.moveToNext()) {
|
while (c.moveToNext()) {
|
||||||
Repo repo = new Repo(c);
|
Repo repo = new Repo(c);
|
||||||
threadPool.execute(() -> {
|
threadPool.execute(() -> {
|
||||||
try {
|
try {
|
||||||
repo.update();
|
repo.update();
|
||||||
mm.repoDB.addRepo(repo);
|
app.repoDB.addRepo(repo);
|
||||||
} catch (Repo.IllegalRepoException e) {
|
} catch (Repo.IllegalRepoException e) {
|
||||||
Logger.debug(e.getMessage());
|
Logger.debug(e.getMessage());
|
||||||
mm.repoDB.removeRepo(repo);
|
app.repoDB.removeRepo(repo);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -147,13 +142,13 @@ public class UpdateRepos {
|
|||||||
public void exec(boolean force) {
|
public void exec(boolean force) {
|
||||||
Topic.reset(Topic.REPO_LOAD_DONE);
|
Topic.reset(Topic.REPO_LOAD_DONE);
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
cached = Collections.synchronizedSet(mm.repoDB.getRepoIDSet());
|
cached = Collections.synchronizedSet(app.repoDB.getRepoIDSet());
|
||||||
threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE);
|
threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE);
|
||||||
|
|
||||||
if (loadPages()) {
|
if (loadPages()) {
|
||||||
waitTasks();
|
waitTasks();
|
||||||
// The leftover cached means they are removed from online repo
|
// The leftover cached means they are removed from online repo
|
||||||
mm.repoDB.removeRepo(cached);
|
app.repoDB.removeRepo(cached);
|
||||||
} else if (force) {
|
} else if (force) {
|
||||||
fullReload();
|
fullReload();
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
package com.topjohnwu.core.utils;
|
||||||
|
|
||||||
import com.topjohnwu.utils.SignBoot;
|
import com.topjohnwu.utils.SignBoot;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
package com.topjohnwu.core.utils;
|
||||||
|
|
||||||
public interface ISafetyNetHelper {
|
public interface ISafetyNetHelper {
|
||||||
|
|
@ -1,13 +1,11 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
package com.topjohnwu.core.utils;
|
||||||
|
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -22,15 +20,15 @@ public class LocaleManager {
|
|||||||
public final static Locale defaultLocale = Locale.getDefault();
|
public final static Locale defaultLocale = Locale.getDefault();
|
||||||
public static List<Locale> locales;
|
public static List<Locale> locales;
|
||||||
|
|
||||||
public static void setLocale(MagiskManager mm) {
|
public static void setLocale(App app) {
|
||||||
String localeConfig = mm.prefs.getString(Const.Key.LOCALE, "");
|
String localeConfig = app.prefs.getString(Const.Key.LOCALE, "");
|
||||||
if (localeConfig.isEmpty()) {
|
if (localeConfig.isEmpty()) {
|
||||||
locale = defaultLocale;
|
locale = defaultLocale;
|
||||||
} else {
|
} else {
|
||||||
locale = Locale.forLanguageTag(localeConfig);
|
locale = Locale.forLanguageTag(localeConfig);
|
||||||
}
|
}
|
||||||
Locale.setDefault(locale);
|
Locale.setDefault(locale);
|
||||||
Resources res = mm.getResources();
|
Resources res = app.getResources();
|
||||||
Configuration config = res.getConfiguration();
|
Configuration config = res.getConfiguration();
|
||||||
config.setLocale(locale);
|
config.setLocale(locale);
|
||||||
res.updateConfiguration(config, res.getDisplayMetrics());
|
res.updateConfiguration(config, res.getDisplayMetrics());
|
||||||
@ -39,18 +37,16 @@ public class LocaleManager {
|
|||||||
public static String getString(Locale locale, @StringRes int id) {
|
public static String getString(Locale locale, @StringRes int id) {
|
||||||
Configuration config = new Configuration();
|
Configuration config = new Configuration();
|
||||||
config.setLocale(locale);
|
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(() -> {
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
locales = new ArrayList<>();
|
locales = new ArrayList<>();
|
||||||
HashSet<String> set = new HashSet<>();
|
HashSet<String> set = new HashSet<>();
|
||||||
Resources res = Data.MM().getResources();
|
Resources res = App.self.getResources();
|
||||||
Locale locale;
|
Locale locale;
|
||||||
|
|
||||||
@StringRes int compareId = R.string.download_file_error;
|
|
||||||
|
|
||||||
// Add default locale
|
// Add default locale
|
||||||
locales.add(Locale.ENGLISH);
|
locales.add(Locale.ENGLISH);
|
||||||
set.add(getString(Locale.ENGLISH, compareId));
|
set.add(getString(Locale.ENGLISH, compareId));
|
@ -1,9 +1,9 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
package com.topjohnwu.core.utils;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.BuildConfig;
|
import com.topjohnwu.core.BuildConfig;
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.Const;
|
||||||
|
|
||||||
public class Logger {
|
public class Logger {
|
||||||
|
|
@ -1,10 +1,10 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
package com.topjohnwu.core.utils;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Data;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.core.R;
|
||||||
import com.topjohnwu.superuser.BusyBox;
|
import com.topjohnwu.superuser.BusyBox;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
import com.topjohnwu.superuser.ShellUtils;
|
@ -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.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
@ -67,7 +67,7 @@ public class Topic {
|
|||||||
topicList[topic].published = true;
|
topicList[topic].published = true;
|
||||||
}
|
}
|
||||||
for (Subscriber sub : topicList[topic].subscribers) {
|
for (Subscriber sub : topicList[topic].subscribers) {
|
||||||
Data.mainHandler.post(() -> sub.onPublish(topic, results));
|
App.mainHandler.post(() -> sub.onPublish(topic, results));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@ -13,16 +9,15 @@ import android.content.res.Resources;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.core.App;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.core.Const;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.core.Data;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.core.container.Module;
|
||||||
import com.topjohnwu.magisk.container.Module;
|
import com.topjohnwu.core.container.ValueSortedMap;
|
||||||
import com.topjohnwu.magisk.container.ValueSortedMap;
|
|
||||||
import com.topjohnwu.magisk.services.UpdateCheckService;
|
|
||||||
import com.topjohnwu.net.Networking;
|
import com.topjohnwu.net.Networking;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
import com.topjohnwu.superuser.io.SuFile;
|
import com.topjohnwu.superuser.io.SuFile;
|
||||||
@ -32,6 +27,19 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class Utils {
|
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) {
|
public static int getPrefsInt(SharedPreferences prefs, String key, int def) {
|
||||||
return Integer.parseInt(prefs.getString(key, String.valueOf(def)));
|
return Integer.parseInt(prefs.getString(key, String.valueOf(def)));
|
||||||
}
|
}
|
||||||
@ -59,7 +67,7 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int dpInPx(int dp) {
|
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);
|
return (int) (dp * scale + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,51 +75,23 @@ public class Utils {
|
|||||||
return String.format(Locale.US, fmt, args);
|
return String.format(Locale.US, fmt, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String dos2unix(String s) {
|
public static String getAppLabel(ApplicationInfo info, PackageManager pm) {
|
||||||
String newString = s.replace("\r\n", "\n");
|
try {
|
||||||
if(!newString.endsWith("\n")) {
|
if (info.labelRes > 0) {
|
||||||
return newString + "\n";
|
Resources res = pm.getResourcesForApplication(info);
|
||||||
} else {
|
Configuration config = new Configuration();
|
||||||
return newString;
|
config.setLocale(LocaleManager.locale);
|
||||||
|
res.updateConfiguration(config, res.getDisplayMetrics());
|
||||||
|
return res.getString(info.labelRes);
|
||||||
}
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return info.loadLabel(pm).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setupUpdateCheck() {
|
public static String getLegalFilename(CharSequence filename) {
|
||||||
MagiskManager mm = Data.MM();
|
return filename.toString().replace(" ", "_").replace("'", "").replace("\"", "")
|
||||||
JobScheduler scheduler = (JobScheduler) mm.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
.replace("$", "").replace("`", "").replace("*", "").replace("/", "_")
|
||||||
|
.replace("#", "").replace("@", "").replace("\\", "_");
|
||||||
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);
|
|
||||||
}
|
|
||||||
} 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 {
|
|
||||||
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 void loadModules() {
|
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() {
|
public static boolean showSuperUser() {
|
||||||
if (Data.multiuserState < 0)
|
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);
|
Const.Value.MULTIUSER_MODE_OWNER_ONLY);
|
||||||
return Shell.rootAccess() && (Const.USER_ID == 0 ||
|
return Shell.rootAccess() && (Const.USER_ID == 0 ||
|
||||||
Data.multiuserState != Const.Value.MULTIUSER_MODE_OWNER_MANAGED);
|
Data.multiuserState != Const.Value.MULTIUSER_MODE_OWNER_MANAGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String dlString(String url) {
|
public static Context getDEContext() {
|
||||||
String s = Networking.get(url).execForString().getResult();
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ?
|
||||||
return s == null ? "" : s;
|
App.self.createDeviceProtectedStorageContext() : App.self;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
package com.topjohnwu.core.utils;
|
||||||
|
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
import com.topjohnwu.superuser.io.SuFile;
|
import com.topjohnwu.superuser.io.SuFile;
|
@ -63,9 +63,9 @@ restore_imgs() {
|
|||||||
post_ota() {
|
post_ota() {
|
||||||
cd $1
|
cd $1
|
||||||
chmod 755 bootctl
|
chmod 755 bootctl
|
||||||
./bootctl hal-info || return
|
../../../../../app/src/full/res/raw/bootctl hal-info || return
|
||||||
[ `./bootctl get-current-slot` -eq 0 ] && SLOT_NUM=1 || SLOT_NUM=0
|
[ `../../../../../app/src/full/res/raw/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 set-active-boot-slot $SLOT_NUM
|
||||||
echo '${0%/*}/../bootctl mark-boot-successful;rm -f ${0%/*}/../bootctl $0' > post-fs-data.d/post_ota.sh
|
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
|
chmod 755 post-fs-data.d/post_ota.sh
|
||||||
cd /
|
cd /
|
@ -1 +1 @@
|
|||||||
include ':app', ':native', ':utils', ':snet', ':net'
|
include ':app', ':native', ':utils', ':snet', ':net', ':core'
|
||||||
|
Loading…
Reference in New Issue
Block a user