mirror of
https://github.com/topjohnwu/Magisk
synced 2025-11-13 07:07:34 +01:00
Compare commits
113 Commits
manager-v5
...
manager-v5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13bf1b27b4 | ||
|
|
f742bb1c47 | ||
|
|
aa0b9e2db2 | ||
|
|
c10076f7ed | ||
|
|
bcd92499f2 | ||
|
|
b2bb0d4f72 | ||
|
|
e140481f14 | ||
|
|
186bd11463 | ||
|
|
a0490d6687 | ||
|
|
beef740ade | ||
|
|
2ac7786a90 | ||
|
|
a3fb5e910f | ||
|
|
319afe86b5 | ||
|
|
762ab66b86 | ||
|
|
0c239a42de | ||
|
|
e9322fba26 | ||
|
|
39b6df27b3 | ||
|
|
b1ee284e7f | ||
|
|
e986332bf2 | ||
|
|
48f9b27381 | ||
|
|
42a6e0dd10 | ||
|
|
d4798b02ac | ||
|
|
963edfe8ab | ||
|
|
53237f3ae0 | ||
|
|
64da9281a4 | ||
|
|
ab7fd9799d | ||
|
|
f6bcc84251 | ||
|
|
35dc3d9df9 | ||
|
|
566714a75d | ||
|
|
c92f30b122 | ||
|
|
294ad094c4 | ||
|
|
c1a0f520f9 | ||
|
|
773c24b7fc | ||
|
|
8f926c7ca9 | ||
|
|
c562cbc2bb | ||
|
|
3fbbb0865a | ||
|
|
7d5f612a48 | ||
|
|
4a5a36440b | ||
|
|
43dd5cfea1 | ||
|
|
7b5fec1842 | ||
|
|
5762ded601 | ||
|
|
a3abb86daa | ||
|
|
4f5c656b05 | ||
|
|
a31cddbe7b | ||
|
|
b4ecd93f1c | ||
|
|
0acc23e058 | ||
|
|
cdd5f9b628 | ||
|
|
4c9f5f4655 | ||
|
|
b80ba13cb4 | ||
|
|
8260bdc09c | ||
|
|
24f856e02b | ||
|
|
3aa619b928 | ||
|
|
4cb5e98d94 | ||
|
|
272910575e | ||
|
|
a15a62f4bc | ||
|
|
53cf11db8c | ||
|
|
01052fbe47 | ||
|
|
a5e1e075c7 | ||
|
|
6be32ac688 | ||
|
|
b362c0ef38 | ||
|
|
bba9969e31 | ||
|
|
007ba24809 | ||
|
|
df21539311 | ||
|
|
2592cb6019 | ||
|
|
f7df17a7ed | ||
|
|
62f42b72f8 | ||
|
|
a1ba4fda6f | ||
|
|
1c06b04c45 | ||
|
|
2ee22fd374 | ||
|
|
4c230d9e61 | ||
|
|
727294fbbe | ||
|
|
478c43969b | ||
|
|
79b5303350 | ||
|
|
ce4b742b25 | ||
|
|
a9dc15bda5 | ||
|
|
ba6387ff5c | ||
|
|
8fa98508b7 | ||
|
|
decdbaecf9 | ||
|
|
6d87cf9be0 | ||
|
|
94f434c4a6 | ||
|
|
7ba867c30b | ||
|
|
3424395e10 | ||
|
|
926c7359a2 | ||
|
|
ec0af99a2e | ||
|
|
b4d948886c | ||
|
|
4d8d79372a | ||
|
|
04a589722c | ||
|
|
d4a10e2873 | ||
|
|
4998ad6c7e | ||
|
|
a07ca5ff50 | ||
|
|
f07e7571ab | ||
|
|
834c16485c | ||
|
|
04a4265ef3 | ||
|
|
0ec473195d | ||
|
|
0bf09256b0 | ||
|
|
db8fd2c913 | ||
|
|
dbe6e5b3d7 | ||
|
|
cc81cd446b | ||
|
|
439c7118f1 | ||
|
|
d8154a5815 | ||
|
|
4e3787bc0d | ||
|
|
02e0955924 | ||
|
|
a78950e822 | ||
|
|
1ce1a94a35 | ||
|
|
977b6d9f67 | ||
|
|
b5e6dbd797 | ||
|
|
833e6688f1 | ||
|
|
bc22c9f84f | ||
|
|
2149a7d116 | ||
|
|
29175d2c17 | ||
|
|
803454d5c8 | ||
|
|
36cf32dc42 | ||
|
|
657f4ab303 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@ app/.externalNativeBuild/
|
||||
*.sh
|
||||
public.certificate.x509.pem
|
||||
private.key.pk8
|
||||
*.apk
|
||||
|
||||
@@ -2,14 +2,14 @@ apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion "26.0.1"
|
||||
buildToolsVersion "26.0.2"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.topjohnwu.magisk"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 26
|
||||
versionCode 52
|
||||
versionName "5.2.0"
|
||||
versionCode 57
|
||||
versionName "5.4.0"
|
||||
ndk {
|
||||
moduleName 'zipadjust'
|
||||
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
||||
@@ -53,14 +53,14 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.android.support:recyclerview-v7:26.0.0'
|
||||
implementation 'com.android.support:cardview-v7:26.0.0'
|
||||
implementation 'com.android.support:design:26.0.0'
|
||||
implementation 'com.android.support:support-v4:26.0.0'
|
||||
implementation project(':common')
|
||||
implementation project(':jarsigner')
|
||||
implementation 'com.android.support:recyclerview-v7:26.1.0'
|
||||
implementation 'com.android.support:cardview-v7:26.1.0'
|
||||
implementation 'com.android.support:design:26.1.0'
|
||||
implementation 'com.android.support:support-v4:26.1.0'
|
||||
implementation 'com.jakewharton:butterknife:8.8.1'
|
||||
implementation 'com.atlassian.commonmark:commonmark:0.9.0'
|
||||
implementation 'org.bouncycastle:bcprov-jdk15on:1.57'
|
||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.57'
|
||||
implementation 'com.google.android.gms:play-services-safetynet:9.0.1'
|
||||
implementation 'com.atlassian.commonmark:commonmark:0.10.0'
|
||||
implementation 'org.kamranzafar:jtar:2.3'
|
||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
|
||||
}
|
||||
|
||||
9
app/proguard-rules.pro
vendored
9
app/proguard-rules.pro
vendored
@@ -16,10 +16,9 @@
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Keep all names, we are open source anyway :)
|
||||
-keepnames class ** { *; }
|
||||
|
||||
# BouncyCastle
|
||||
-keep class org.bouncycastle.** { *; }
|
||||
-keep class org.bouncycastle.jcajce.provider.** { *; }
|
||||
-dontwarn javax.naming.**
|
||||
|
||||
-dontwarn android.content.**
|
||||
-dontwarn android.animation.**
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
|
||||
android:directBootAware="true"
|
||||
tools:ignore="UnusedAttribute">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
@@ -89,9 +90,10 @@
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<!-- Hardcode GMS version -->
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
android:value="11400000" />
|
||||
|
||||
</application>
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
@@ -42,7 +43,7 @@ public class AboutActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getApplicationContext().isDarkTheme) {
|
||||
if (getMagiskManager().isDarkTheme) {
|
||||
setTheme(R.style.AppTheme_Transparent_Dark);
|
||||
}
|
||||
setContentView(R.layout.activity_about);
|
||||
@@ -57,7 +58,7 @@ public class AboutActivity extends Activity {
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
appVersionInfo.setSummary(BuildConfig.VERSION_NAME);
|
||||
appVersionInfo.setSummary(String.format(Locale.US, "%s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
|
||||
|
||||
String changes = null;
|
||||
try (InputStream is = getAssets().open("changelog.html")) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
@@ -8,25 +9,37 @@ import android.support.v7.widget.Toolbar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.FlashZip;
|
||||
import com.topjohnwu.magisk.asyncs.InstallMagisk;
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.utils.AdaptiveList;
|
||||
import com.topjohnwu.magisk.container.AdaptiveList;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
||||
public class FlashActivity extends Activity {
|
||||
|
||||
public static final String SET_ACTION = "action";
|
||||
public static final String SET_BOOT = "boot";
|
||||
public static final String SET_ENC = "enc";
|
||||
public static final String SET_VERITY = "verity";
|
||||
|
||||
public static final String FLASH_ZIP = "flash";
|
||||
public static final String PATCH_BOOT = "patch";
|
||||
public static final String FLASH_MAGISK = "magisk";
|
||||
|
||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||
@BindView(R.id.flash_logs) RecyclerView flashLogs;
|
||||
@BindView(R.id.button_panel) LinearLayout buttonPanel;
|
||||
|
||||
private AdaptiveList<String> rootShellOutput;
|
||||
@BindView(R.id.reboot) Button reboot;
|
||||
|
||||
@OnClick(R.id.no_thanks)
|
||||
public void dismiss() {
|
||||
@@ -35,7 +48,7 @@ public class FlashActivity extends Activity {
|
||||
|
||||
@OnClick(R.id.reboot)
|
||||
public void reboot() {
|
||||
Shell.getShell(this).su_raw("reboot");
|
||||
getShell().su_raw("reboot");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -43,22 +56,57 @@ public class FlashActivity extends Activity {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_flash);
|
||||
ButterKnife.bind(this);
|
||||
rootShellOutput = new AdaptiveList<>(flashLogs);
|
||||
AdaptiveList<String> rootShellOutput = new AdaptiveList<>(flashLogs);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setTitle(R.string.flashing);
|
||||
}
|
||||
setFloating();
|
||||
setFinishOnTouchOutside(false);
|
||||
if (!Shell.rootAccess())
|
||||
reboot.setVisibility(View.GONE);
|
||||
|
||||
flashLogs.setAdapter(new FlashLogAdapter());
|
||||
flashLogs.setAdapter(new FlashLogAdapter(rootShellOutput));
|
||||
|
||||
// We must receive a Uri of the target zip
|
||||
Uri uri = getIntent().getData();
|
||||
Intent intent = getIntent();
|
||||
Uri uri = intent.getData();
|
||||
|
||||
new FlashZip(this, uri, rootShellOutput)
|
||||
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
|
||||
.exec();
|
||||
boolean keepEnc = intent.getBooleanExtra(SET_ENC, false);
|
||||
boolean keepVerity = intent.getBooleanExtra(SET_VERITY, false);
|
||||
|
||||
switch (getIntent().getStringExtra(SET_ACTION)) {
|
||||
case FLASH_ZIP:
|
||||
new FlashZip(this, uri, rootShellOutput)
|
||||
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
|
||||
.exec();
|
||||
break;
|
||||
case PATCH_BOOT:
|
||||
new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, (Uri) intent.getParcelableExtra(SET_BOOT))
|
||||
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
|
||||
.exec();
|
||||
break;
|
||||
case FLASH_MAGISK:
|
||||
String boot = intent.getStringExtra(SET_BOOT);
|
||||
if (getMagiskManager().remoteMagiskVersionCode < 1370) {
|
||||
// Use legacy installation method
|
||||
getShell().su_raw(
|
||||
"echo \"BOOTIMAGE=" + boot + "\" > /dev/.magisk",
|
||||
"echo \"KEEPFORCEENCRYPT=" + keepEnc + "\" >> /dev/.magisk",
|
||||
"echo \"KEEPVERITY=" + keepVerity + "\" >> /dev/.magisk"
|
||||
);
|
||||
new FlashZip(this, uri, rootShellOutput)
|
||||
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
|
||||
.exec();
|
||||
} else {
|
||||
// Use new installation method
|
||||
new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, boot)
|
||||
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
|
||||
.exec();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,7 +114,13 @@ public class FlashActivity extends Activity {
|
||||
// Prevent user accidentally press back button
|
||||
}
|
||||
|
||||
private class FlashLogAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
private static class FlashLogAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
|
||||
private List<String> mList;
|
||||
|
||||
FlashLogAdapter(List<String> list) {
|
||||
mList = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
@@ -77,16 +131,16 @@ public class FlashActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
holder.text.setText(rootShellOutput.get(position));
|
||||
holder.text.setText(mList.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return rootShellOutput.size();
|
||||
return mList.size();
|
||||
}
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@BindView(R.id.textView) TextView text;
|
||||
|
||||
@@ -95,4 +149,5 @@ public class FlashActivity extends Activity {
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -84,7 +84,7 @@ public class MagiskHideFragment extends Fragment implements Topic.Subscriber {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTopicPublished(Topic topic) {
|
||||
public void onTopicPublished(Topic topic, Object result) {
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
appAdapter.filter(lastFilter);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.text.TextUtils;
|
||||
@@ -25,6 +23,7 @@ import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
@@ -40,25 +39,18 @@ public class MagiskLogFragment extends Fragment {
|
||||
private static final String MAGISK_LOG = "/cache/magisk.log";
|
||||
|
||||
private Unbinder unbinder;
|
||||
|
||||
@BindView(R.id.txtLog) TextView txtLog;
|
||||
@BindView(R.id.svLog) ScrollView svLog;
|
||||
@BindView(R.id.hsvLog) HorizontalScrollView hsvLog;
|
||||
|
||||
@BindView(R.id.progressBar) ProgressBar progressBar;
|
||||
|
||||
private MenuItem mClickedMenuItem;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_magisk_log, container, false);
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
txtLog.setTextIsSelectable(true);
|
||||
|
||||
@@ -92,13 +84,14 @@ public class MagiskLogFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
mClickedMenuItem = item;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_refresh:
|
||||
new LogManager().read();
|
||||
return true;
|
||||
case R.id.menu_save:
|
||||
new LogManager().save();
|
||||
Utils.runWithPermission(getActivity(),
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
() -> new LogManager().save());
|
||||
return true;
|
||||
case R.id.menu_clear:
|
||||
new LogManager().clear();
|
||||
@@ -108,38 +101,27 @@ public class MagiskLogFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == 0) {
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
if (mClickedMenuItem != null) {
|
||||
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
||||
}
|
||||
} else {
|
||||
SnackbarMaker.make(txtLog, R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class LogManager extends ParallelTask<Object, Void, Object> {
|
||||
|
||||
private int mode;
|
||||
private File targetFile;
|
||||
|
||||
LogManager() {
|
||||
super(MagiskLogFragment.this.getActivity());
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
@Override
|
||||
protected Object doInBackground(Object... params) {
|
||||
MagiskManager magiskManager = MagiskLogFragment.this.getApplication();
|
||||
mode = (int) params[0];
|
||||
switch (mode) {
|
||||
case 0:
|
||||
StringBuildingList logList = new StringBuildingList();
|
||||
Shell.getShell(magiskManager).su(logList, "cat " + MAGISK_LOG);
|
||||
getShell().su(logList, "cat " + MAGISK_LOG);
|
||||
return logList.toString();
|
||||
|
||||
case 1:
|
||||
Shell.getShell(magiskManager).su_raw("echo > " + MAGISK_LOG);
|
||||
getShell().su_raw("echo -n > " + MAGISK_LOG);
|
||||
SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
||||
return "";
|
||||
|
||||
@@ -151,7 +133,7 @@ public class MagiskLogFragment extends Fragment {
|
||||
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
||||
|
||||
targetFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/MagiskManager/" + filename);
|
||||
targetFile = new File(Environment.getExternalStorageDirectory() + "/MagiskManager/" + filename);
|
||||
|
||||
if ((!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs())
|
||||
|| (targetFile.exists() && !targetFile.delete())) {
|
||||
@@ -160,7 +142,7 @@ public class MagiskLogFragment extends Fragment {
|
||||
|
||||
try (FileWriter out = new FileWriter(targetFile)) {
|
||||
FileWritingList fileWritingList = new FileWritingList(out);
|
||||
Shell.getShell(magiskManager).su(fileWritingList, "cat " + MAGISK_LOG);
|
||||
getShell().su(fileWritingList, "cat " + MAGISK_LOG);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
@@ -188,9 +170,9 @@ public class MagiskLogFragment extends Fragment {
|
||||
case 2:
|
||||
boolean bool = (boolean) o;
|
||||
if (bool) {
|
||||
MagiskLogFragment.this.getApplication().toast(targetFile.toString(), Toast.LENGTH_LONG);
|
||||
getMagiskManager().toast(targetFile.toString(), Toast.LENGTH_LONG);
|
||||
} else {
|
||||
MagiskLogFragment.this.getApplication().toast(R.string.logs_save_failed, Toast.LENGTH_LONG);
|
||||
getMagiskManager().toast(R.string.logs_save_failed, Toast.LENGTH_LONG);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,11 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
@@ -42,24 +38,20 @@ public class MainActivity extends Activity
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
getMagiskManager().startup();
|
||||
|
||||
prefs = getApplicationContext().prefs;
|
||||
prefs = getMagiskManager().prefs;
|
||||
|
||||
if (getApplicationContext().isDarkTheme) {
|
||||
if (getMagiskManager().isDarkTheme) {
|
||||
setTheme(R.style.AppTheme_Dark);
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
ButterKnife.bind(this);
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
|
||||
}
|
||||
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
|
||||
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.magisk, R.string.magisk) {
|
||||
@Override
|
||||
public void onDrawerOpened(View drawerView) {
|
||||
super.onDrawerOpened(drawerView);
|
||||
@@ -110,27 +102,27 @@ public class MainActivity extends Activity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTopicPublished(Topic topic) {
|
||||
public void onTopicPublished(Topic topic, Object result) {
|
||||
recreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Topic[] getSubscription() {
|
||||
return new Topic[] { getApplicationContext().reloadActivity };
|
||||
return new Topic[] { getMagiskManager().reloadActivity };
|
||||
}
|
||||
|
||||
public void checkHideSection() {
|
||||
Menu menu = navigationView.getMenu();
|
||||
menu.findItem(R.id.magiskhide).setVisible(
|
||||
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 1300
|
||||
Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 1300
|
||||
&& prefs.getBoolean("magiskhide", false));
|
||||
menu.findItem(R.id.modules).setVisible(
|
||||
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 0);
|
||||
Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 0);
|
||||
menu.findItem(R.id.downloads).setVisible(Utils.checkNetworkStatus(this) &&
|
||||
Shell.rootAccess() && getApplicationContext().magiskVersionCode >= 0);
|
||||
Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 0);
|
||||
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
|
||||
menu.findItem(R.id.superuser).setVisible(
|
||||
Shell.rootAccess() && getApplicationContext().isSuClient);
|
||||
Shell.rootAccess() && getMagiskManager().isSuClient);
|
||||
}
|
||||
|
||||
public void navigate(String item) {
|
||||
@@ -140,9 +132,6 @@ public class MainActivity extends Activity
|
||||
case "magisk":
|
||||
itemId = R.id.magisk;
|
||||
break;
|
||||
case "install":
|
||||
itemId = -1;
|
||||
break;
|
||||
case "superuser":
|
||||
itemId = R.id.superuser;
|
||||
break;
|
||||
@@ -174,13 +163,6 @@ public class MainActivity extends Activity
|
||||
mDrawerItem = itemId;
|
||||
navigationView.setCheckedItem(itemId);
|
||||
switch (itemId) {
|
||||
case -1:
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean(MagiskFragment.SHOW_DIALOG, true);
|
||||
Fragment frag = new MagiskFragment();
|
||||
frag.setArguments(args);
|
||||
displayFragment(frag, "magisk", true);
|
||||
break;
|
||||
case R.id.magisk:
|
||||
displayFragment(new MagiskFragment(), "magisk", true);
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
@@ -14,9 +15,9 @@ import android.widget.TextView;
|
||||
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.container.Module;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -36,9 +37,11 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
||||
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||
@OnClick(R.id.fab)
|
||||
public void selectFile() {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("application/zip");
|
||||
startActivityForResult(intent, FETCH_ZIP_CODE);
|
||||
Utils.runWithPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE, () -> {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("application/zip");
|
||||
startActivityForResult(intent, FETCH_ZIP_CODE);
|
||||
});
|
||||
}
|
||||
|
||||
private List<Module> listModules = new ArrayList<>();
|
||||
@@ -72,8 +75,7 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTopicPublished(Topic topic) {
|
||||
Logger.dev("ModulesFragment: UI refresh triggered");
|
||||
public void onTopicPublished(Topic topic, Object result) {
|
||||
updateUI();
|
||||
}
|
||||
|
||||
@@ -87,7 +89,7 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
||||
if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||
// Get the URI of the selected file
|
||||
Intent intent = new Intent(getActivity(), FlashActivity.class);
|
||||
intent.setData(data.getData()).putExtra("ACTION", "flash");
|
||||
intent.setData(data.getData()).putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_ZIP);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import android.widget.TextView;
|
||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
|
||||
import butterknife.BindView;
|
||||
@@ -29,7 +28,7 @@ public class ReposFragment extends Fragment implements Topic.Subscriber {
|
||||
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||
|
||||
private ReposAdapter adapter;
|
||||
public static ReposAdapter adapter;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
@@ -43,14 +42,12 @@ public class ReposFragment extends Fragment implements Topic.Subscriber {
|
||||
View view = inflater.inflate(R.layout.fragment_repos, container, false);
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
adapter = new ReposAdapter(getApplication().repoDB, getApplication().moduleMap);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
mSwipeRefreshLayout.setRefreshing(true);
|
||||
|
||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
new UpdateRepos(getActivity()).exec();
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
emptyRv.setVisibility(View.GONE);
|
||||
new UpdateRepos(getActivity(), true).exec();
|
||||
});
|
||||
|
||||
getActivity().setTitle(R.string.downloads);
|
||||
@@ -59,10 +56,21 @@ public class ReposFragment extends Fragment implements Topic.Subscriber {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTopicPublished(Topic topic) {
|
||||
Logger.dev("ReposFragment: UI refresh triggered");
|
||||
public void onResume() {
|
||||
adapter = new ReposAdapter(getApplication().repoDB, getApplication().moduleMap);
|
||||
recyclerView.setAdapter(adapter);
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
adapter = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTopicPublished(Topic topic, Object result) {
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
adapter.notifyDBChanged();
|
||||
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
|
||||
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,54 +1,17 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.services.UpdateCheckService;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
public class SplashActivity extends Activity{
|
||||
|
||||
private static final int UPDATE_SERVICE_ID = 1;
|
||||
public class SplashActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
MagiskManager magiskManager = getApplicationContext();
|
||||
|
||||
// Init the info and configs and root sh
|
||||
magiskManager.init();
|
||||
|
||||
// Get possible additional info from intent
|
||||
magiskManager.remoteMagiskVersionString = getIntent().getStringExtra(MagiskManager.INTENT_VERSION);
|
||||
magiskManager.magiskLink = getIntent().getStringExtra(MagiskManager.INTENT_LINK);
|
||||
|
||||
LoadModules loadModuleTask = new LoadModules(this);
|
||||
|
||||
if (Utils.checkNetworkStatus(this)) {
|
||||
// Initialize the update check service, notify every 8 hours
|
||||
if (!TextUtils.equals("install", getIntent().getStringExtra(MagiskManager.INTENT_SECTION))) {
|
||||
ComponentName service = new ComponentName(this, UpdateCheckService.class);
|
||||
JobInfo jobInfo = new JobInfo.Builder(UPDATE_SERVICE_ID, service)
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
|
||||
.setPersisted(true)
|
||||
.setPeriodic(8 * 60 * 60 * 1000)
|
||||
.build();
|
||||
((JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(jobInfo);
|
||||
}
|
||||
loadModuleTask.setCallBack(() -> new UpdateRepos(getApplication()).exec());
|
||||
}
|
||||
|
||||
loadModuleTask.exec();
|
||||
getMagiskManager().startup();
|
||||
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION);
|
||||
|
||||
@@ -24,7 +24,7 @@ public class SuLogFragment extends Fragment {
|
||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||
|
||||
private Unbinder unbinder;
|
||||
private MagiskManager magiskManager;
|
||||
private MagiskManager mm;
|
||||
private SuLogAdapter adapter;
|
||||
|
||||
@Override
|
||||
@@ -45,8 +45,8 @@ public class SuLogFragment extends Fragment {
|
||||
// Inflate the layout for this fragment
|
||||
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
|
||||
unbinder = ButterKnife.bind(this, v);
|
||||
magiskManager = getApplication();
|
||||
adapter = new SuLogAdapter(magiskManager.suDB);
|
||||
mm = getApplication();
|
||||
adapter = new SuLogAdapter(mm.suDB);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
updateList();
|
||||
@@ -73,7 +73,7 @@ public class SuLogFragment extends Fragment {
|
||||
updateList();
|
||||
return true;
|
||||
case R.id.menu_clear:
|
||||
magiskManager.suDB.clearLogs();
|
||||
mm.suDB.clearLogs();
|
||||
updateList();
|
||||
return true;
|
||||
default:
|
||||
|
||||
@@ -11,7 +11,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.superuser.Policy;
|
||||
import com.topjohnwu.magisk.container.Policy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -32,15 +32,15 @@ public class SuperuserFragment extends Fragment {
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
PackageManager pm = getActivity().getPackageManager();
|
||||
MagiskManager magiskManager = getApplication();
|
||||
MagiskManager mm = getApplication();
|
||||
|
||||
List<Policy> policyList = magiskManager.suDB.getPolicyList(pm);
|
||||
List<Policy> policyList = mm.suDB.getPolicyList(pm);
|
||||
|
||||
if (policyList.size() == 0) {
|
||||
emptyRv.setVisibility(View.VISIBLE);
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
} else {
|
||||
recyclerView.setAdapter(new PolicyAdapter(policyList, magiskManager.suDB, pm));
|
||||
recyclerView.setAdapter(new PolicyAdapter(policyList, mm.suDB, pm));
|
||||
emptyRv.setVisibility(View.GONE);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.container.Module;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.topjohnwu.magisk.adapters;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
@@ -12,10 +13,10 @@ import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||
import com.topjohnwu.magisk.components.ExpandableViewHolder;
|
||||
import com.topjohnwu.magisk.components.ExpandableView;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.container.Policy;
|
||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||
import com.topjohnwu.magisk.superuser.Policy;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -50,7 +51,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
||||
holder.setExpanded(expandList.contains(policy));
|
||||
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
if (holder.mExpanded) {
|
||||
if (holder.isExpanded()) {
|
||||
holder.collapse();
|
||||
expandList.remove(policy);
|
||||
} else {
|
||||
@@ -92,7 +93,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
||||
dbHelper.updatePolicy(policy);
|
||||
}
|
||||
});
|
||||
holder.delete.setOnClickListener(v -> new AlertDialogBuilder(v.getContext())
|
||||
holder.delete.setOnClickListener(v -> new AlertDialogBuilder((Activity) v.getContext())
|
||||
.setTitle(R.string.su_revoke_title)
|
||||
.setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName))
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||
@@ -119,7 +120,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
||||
return policyList.size();
|
||||
}
|
||||
|
||||
static class ViewHolder extends ExpandableViewHolder {
|
||||
static class ViewHolder extends RecyclerView.ViewHolder implements ExpandableView {
|
||||
|
||||
@BindView(R.id.app_name) TextView appName;
|
||||
@BindView(R.id.package_name) TextView packageName;
|
||||
@@ -127,18 +128,23 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
||||
@BindView(R.id.master_switch) Switch masterSwitch;
|
||||
@BindView(R.id.notification_switch) Switch notificationSwitch;
|
||||
@BindView(R.id.logging_switch) Switch loggingSwitch;
|
||||
@BindView(R.id.expand_layout) ViewGroup expandLayout;
|
||||
|
||||
@BindView(R.id.delete) ImageView delete;
|
||||
@BindView(R.id.more_info) ImageView moreInfo;
|
||||
|
||||
private Container container = new Container();
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
container.expandLayout = expandLayout;
|
||||
setupExpandable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpandLayout(View itemView) {
|
||||
expandLayout = itemView.findViewById(R.id.expand_layout);
|
||||
public Container getContainer() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.topjohnwu.magisk.adapters;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
@@ -18,10 +17,9 @@ import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
||||
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||
import com.topjohnwu.magisk.container.Module;
|
||||
import com.topjohnwu.magisk.container.Repo;
|
||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.module.Repo;
|
||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -46,6 +44,7 @@ public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, R
|
||||
repoDB = db;
|
||||
moduleMap = map;
|
||||
repoPairs = new ArrayList<>();
|
||||
notifyDBChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -102,30 +101,17 @@ public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, R
|
||||
|
||||
holder.downloadImage.setOnClickListener(v -> {
|
||||
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
|
||||
new AlertDialogBuilder(context)
|
||||
new AlertDialogBuilder((Activity) context)
|
||||
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
|
||||
.setMessage(context.getString(R.string.repo_install_msg, filename))
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.install, (d, i) -> Utils.dlAndReceive(
|
||||
context,
|
||||
new DownloadReceiver() {
|
||||
@Override
|
||||
public void onDownloadDone(Uri uri) {
|
||||
new ProcessRepoZip((Activity) context, uri, true).exec();
|
||||
}
|
||||
},
|
||||
repo.getZipUrl(),
|
||||
Utils.getLegalFilename(filename)))
|
||||
.setNeutralButton(R.string.download, (d, i) -> Utils.dlAndReceive(
|
||||
context,
|
||||
new DownloadReceiver() {
|
||||
@Override
|
||||
public void onDownloadDone(Uri uri) {
|
||||
new ProcessRepoZip((Activity) context, uri, false).exec();
|
||||
}
|
||||
},
|
||||
repo.getZipUrl(),
|
||||
Utils.getLegalFilename(filename)))
|
||||
.setPositiveButton(R.string.install, (d, i) ->
|
||||
new ProcessRepoZip((Activity) context, repo.getZipUrl(),
|
||||
Utils.getLegalFilename(filename), true).exec()
|
||||
)
|
||||
.setNeutralButton(R.string.download, (d, i) ->
|
||||
new ProcessRepoZip((Activity) context, repo.getZipUrl(),
|
||||
Utils.getLegalFilename(filename), false).exec())
|
||||
.setNegativeButton(R.string.no_thanks, null)
|
||||
.show();
|
||||
});
|
||||
|
||||
@@ -11,9 +11,9 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.components.ExpandableViewHolder;
|
||||
import com.topjohnwu.magisk.components.ExpandableView;
|
||||
import com.topjohnwu.magisk.container.SuLogEntry;
|
||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -90,7 +90,7 @@ public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, S
|
||||
SuLogEntry entry = new SuLogEntry(suLogCursor);
|
||||
holder.setExpanded(itemExpanded.contains(sqlPosition));
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
if (holder.mExpanded) {
|
||||
if (holder.isExpanded()) {
|
||||
holder.collapse();
|
||||
itemExpanded.remove(sqlPosition);
|
||||
} else {
|
||||
@@ -128,7 +128,7 @@ public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, S
|
||||
}
|
||||
}
|
||||
|
||||
static class LogViewHolder extends ExpandableViewHolder {
|
||||
static class LogViewHolder extends RecyclerView.ViewHolder implements ExpandableView {
|
||||
|
||||
@BindView(R.id.app_name) TextView appName;
|
||||
@BindView(R.id.action) TextView action;
|
||||
@@ -136,15 +136,20 @@ public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, S
|
||||
@BindView(R.id.fromPid) TextView fromPid;
|
||||
@BindView(R.id.toUid) TextView toUid;
|
||||
@BindView(R.id.command) TextView command;
|
||||
@BindView(R.id.expand_layout) ViewGroup expandLayout;
|
||||
|
||||
private Container container = new Container();
|
||||
|
||||
LogViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
container.expandLayout = expandLayout;
|
||||
setupExpandable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpandLayout(View itemView) {
|
||||
expandLayout = itemView.findViewById(R.id.expand_layout);
|
||||
public Container getContainer() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
|
||||
import com.topjohnwu.jarsigner.ByteArrayStream;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
import dalvik.system.DexClassLoader;
|
||||
|
||||
public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
|
||||
|
||||
public static final int SNET_VER = 2;
|
||||
|
||||
private static final String SNET_URL = "https://github.com/topjohnwu/MagiskManager/releases/download/v5.4.0/snet.apk";
|
||||
private static final String PKG = "com.topjohnwu.snet";
|
||||
|
||||
private File dexPath;
|
||||
private DexClassLoader loader;
|
||||
|
||||
public CheckSafetyNet(FragmentActivity activity) {
|
||||
super(activity);
|
||||
dexPath = new File(activity.getCacheDir().getParent() + "/snet", "snet.apk");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
MagiskManager mm = getMagiskManager();
|
||||
if (mm.snet_version != CheckSafetyNet.SNET_VER) {
|
||||
getShell().sh("rm -rf " + dexPath.getParent());
|
||||
}
|
||||
mm.snet_version = CheckSafetyNet.SNET_VER;
|
||||
mm.prefs.edit().putInt("snet_version", CheckSafetyNet.SNET_VER).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Exception doInBackground(Void... voids) {
|
||||
try {
|
||||
if (!dexPath.exists()) {
|
||||
HttpURLConnection conn = WebService.request(SNET_URL, null);
|
||||
ByteArrayStream bas = new ByteArrayStream();
|
||||
bas.readFrom(conn.getInputStream());
|
||||
conn.disconnect();
|
||||
dexPath.getParentFile().mkdir();
|
||||
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath))) {
|
||||
bas.writeTo(out);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
loader = new DexClassLoader(dexPath.toString(), dexPath.getParent(),
|
||||
null, ClassLoader.getSystemClassLoader());
|
||||
} catch (Exception e) {
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Exception err) {
|
||||
try {
|
||||
if (err != null) throw err;
|
||||
Class<?> helperClazz = loader.loadClass(PKG + ".SafetyNetHelper");
|
||||
Class<?> callbackClazz = loader.loadClass(PKG + ".SafetyNetCallback");
|
||||
Object helper = helperClazz.getConstructors()[0].newInstance(
|
||||
getActivity(), Proxy.newProxyInstance(
|
||||
loader, new Class[] { callbackClazz }, (proxy, method, args) -> {
|
||||
getMagiskManager().safetyNetDone.publish(false, args[0]);
|
||||
return null;
|
||||
}));
|
||||
helperClazz.getMethod("attest").invoke(helper);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
getMagiskManager().safetyNetDone.publish(false, -1);
|
||||
}
|
||||
super.onPostExecute(err);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,11 @@ import org.json.JSONObject;
|
||||
|
||||
public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
private static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/magisk_update.json";
|
||||
public static final int STABLE_CHANNEL = 0;
|
||||
public static final int BETA_CHANNEL = 1;
|
||||
|
||||
private static final String STABLE_URL = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/stable.json";
|
||||
private static final String BETA_URL = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/beta.json";
|
||||
|
||||
private boolean showNotification = false;
|
||||
|
||||
@@ -27,36 +31,46 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return null;
|
||||
String jsonStr = WebService.getString(UPDATE_JSON);
|
||||
MagiskManager mm = getMagiskManager();
|
||||
if (mm == null) return null;
|
||||
String jsonStr;
|
||||
switch (mm.updateChannel) {
|
||||
case STABLE_CHANNEL:
|
||||
jsonStr = WebService.getString(STABLE_URL);
|
||||
break;
|
||||
case BETA_CHANNEL:
|
||||
jsonStr = WebService.getString(BETA_URL);
|
||||
break;
|
||||
default:
|
||||
jsonStr = null;
|
||||
}
|
||||
try {
|
||||
JSONObject json = new JSONObject(jsonStr);
|
||||
JSONObject magisk = json.getJSONObject("magisk");
|
||||
magiskManager.remoteMagiskVersionString = magisk.getString("version");
|
||||
magiskManager.remoteMagiskVersionCode = magisk.getInt("versionCode");
|
||||
magiskManager.magiskLink = magisk.getString("link");
|
||||
magiskManager.releaseNoteLink = magisk.getString("note");
|
||||
mm.remoteMagiskVersionString = magisk.getString("version");
|
||||
mm.remoteMagiskVersionCode = magisk.getInt("versionCode");
|
||||
mm.magiskLink = magisk.getString("link");
|
||||
mm.releaseNoteLink = magisk.getString("note");
|
||||
JSONObject manager = json.getJSONObject("app");
|
||||
magiskManager.remoteManagerVersionString = manager.getString("version");
|
||||
magiskManager.remoteManagerVersionCode = manager.getInt("versionCode");
|
||||
magiskManager.managerLink = manager.getString("link");
|
||||
mm.remoteManagerVersionString = manager.getString("version");
|
||||
mm.remoteManagerVersionCode = manager.getInt("versionCode");
|
||||
mm.managerLink = manager.getString("link");
|
||||
} catch (JSONException ignored) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return;
|
||||
if (showNotification && magiskManager.updateNotification) {
|
||||
if (BuildConfig.VERSION_CODE < magiskManager.remoteManagerVersionCode) {
|
||||
Utils.showManagerUpdate(magiskManager);
|
||||
} else if (magiskManager.magiskVersionCode < magiskManager.remoteMagiskVersionCode) {
|
||||
Utils.showMagiskUpdate(magiskManager);
|
||||
MagiskManager mm = getMagiskManager();
|
||||
if (mm == null) return;
|
||||
if (showNotification && mm.updateNotification) {
|
||||
if (BuildConfig.VERSION_CODE < mm.remoteManagerVersionCode) {
|
||||
Utils.showManagerUpdateNotification(mm);
|
||||
} else if (mm.magiskVersionCode < mm.remoteMagiskVersionCode) {
|
||||
Utils.showMagiskUpdateNotification(mm);
|
||||
}
|
||||
}
|
||||
magiskManager.updateCheckDone.publish();
|
||||
mm.updateCheckDone.publish();
|
||||
super.onPostExecute(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,19 +3,20 @@ package com.topjohnwu.magisk.asyncs;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
public class DownloadBusybox extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
private static final String BUSYBOX_ARM = "https://github.com/topjohnwu/ndk-busybox/releases/download/1.27.1/busybox-arm";
|
||||
private static final String BUSYBOX_X86 = "https://github.com/topjohnwu/ndk-busybox/releases/download/1.27.1/busybox-x86";
|
||||
private static final String BUSYBOXPATH = "/dev/magisk/bin";
|
||||
private static final String BUSYBOX_ARM = "https://github.com/topjohnwu/ndk-busybox/releases/download/1.27.2/busybox-arm";
|
||||
private static final String BUSYBOX_X86 = "https://github.com/topjohnwu/ndk-busybox/releases/download/1.27.2/busybox-x86";
|
||||
|
||||
private File busybox;
|
||||
|
||||
@@ -24,47 +25,39 @@ public class DownloadBusybox extends ParallelTask<Void, Void, Void> {
|
||||
busybox = new File(context.getCacheDir(), "busybox");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
getShell().su_raw("export PATH=" + BUSYBOXPATH + ":$PATH");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
Context context = getMagiskManager();
|
||||
if (!Utils.itemExist(getShell(), BUSYBOXPATH + "/busybox")) {
|
||||
if (!busybox.exists() && Utils.checkNetworkStatus(context)) {
|
||||
Utils.removeItem(getShell(), context.getApplicationInfo().dataDir + "/busybox");
|
||||
try {
|
||||
FileOutputStream out = new FileOutputStream(busybox);
|
||||
InputStream in = WebService.request(WebService.GET,
|
||||
Build.SUPPORTED_32_BIT_ABIS[0].contains("x86") ?
|
||||
BUSYBOX_X86 :
|
||||
BUSYBOX_ARM,
|
||||
null
|
||||
);
|
||||
if (in == null) throw new IOException();
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
out.close();
|
||||
in.close();
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (busybox.exists()) {
|
||||
getShell().su_raw(
|
||||
"rm -rf " + BUSYBOXPATH,
|
||||
"mkdir -p " + BUSYBOXPATH,
|
||||
"cp " + busybox + " " + BUSYBOXPATH,
|
||||
"chmod -R 755 " + BUSYBOXPATH,
|
||||
BUSYBOXPATH + "/busybox --install -s " + BUSYBOXPATH
|
||||
);
|
||||
Utils.removeItem(getShell(), context.getApplicationInfo().dataDir + "/busybox");
|
||||
try {
|
||||
FileOutputStream out = new FileOutputStream(busybox);
|
||||
HttpURLConnection conn = WebService.request(
|
||||
Build.SUPPORTED_32_BIT_ABIS[0].contains("x86") ?
|
||||
BUSYBOX_X86 :
|
||||
BUSYBOX_ARM,
|
||||
null
|
||||
);
|
||||
if (conn == null) throw new IOException();
|
||||
BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
|
||||
byte[] buffer = new byte[4096];
|
||||
int len;
|
||||
while ((len = bis.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
out.close();
|
||||
conn.disconnect();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (busybox.exists()) {
|
||||
getShell().su(
|
||||
"rm -rf " + MagiskManager.BUSYBOXPATH,
|
||||
"mkdir -p " + MagiskManager.BUSYBOXPATH,
|
||||
"cp " + busybox + " " + MagiskManager.BUSYBOXPATH,
|
||||
"chmod -R 755 " + MagiskManager.BUSYBOXPATH,
|
||||
MagiskManager.BUSYBOXPATH + "/busybox --install -s " + MagiskManager.BUSYBOXPATH
|
||||
);
|
||||
busybox.delete();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.AdaptiveList;
|
||||
import com.topjohnwu.magisk.container.AdaptiveList;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -18,30 +20,22 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class FlashZip extends ParallelTask<Void, String, Integer> {
|
||||
public class FlashZip extends ParallelTask<Void, Void, Integer> {
|
||||
|
||||
private Uri mUri;
|
||||
private File mCachedFile, mScriptFile, mCheckFile;
|
||||
|
||||
private String mFilename;
|
||||
private File mCachedFile;
|
||||
private AdaptiveList<String> mList;
|
||||
|
||||
public FlashZip(Activity context, Uri uri, AdaptiveList<String> list) {
|
||||
super(context);
|
||||
mUri = uri;
|
||||
mList = list;
|
||||
|
||||
mCachedFile = new File(context.getCacheDir(), "install.zip");
|
||||
mScriptFile = new File(context.getCacheDir(), "/META-INF/com/google/android/update-binary");
|
||||
mCheckFile = new File(mScriptFile.getParent(), "updater-script");
|
||||
|
||||
// Try to get the filename ourselves
|
||||
mFilename = Utils.getNameFromUri(context, mUri);
|
||||
}
|
||||
|
||||
private boolean unzipAndCheck() throws Exception {
|
||||
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android");
|
||||
List<String> ret = Utils.readFile(getShell(), mCheckFile.getPath());
|
||||
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", true);
|
||||
List<String> ret = Utils.readFile(getShell(), new File(mCachedFile.getParentFile(), "updater-script").getPath());
|
||||
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
|
||||
}
|
||||
|
||||
@@ -52,27 +46,28 @@ public class FlashZip extends ParallelTask<Void, String, Integer> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(String... values) {
|
||||
protected void onProgressUpdate(Void... values) {
|
||||
mList.updateView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... voids) {
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return -1;
|
||||
MagiskManager mm = getMagiskManager();
|
||||
if (mm == null) return -1;
|
||||
try {
|
||||
mList.add(magiskManager.getString(R.string.copying_msg));
|
||||
mList.add("- Copying zip to temp directory");
|
||||
|
||||
mCachedFile.delete();
|
||||
try (
|
||||
InputStream in = magiskManager.getContentResolver().openInputStream(mUri);
|
||||
OutputStream outputStream = new FileOutputStream(mCachedFile)
|
||||
InputStream in = mm.getContentResolver().openInputStream(mUri);
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(mCachedFile))
|
||||
) {
|
||||
if (in == null) throw new FileNotFoundException();
|
||||
byte buffer[] = new byte[1024];
|
||||
InputStream buf= new BufferedInputStream(in);
|
||||
byte buffer[] = new byte[4096];
|
||||
int length;
|
||||
while ((length = in.read(buffer)) > 0)
|
||||
outputStream.write(buffer, 0, length);
|
||||
while ((length = buf.read(buffer)) > 0)
|
||||
out.write(buffer, 0, length);
|
||||
} catch (FileNotFoundException e) {
|
||||
mList.add("! Invalid Uri");
|
||||
throw e;
|
||||
@@ -81,9 +76,10 @@ public class FlashZip extends ParallelTask<Void, String, Integer> {
|
||||
throw e;
|
||||
}
|
||||
if (!unzipAndCheck()) return 0;
|
||||
mList.add(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
|
||||
mList.add("- Installing " + Utils.getNameFromUri(mm, mUri));
|
||||
getShell().su(mList,
|
||||
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile +
|
||||
"cd " + mCachedFile.getParent(),
|
||||
"BOOTMODE=true sh update-binary dummy 1 " + mCachedFile +
|
||||
" && echo 'Success!' || echo 'Failed!'"
|
||||
);
|
||||
if (TextUtils.equals(mList.get(mList.size() - 1), "Success!"))
|
||||
@@ -97,23 +93,23 @@ public class FlashZip extends ParallelTask<Void, String, Integer> {
|
||||
// -1 = error, manual install; 0 = invalid zip; 1 = success
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return;
|
||||
MagiskManager mm = getMagiskManager();
|
||||
if (mm == null) return;
|
||||
getShell().su_raw(
|
||||
"rm -rf " + mCachedFile.getParent(),
|
||||
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
|
||||
);
|
||||
switch (result) {
|
||||
case -1:
|
||||
mList.add(magiskManager.getString(R.string.install_error));
|
||||
mList.add(mm.getString(R.string.install_error));
|
||||
Utils.showUriSnack(getActivity(), mUri);
|
||||
break;
|
||||
case 0:
|
||||
mList.add(magiskManager.getString(R.string.invalid_zip));
|
||||
mList.add(mm.getString(R.string.invalid_zip));
|
||||
break;
|
||||
case 1:
|
||||
// Success
|
||||
new LoadModules(magiskManager).exec();
|
||||
new LoadModules(mm).exec();
|
||||
break;
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
|
||||
115
app/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java
Normal file
115
app/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java
Normal file
@@ -0,0 +1,115 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Environment;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.jarsigner.JarMap;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.container.Policy;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
public class HideManager extends ParallelTask<Void, Void, Boolean> {
|
||||
|
||||
private static final String UNHIDE_APK = "unhide.apk";
|
||||
private static final String ANDROID_MANIFEST = "AndroidManifest.xml";
|
||||
private static final byte[] UNHIDE_PKG_NAME = "com.topjohnwu.unhide\0".getBytes();
|
||||
|
||||
public HideManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
getMagiskManager().toast(R.string.hide_manager_toast, Toast.LENGTH_SHORT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
MagiskManager mm = getMagiskManager();
|
||||
if (mm == null)
|
||||
return false;
|
||||
|
||||
// Generate a new unhide app with random package name
|
||||
File unhideAPK = new File(Environment.getExternalStorageDirectory() + "/MagiskManager", "unhide.apk");
|
||||
unhideAPK.getParentFile().mkdirs();
|
||||
String pkg;
|
||||
|
||||
try {
|
||||
JarMap asset = new JarMap(mm.getAssets().open(UNHIDE_APK));
|
||||
JarEntry je = new JarEntry(ANDROID_MANIFEST);
|
||||
byte xml[] = asset.getRawData(je);
|
||||
int offset = -1;
|
||||
|
||||
// Linear search pattern offset
|
||||
for (int i = 0; i < xml.length - UNHIDE_PKG_NAME.length; ++i) {
|
||||
boolean match = true;
|
||||
for (int j = 0; j < UNHIDE_PKG_NAME.length; ++j) {
|
||||
if (xml[i + j] != UNHIDE_PKG_NAME[j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
offset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (offset < 0)
|
||||
return false;
|
||||
|
||||
// Patch binary XML with new package name
|
||||
pkg = Utils.genPackageName("com.", UNHIDE_PKG_NAME.length - 1);
|
||||
System.arraycopy(pkg.getBytes(), 0, xml, offset, pkg.length());
|
||||
asset.getOutputStream(je).write(xml);
|
||||
|
||||
// Sign the APK
|
||||
ZipUtils.signZip(mm, asset, unhideAPK, false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Install the application
|
||||
List<String> ret = getShell().su("pm install " + unhideAPK + ">/dev/null && echo true || echo false");
|
||||
unhideAPK.delete();
|
||||
if (!Utils.isValidShellResponse(ret) || !Boolean.parseBoolean(ret.get(0)))
|
||||
return false;
|
||||
|
||||
try {
|
||||
// Allow the application to gain root by default
|
||||
PackageManager pm = mm.getPackageManager();
|
||||
int uid = pm.getApplicationInfo(pkg, 0).uid;
|
||||
Policy policy = new Policy(uid, pm);
|
||||
policy.policy = Policy.ALLOW;
|
||||
policy.notification = false;
|
||||
policy.logging = false;
|
||||
mm.suDB.addPolicy(policy);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hide myself!
|
||||
getShell().su_raw("pm hide " + mm.getPackageName());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean b) {
|
||||
MagiskManager mm = getMagiskManager();
|
||||
if (mm == null)
|
||||
return;
|
||||
if (!b) {
|
||||
mm.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
|
||||
}
|
||||
super.onPostExecute(b);
|
||||
}
|
||||
}
|
||||
230
app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java
Normal file
230
app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java
Normal file
@@ -0,0 +1,230 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.container.AdaptiveList;
|
||||
import com.topjohnwu.magisk.container.TarEntry;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||
|
||||
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;
|
||||
private static final int DIRECT_MODE = 1;
|
||||
|
||||
private Uri mBootImg, mZip;
|
||||
private AdaptiveList<String> mList;
|
||||
private String mBootLocation;
|
||||
private boolean mKeepEnc, mKeepVerity;
|
||||
private int mode;
|
||||
|
||||
private InstallMagisk(Activity context, AdaptiveList<String> list, Uri zip, boolean enc, boolean verity) {
|
||||
super(context);
|
||||
mList = list;
|
||||
mZip = zip;
|
||||
mKeepEnc = enc;
|
||||
mKeepVerity = verity;
|
||||
}
|
||||
|
||||
public InstallMagisk(Activity context, AdaptiveList<String> list, Uri zip, boolean enc, boolean verity, Uri boot) {
|
||||
this(context, list, zip, enc, verity);
|
||||
mBootImg = boot;
|
||||
mode = PATCH_MODE;
|
||||
}
|
||||
|
||||
public InstallMagisk(Activity context, AdaptiveList<String> list, Uri zip, boolean enc, boolean verity, String boot) {
|
||||
this(context, list, zip, enc, verity);
|
||||
mBootLocation = boot;
|
||||
mode = DIRECT_MODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
// UI updates must run in the UI thread
|
||||
mList.setCallback(this::publishProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Void... values) {
|
||||
mList.updateView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
MagiskManager mm = getMagiskManager();
|
||||
if (mm == null) return false;
|
||||
|
||||
File install = new File(Utils.getEncContext(mm).getFilesDir().getParent(), "install");
|
||||
getShell().sh_raw("rm -rf " + install);
|
||||
|
||||
List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS);
|
||||
String arch;
|
||||
if (abis.contains("x86_64")) arch = "x64";
|
||||
else if (abis.contains("arm64-v8a")) arch = "arm64";
|
||||
else if (abis.contains("x86")) arch = "x86";
|
||||
else arch = "arm";
|
||||
mList.add("- Device platform: " + arch);
|
||||
|
||||
try {
|
||||
// Unzip files
|
||||
mList.add("- Extracting files");
|
||||
try (InputStream in = mm.getContentResolver().openInputStream(mZip)) {
|
||||
if (in == null) throw new FileNotFoundException();
|
||||
BufferedInputStream buf = new BufferedInputStream(in);
|
||||
buf.mark(Integer.MAX_VALUE);
|
||||
ZipUtils.unzip(buf, install, arch + "/", true);
|
||||
buf.reset();
|
||||
ZipUtils.unzip(buf, install, "common/", true);
|
||||
buf.reset();
|
||||
ZipUtils.unzip(buf, install, "chromeos/", false);
|
||||
buf.reset();
|
||||
ZipUtils.unzip(buf, install, "META-INF/com/google/android/update-binary", true);
|
||||
} catch (FileNotFoundException e) {
|
||||
mList.add("! Invalid Uri");
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
mList.add("! Cannot unzip zip");
|
||||
throw e;
|
||||
}
|
||||
|
||||
File boot;
|
||||
switch (mode) {
|
||||
case PATCH_MODE:
|
||||
boot = new File(install, "boot.img");
|
||||
// Copy boot image to local
|
||||
try (
|
||||
InputStream in = mm.getContentResolver().openInputStream(mBootImg);
|
||||
OutputStream out = new FileOutputStream(boot)
|
||||
) {
|
||||
InputStream source;
|
||||
if (in == null) throw new FileNotFoundException();
|
||||
|
||||
if (Utils.getNameFromUri(mm, mBootImg).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;
|
||||
}
|
||||
source = tar;
|
||||
} else {
|
||||
// Direct copy raw image
|
||||
source = new BufferedInputStream(in);
|
||||
}
|
||||
byte buffer[] = new byte[1024];
|
||||
int length;
|
||||
while ((length = source.read(buffer)) > 0)
|
||||
out.write(buffer, 0, length);
|
||||
} catch (FileNotFoundException e) {
|
||||
mList.add("! Invalid Uri");
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
mList.add("! Copy failed");
|
||||
throw e;
|
||||
}
|
||||
break;
|
||||
case DIRECT_MODE:
|
||||
boot = new File(mBootLocation);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
mList.add("- Use boot image: " + boot);
|
||||
|
||||
Shell shell;
|
||||
if (mode == PATCH_MODE && Shell.rootAccess()) {
|
||||
// Force non-root shell
|
||||
shell = Shell.getShell("sh");
|
||||
} else {
|
||||
shell = getShell();
|
||||
}
|
||||
|
||||
// Patch boot image
|
||||
shell.sh(mList,
|
||||
"cd " + install,
|
||||
"KEEPFORCEENCRYPT=" + mKeepEnc + " KEEPVERITY=" + mKeepVerity + " sh " +
|
||||
"update-binary indep boot_patch.sh " + boot +
|
||||
" && echo 'Success!' || echo 'Failed!'"
|
||||
);
|
||||
|
||||
if (!TextUtils.equals(mList.get(mList.size() - 1), "Success!"))
|
||||
return false;
|
||||
|
||||
File patched_boot = new File(install, "new-boot.img");
|
||||
mList.add("");
|
||||
switch (mode) {
|
||||
case PATCH_MODE:
|
||||
File dest = new File(Environment.getExternalStorageDirectory() + "/MagiskManager/patched_boot" + mm.bootFormat);
|
||||
dest.getParentFile().mkdirs();
|
||||
switch (mm.bootFormat) {
|
||||
case ".img":
|
||||
getShell().sh_raw("cp -f " + patched_boot + " " + dest);
|
||||
break;
|
||||
case ".img.tar":
|
||||
TarOutputStream tar = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
|
||||
tar.putNextEntry(new TarEntry(patched_boot, "boot.img"));
|
||||
byte buffer[] = new byte[4096];
|
||||
BufferedInputStream in = new BufferedInputStream(new FileInputStream(patched_boot));
|
||||
int len;
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
tar.write(buffer, 0, len);
|
||||
}
|
||||
tar.flush();
|
||||
tar.close();
|
||||
in.close();
|
||||
break;
|
||||
}
|
||||
mList.add("*********************************");
|
||||
mList.add(" Patched Boot Image is placed in ");
|
||||
mList.add(" " + dest + " ");
|
||||
mList.add("*********************************");
|
||||
break;
|
||||
case DIRECT_MODE:
|
||||
// Direct flash boot image
|
||||
getShell().su(mList, "flash_boot_image " + patched_boot + " " + mBootLocation);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finals
|
||||
getShell().sh_raw(
|
||||
"cd " + install,
|
||||
"mv bin/busybox busybox",
|
||||
"rm -rf bin *.img update-binary",
|
||||
"cd /");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,9 @@ package com.topjohnwu.magisk.asyncs;
|
||||
import android.content.Context;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.module.BaseModule;
|
||||
import com.topjohnwu.magisk.module.Module;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.container.Module;
|
||||
import com.topjohnwu.magisk.container.ValueSortedMap;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ValueSortedMap;
|
||||
|
||||
public class LoadModules extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
@@ -17,29 +15,23 @@ public class LoadModules extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return null;
|
||||
Logger.dev("LoadModules: Loading modules");
|
||||
|
||||
magiskManager.moduleMap = new ValueSortedMap<>();
|
||||
MagiskManager mm = getMagiskManager();
|
||||
if (mm == null) return null;
|
||||
mm.moduleMap = new ValueSortedMap<>();
|
||||
|
||||
for (String path : Utils.getModList(getShell(), MagiskManager.MAGISK_PATH)) {
|
||||
Logger.dev("LoadModules: Adding modules from " + path);
|
||||
try {
|
||||
Module module = new Module(getShell(), path);
|
||||
magiskManager.moduleMap.put(module.getId(), module);
|
||||
} catch (BaseModule.CacheModException ignored) {}
|
||||
Module module = new Module(getShell(), path);
|
||||
mm.moduleMap.put(module.getId(), module);
|
||||
}
|
||||
|
||||
Logger.dev("LoadModules: Data load done");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
MagiskManager magiskManager = getMagiskManager();
|
||||
if (magiskManager == null) return;
|
||||
magiskManager.moduleLoadDone.publish();
|
||||
MagiskManager mm = getMagiskManager();
|
||||
if (mm == null) return;
|
||||
mm.moduleLoadDone.publish();
|
||||
super.onPostExecute(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ public class MarkDownWindow extends ParallelTask<Void, Void, String> {
|
||||
Parser parser = Parser.builder().build();
|
||||
HtmlRenderer renderer = HtmlRenderer.builder().build();
|
||||
Node doc = parser.parse(md);
|
||||
return renderer.render(doc);
|
||||
return String.format(
|
||||
"<link rel='stylesheet' type='text/css' href='file:///android_asset/%s.css'/> %s",
|
||||
getMagiskManager().isDarkTheme ? "dark" : "light", renderer.render(doc));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -36,11 +38,6 @@ public class MarkDownWindow extends ParallelTask<Void, Void, String> {
|
||||
alert.setTitle(mTitle);
|
||||
|
||||
WebView wv = new WebView(getActivity());
|
||||
|
||||
html = String.format(
|
||||
"<link rel='stylesheet' type='text/css' href='file:///android_asset/%s.css'/> %s",
|
||||
getMagiskManager().isDarkTheme ? "dark" : "light", html);
|
||||
|
||||
wv.loadDataWithBaseURL("fake://", html, "text/html", "UTF-8", null);
|
||||
|
||||
alert.setView(wv);
|
||||
|
||||
@@ -42,8 +42,9 @@ public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<P
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void exec(Params... params) {
|
||||
public ParallelTask<Params, Progress, Result> exec(Params... params) {
|
||||
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,42 +1,102 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.FlashActivity;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.container.InputStreamWrapper;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||
|
||||
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.net.HttpURLConnection;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
||||
public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
|
||||
|
||||
private Uri mUri;
|
||||
private ProgressDialog progressDialog;
|
||||
private boolean mInstall;
|
||||
private String mLink;
|
||||
private File mFile;
|
||||
private int progress = 0, total = -1;
|
||||
|
||||
public ProcessRepoZip(Activity context, Uri uri, boolean install) {
|
||||
private static final int UPDATE_DL_PROG = 0;
|
||||
private static final int SHOW_PROCESSING = 1;
|
||||
|
||||
public ProcessRepoZip(Activity context, String link, String filename, boolean install) {
|
||||
super(context);
|
||||
mUri = uri;
|
||||
mLink = link;
|
||||
mFile = new File(Environment.getExternalStorageDirectory() + "/MagiskManager", filename);
|
||||
mInstall = install;
|
||||
}
|
||||
|
||||
private void removeTopFolder(InputStream in, File output) throws IOException {
|
||||
JarInputStream source = new JarInputStream(in);
|
||||
JarOutputStream dest = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(output)));
|
||||
JarEntry entry;
|
||||
String path;
|
||||
int size;
|
||||
byte buffer[] = new byte[4096];
|
||||
while ((entry = source.getNextJarEntry()) != null) {
|
||||
// Remove the top directory from the path
|
||||
path = entry.getName().substring(entry.getName().indexOf("/") + 1);
|
||||
// If it's the top folder, ignore it
|
||||
if (path.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// Don't include placeholder
|
||||
if (path.equals("system/placeholder")) {
|
||||
continue;
|
||||
}
|
||||
dest.putNextEntry(new JarEntry(path));
|
||||
while((size = source.read(buffer)) != -1) {
|
||||
dest.write(buffer, 0, size);
|
||||
}
|
||||
}
|
||||
source.close();
|
||||
dest.close();
|
||||
in.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
progressDialog = ProgressDialog.show(activity,
|
||||
activity.getString(R.string.zip_process_title),
|
||||
activity.getString(R.string.zip_process_msg));
|
||||
mFile.getParentFile().mkdirs();
|
||||
progressDialog = ProgressDialog.show(activity, activity.getString(R.string.zip_download_title), activity.getString(R.string.zip_download_msg, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Object... values) {
|
||||
int mode = (int) values[0];
|
||||
switch (mode) {
|
||||
case UPDATE_DL_PROG:
|
||||
int add = (int) values[1];
|
||||
progress += add;
|
||||
progressDialog.setMessage(getActivity().getString(R.string.zip_download_msg, 100 * progress / total));
|
||||
break;
|
||||
case SHOW_PROCESSING:
|
||||
progressDialog.setTitle(R.string.zip_process_title);
|
||||
progressDialog.setMessage(getActivity().getString(R.string.zip_process_msg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,15 +105,30 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
||||
if (activity == null) return null;
|
||||
try {
|
||||
|
||||
// Create temp file
|
||||
File temp1 = new File(activity.getCacheDir(), "1.zip");
|
||||
File temp2 = new File(activity.getCacheDir(), "2.zip");
|
||||
activity.getCacheDir().mkdirs();
|
||||
temp1.createNewFile();
|
||||
temp2.createNewFile();
|
||||
// Request zip from Internet
|
||||
HttpURLConnection conn;
|
||||
do {
|
||||
conn = WebService.request(mLink, null);
|
||||
if (conn == null) return null;
|
||||
total = conn.getContentLength();
|
||||
if (total < 0)
|
||||
conn.disconnect();
|
||||
else
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
// First remove top folder in Github source zip, Uri -> temp1
|
||||
ZipUtils.removeTopFolder(activity.getContentResolver().openInputStream(mUri), temp1);
|
||||
InputStream in = new BufferedInputStream(new ProgressInputStream(conn.getInputStream()));
|
||||
|
||||
// Temp files
|
||||
File temp1 = new File(activity.getCacheDir(), "1.zip");
|
||||
File temp2 = new File(temp1.getParentFile(), "2.zip");
|
||||
temp1.getParentFile().mkdir();
|
||||
|
||||
// First remove top folder in Github source zip, Web -> temp1
|
||||
removeTopFolder(in, temp1);
|
||||
|
||||
conn.disconnect();
|
||||
publishProgress(SHOW_PROCESSING);
|
||||
|
||||
// Then sign the zip for the first time, temp1 -> temp2
|
||||
ZipUtils.signZip(activity, temp1, temp2, false);
|
||||
@@ -64,24 +139,22 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
||||
// Finally, sign the whole zip file again, temp1 -> temp2
|
||||
ZipUtils.signZip(activity, temp1, temp2, true);
|
||||
|
||||
// Write it back to the downloaded zip, temp2 -> Uri
|
||||
try (OutputStream out = activity.getContentResolver().openOutputStream(mUri);
|
||||
FileInputStream in = new FileInputStream(temp2)
|
||||
// Write it to the target zip, temp2 -> file
|
||||
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(mFile));
|
||||
InputStream source = new BufferedInputStream(new FileInputStream(temp2))
|
||||
) {
|
||||
byte[] buffer = new byte[4096];
|
||||
int length;
|
||||
if (out == null) throw new FileNotFoundException();
|
||||
while ((length = in.read(buffer)) > 0)
|
||||
while ((length = source.read(buffer)) > 0)
|
||||
out.write(buffer, 0, length);
|
||||
}
|
||||
|
||||
// Delete the temp file
|
||||
// Delete temp files
|
||||
temp1.delete();
|
||||
temp2.delete();
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Logger.error("ProcessRepoZip: Error!");
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
@@ -92,14 +165,50 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
||||
Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
progressDialog.dismiss();
|
||||
Uri uri = Uri.fromFile(mFile);
|
||||
if (result) {
|
||||
if (Shell.rootAccess() && mInstall) {
|
||||
activity.startActivity(new Intent(activity, FlashActivity.class).setData(mUri));
|
||||
Intent intent = new Intent(getActivity(), FlashActivity.class);
|
||||
intent.setData(uri).putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_ZIP);
|
||||
activity.startActivity(intent);
|
||||
} else {
|
||||
Utils.showUriSnack(activity, mUri);
|
||||
Utils.showUriSnack(activity, uri);
|
||||
}
|
||||
} else {
|
||||
Utils.getMagiskManager(activity).toast(R.string.process_error, Toast.LENGTH_LONG);
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParallelTask<Void, Object, Boolean> exec(Void... voids) {
|
||||
Utils.runWithPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
() -> super.exec(voids));
|
||||
return this;
|
||||
}
|
||||
|
||||
private class ProgressInputStream extends InputStreamWrapper {
|
||||
|
||||
ProgressInputStream(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int read() throws IOException {
|
||||
publishProgress(UPDATE_DL_PROG, 1);
|
||||
return super.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int read(@NonNull byte[] b, int off, int len) throws IOException {
|
||||
int read = super.read(b, off, len);
|
||||
publishProgress(UPDATE_DL_PROG, read);
|
||||
return read;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RestoreStockBoot extends ParallelTask<Void, Void, Boolean> {
|
||||
|
||||
private String mBoot;
|
||||
|
||||
public RestoreStockBoot(Context context, String boot) {
|
||||
super(context);
|
||||
mBoot = boot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
List<String> ret = getShell().su("cat /init.magisk.rc | grep STOCKSHA1");
|
||||
if (!Utils.isValidShellResponse(ret))
|
||||
return false;
|
||||
String stock_boot = "/data/stock_boot_" + ret.get(0).substring(ret.get(0).indexOf('=') + 1) + ".img.gz";
|
||||
if (!Utils.itemExist(getShell(), stock_boot))
|
||||
return false;
|
||||
getShell().su_raw("flash_boot_image " + stock_boot + " " + mBoot);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
if (result) {
|
||||
getMagiskManager().toast(R.string.restore_done, Toast.LENGTH_SHORT);
|
||||
} else {
|
||||
getMagiskManager().toast(R.string.restore_fail, Toast.LENGTH_LONG);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user